JavaScript
module
最適化
es6
webpack

Webpackでもモジュール統合がしたい

少し前にRollupを使ってみたところ、「モジュールごとに名前空間の関数を切るのではなく、各変数や関数の名前を変更してすべてを同じ名前空間に入れる」というシンプルさに感心したのですが、ある程度までは同様のことがWebpackでできることに気づきました。

プラグインの用意

このような処理は、WebpackにModuleConcatenationPluginを入れることで実現可能ですが、Webpack 3には標準添付されています。ということで、使い始めるにはwebpack.config.jspluginsnew webpack.optimize.ModuleConcatenationPlugin()を書き足すだけです(なお、後述の理由により、Babelにはmodules: falseなどES6 Moduleの変換を止める設定が必要となります)。

また、従来は「ソースコードの1ファイル」=「Webpack後の1関数」=「1モジュール」で曖昧さはなかったのですが、1つの関数に複数のモジュールが入るようになったので、以降では「Webpack後の1関数」を「グループ」と呼ぶことにします。

グループが切れるパターン

従来のように、ソースの1ファイルが1グループとなる場合(Prevent)

まず、ModuleConcatenationPluginES6 Moduleが前提となっています。そのため、CommonJSの外部モジュールや、exportsrequireで書かれたCommonJSモジュールは、従来通り1ファイル1グループで切り出されます。

また、モジュール内でevalをやっているような場合や、ProvidesPluginで定義のない変数を読み取るような場合も、スコープを広げるのは危険なので1ファイル1グループとなります。

ある程度のモジュールをまとめたグループを形成する場合(Root)

Webpackには、モジュール分割を前提とした機能(動的import、HMR、チャンク分割など)がありますが、これらの機能を使う場合はもちろん同じ名前空間に混ぜ込むわけには行きませんので、きちんとグループの分割が行われます。

また、import以外のrequireやWebpack独自の方法で参照されるモジュールも、モジュール参照が関数実行である以上、そのまま展開することはできず、参照されたモジュールを返すようなグループを形成します。

さらに、何らかの理由でグループA、Bが分かれることが決定していた場合に、AとBの両方から同じモジュールをimportしていた場合、このモジュールCなども1つのグループを形成します。

実際にやってみる

動作が気になったのでいろいろやってみて、結果をjkr2255/webpack-module-concat-testにおいてあります。実際にどんなコードが吐き出されるかも、確認しておくといいかもしれません。