webpackの動作を見てみよう
Vueは置いといて、webpackが何をするものなのか、実際に生成されたbundleファイルを覗いてみよう。
先にまとめ
webpackは、雑に言うと依存するJSライブラリをbundleという1枚のJSファイルにまとめてくれる
細かく言うと一枚とは限らなくて、共通部分を別ファイルに分けたり、現場の要請に応じた高度な機能があるけどこのページでは略!
JSファイル内の「require」という所を見て必要なJSファイルを持ってくる
requireに変わる仕様である「import」という構文は、自動的にrequireに変換される
requireについてちょっとだけ説明
requireはもともとJavaScriptの仕様になかったもので、Node.js独自の構文
相対パスまたは、node_modulesにあるJSファイルを使うことが出来た
npmjs.comは便利ライブラリを集めたレジストリで、誰でもモジュールを公開することができる。
Node.jsはnpmというツールを使って上記レジストリからnode_modules下に構成ファイルをインストールする仕組みがあった
…のだけど、ブラウザでもこれを使いたいという層が出てきてしまった
その結果生まれたのがbrowserify、webpackを始めとする「モジュールバンドラー」
requireはNode独自仕様であり、ブラウザだけではrequireを実行することができないので、browserifyやwebpackは一つのJSファイルにライブラリをまとめてしまうという、Cでいうリンカに相当する解決方法を選択した
その後に、requireを置き換える仕様として、JavaScriptの仕様自体にimportという構文が導入された。
そのために、webpackは現状requireとimport両方を処理することが出来る。一部ブラウザはwebpackを必要とせずにimportを処理することが出来る。Node.jsは未だにimportに対応出来ていない…
そのために現在の複雑な状況が生まれている。これどうするの…
一応、Node.jsもブラウザもimport(ESModules)に対応する方向に向かっている。拡張子をjsからmjsに変更する必要があり、まだ過渡期は続きそう
以下検証
検証環境
webpack4
作るもの
名前を表示するだけのスクリプト
山田太郎さんを右詰めしてconsole.logで表示する。
ファイル構成
https://gyazo.com/9744629b693bff4cf1f7beb3eb40f2cc
それぞれの中身
code: index.js
const leftPad = require("left-pad");
const name = leftPad("Yamada Taro", 20);
console.log("Hello!" + name);
code: package.json
{
"name": "study-webpack4",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"devDependencies": {
"webpack": "^4.1.1",
"webpack-cli": "^2.0.12"
},
"scripts": {
"dev": "webpack --mode development",
"build": "webpack --mode production"
},
"dependencies": {
"left-pad": "^1.2.0"
}
}
code: index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Webpack検証</title>
</head>
<body>
<script src="./main.js"></script>
</body>
</html>
ビルド実行
webpackのdevelopmentビルドを実施。
その結果、dist/main.jsが生成された。
https://gyazo.com/df18e7bd29cb042d55ed29fc8e9de95e
出来たのは下記のようなファイル。
https://gyazo.com/0e27accaa2aa5cf4d87ab706af73b726
つまり、requireに対してwebpackがやってくれることというのは…
基本的に1枚のbundleにベタベタとJSを張り合わせるだけ
__webpack_require__という関数を作って、そこからインストールされたモジュールを呼べるようにする
requireは__webpack_require__に変換される
やっていることはそれだけ。
requireとimportは何が違うのか?
code: index.js
// const leftPad = require("left-pad");
import * as leftPad from "left-pad";
const name = leftPad("Yamada Taro", 20);
console.log("Hello!" + name);
requireと等価なimportに書き換えて、再度webpackを実行。
import版のbundle
code: main-index-import.js
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var left_pad__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! left-pad */ \"./node_modules/left-pad/index.js\");
/* harmony import */ var left_pad__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(left_pad__WEBPACK_IMPORTED_MODULE_0__);
// const leftPad = require(\"left-pad\");
const name = left_pad__WEBPACK_IMPORTED_MODULE_0__(\"Yamada Taro\", 20);
console.log(\"Hello!\" + name);
//# sourceURL=webpack:///./src/index.js?
require版のbundle
code: main-index-require.js
const leftPad = __webpack_require__(/*! left-pad */ \"./node_modules/left-pad/index.js\");\r
const name = leftPad(\"Yamada Taro\", 20);
console.log(\"Hello!\" + name);
//# sourceURL=webpack:///./src/index.js?
requireに比べて出力されるものが5行くらい多い。
やっていることは、
require版と同様に、__webpack_require__を呼んでいる
__webpack_require__.rは、exportsに__esModuleというフラグを立てるものみたい
__webpack_require__.nは、esModuleでないものに対してgetDefault, getModuleExportsというpolyfillらしきものを付けているっぽい
つまり、既存のcommonJSに対して、default export絡みのpolyfillをしてくれてるんじゃないかなと。想像だけど。
参考サイト