webpack (version 2) の公式ドキュメントではバンドルファイルのブラウザキャッシュ対策として、ファイル名にハッシュ値を埋め込む方法が提案されている。
こうするとアプリのコードを変更する度に、バンドルファイル名に埋め込まれたハッシュ値も更新され、ブラウザキャッシュ対策ができる、という寸法だが…。
当然ファイル名が変わるわけだから、<sript>
タグも更新しなくてはならない。それを解決するには、HTML ファイルも動的に扱わなければならない。chunk-manifest-webpack-plugin と html-webpack-plugin を導入し、HTML のテンプレーティングを行い…、となると今使っている Pug はどうなる…、となってさらにさらに掘り下げないといけなくなり、はっきり言ってソリューションとして無理がある。
閑話休題。
webpack をヘビーに使っていると、サードパーティーフレームワークやライブラリのコード(npm install
でインストールしたようなモジュール)を出力ファイル(バンドルファイル)から切り離したくなる。
バンドルファイルにライブラリが直接含まれるが故に、以下のような事象に直面したことがある開発者は多いのではないだろうか。
- 複数人で開発していて各自のライブラリのバージョンが微妙に異なり、Git経由でやり取りされるバンドルファイルに環境の差分までが含まれてしまう
- 使っているライブラリが増えて、コンパイルがとても遅くなる
解決策として、フレームワークやライブラリはまとめて別のバンドルファイルにする、もしくは単独で配布されたものを <script>
タグを読み込む、という解決方法を取ることもできる。
これを可能にするのが externals
オプションで、ここで宣言された名前については、依存関係がグローバルスコープから参照されるようになる。
externals: {
jquery: 'jQuery'
}
と webpack.config.js
に設定しておくと、 import jQuery from 'jquery';
というコードはグローバルスコープの jQuery
を参照するようになり、バンドルファイルに jQuery のコードは含まれないようになる。
もちろんこの場合には jQuery は新たに別の <script>
タグで読み込む必要ある。
よりスマートな解決策としての CommonsChunkPlugin
CommonsChunkPlugin を使うと、複数のバンドルファイルから共通の依存モジュールを切り出してくれる。 サードパーティーライブラリをアプリのコードと分割する、という使い方ももちろんできる。 公式で示されている設定は以下のようなものだ。
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: "vendor",
minChunks: function(module){
// node_modules のディレクトリ下に含まれるものだけに絞る
return module.context && module.context.indexOf("node_modules") !== -1;
}
}),
new webpack.optimize.CommonsChunkPlugin({
name: "manifest", // 名前は "manifest" でないとダメ
minChunks: Infinity // entryがいくつあろうと生成。省略可
}),
]
サードパーティーコードを別にしたいだけなら vendor
だけでも目的は果たせるが、manifest
を入れると、webpack バンドル共通部分(ソースには webpackBootstrap
とコメントが書かれている部分)が manifest.js
として別ファイルに書き出される。こうするとビルドするたびに vendor
のハッシュ値が変更されることを防げるとのこと。
でもこれ、先述のハッシュ値をファイル名に含めるキャッシュ対策をやっていないと、意味はなさそう。なぜならハッシュ値はバンドルファイルのコード内には現れないから。
manifest
を定義した場合、以下のように manifest.js
も読み込まないとコードは動かないので注意。
<script src="/js/manifest.js"></script>
<script src="/js/vendor.js"></script>
<script src="/js/bundle.js"></script>