Works by

Ren's blog

@rennnosuke_rk 技術ブログです

【webpack】webpackを使用してWebアプリケーションをバンドルする

f:id:rennnosukesann:20181225231948p:plain:w600

webpackとは

webPackとはモジュールバンドラと呼ばれるツールです。アプリーケーションが依存するjsモジュールを一つのjsファイルにまとめ上げ、依存関係の解決やトランスパイルを自動実行してくれます。内部的にモジュール同士の依存関係を表すグラフを自動で構築し、それに基づいて依存関係の解決をしてくれるので、設定ファイルなどなしに使用することができます(詳細な設定を記述したファイルを使用することもできます)。

・・・とはいったものの、「モジュールのバンドル」がいまいちピンと来なかったので、こちらチュートリアルを実践してみました。

以下、チュートリアルのメモになります。

webpackのインストール

まず、webpack対象となる node プロジェクトを作成します。

$ mkdir hello-webpack
$ cd hello-webpack
$ npm init -y

npm でwebpackと、webpackのCLIツールをインストールします。

$ npm install webpack webpack-cli --save-dev

webpackを試しに使用する

実験環境準備

webpackを使用する前に、テスト用のモジュールを作ってみます。

最初のディレクトリ構成は以下の通り。

$ ls
node_modules        package.json
package-lock.json

プロジェクトルートに以下のような index.html を作成します。HTMLを見ると、 index.html<script> タグ中でCDNによって茶刈 lodash.js スクリプトをロードしていることがわかります。

<!doctype html>
<html>
  <head>
    <title>Hello, webpack !!1!</title>
    <script src="https://unpkg.com/lodash@4.16.6"></script>
  </head>
  <body>
    <script src="./src/index.js"></script>
  </body>
</html>

次に内部ロジック記述用スクリプトである src/index.js を用意します。このスクリプトでは、先程 index.html でロードしていた lodash モジュールを使用しようとしているとします。が、 lodash に対する依存関係が暗黙的で、 _ を未定義のグローバル変数として参照してしまっています。

function component() {
  let element = document.createElement('div');
  element.innerHTML = _.join(['Hello', 'webpack'], ' ');
  return element;
}

document.body.appendChild(component());

上記の index.js のような、参照できているようで参照できていない暗黙の依存関係は様々なバグを生んでしまいます。 このようなバグをなくすため、lodash をnpmでのパッケージインストール & import に変更してしまいましょう!

npm での lodash のインストール

先程用意した index.html を、新たに生成した /dist ディレクトリ配下に配置します。

dist
└── index.html

次に、 lodash をnpm経由でインストール。

$ npm install --save lodash

src/index.js を修正します。明示的に lodash を参照できるよう、下記一文をファイル先頭に追加します。

import _ from 'lodash';

dist/index.html を編集します。 <script> タグによる lodash のロードをやめ、 参照先スクリプトmain.js としました。これは後ほど使用するwebpackのバンドル後ファイルへの参照です。

webpackによるモジュールバンドル

上記の import 文によって、webpackが依存関係のグラフを自動作成可能になりました。

それでは、実際にwebpackでモジュールバンドルを行います。

npx コマンドを使用し、 webpack を実行します。

npx についてはこちらを参照。

rennnosukesann.hatenablog.com

$ npx webpack 
Hash: 53680323beef520a74cd
Version: webpack 4.28.2
Time: 445ms
Built at: 2018/12/25 23:10:03
  Asset      Size  Chunks             Chunk Names
main.js  1.03 KiB       0  [emitted]  main
Entrypoint main = main.js
[0] ./src/index.js 189 bytes {0} [built]

WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/

webpackが成功し、 dist/main.js が生成されました!

!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=0)}([function(e,t){document.body.appendChild(function(){let e=document.createElement("div");return e.innerHTML=_.join(["Hello","webpack"]," "),e}())}])

どうやら「モジュールのバンドル」 とは

といった操作のようです。


webpackを使ってみての感想ですが、「アプリの最適化」を行うのには素晴らしいツールだなと思いました。 アプリの複雑な依存関係を解決し一つのファイルにアプリのスクリプトをまとめることで、ビルド・デプロイするアプリを軽量化・高速化できるので、アプリの総仕上げとして良いのではないでしょうか。 (多くのフロントエンドCLIでもデフォルトで採用されているみたいですね)

参考文献

webpack - Getting Started