ModuleConcatenationPlugin

以前は、webpackでバンドルする際のトレードオフの1つは、バンドル内の各モジュールが個々の関数クロージャでラップされることでした。 これらのラッパー関数は、ブラウザでJavaScriptを実行する速度を低下させました。 これと比較して、Closure CompilerやRollupJSなどのツールは、すべてのモジュールのスコープを1つのクロージャに「ホイスト」または連結し、ブラウザでコードの実行時間を短縮できます。

このプラグインは、webpackで同じ連結動作を有効にします。 デフォルトでは、このプラグインは本番環境のmodeで既に有効になっており、それ以外の場合は無効になっています。 本番環境のmode最適化をオーバーライドする必要がある場合は、optimization.concatenateModulesオプションfalseに設定します。 他のモードで連結動作を有効にするには、ModuleConcatenationPluginを手動で追加するか、optimization.concatenateModulesオプションを使用します

new webpack.optimize.ModuleConcatenationPlugin();

この連結動作は、「スコープホイスト」と呼ばれます。

スコープホイストは、ECMAScriptモジュール構文によって specifically に実現される機能です。 このため、webpackは、使用しているモジュールの種類やその他の条件に基づいて、通常のバンドルにフォールバックする場合があります。

最適化のベイルアウト

この記事で説明されているように、webpack は部分的なスコープホイストを実現しようとします。モジュールを単一のスコープにマージしますが、常にそうできるわけではありません。webpack がモジュールをマージできない場合、代替手段は Prevent と Root の 2 つです。Prevent は、モジュールが独自のスコープに存在する必要があることを意味します。Root は、新しいモジュールグループが作成されることを意味します。次の条件によって結果が決まります。

条件結果
非 ES6 モジュールPrevent
import 以外の方法でインポートされているRoot
他のチャンクからインポートされているRoot
複数の他のモジュールグループによってインポートされているRoot
import() を使用してインポートされているRoot
ProvidePlugin の影響を受ける、または module を使用しているPrevent
HMR が受け入れられているRoot
eval() を使用しているPrevent
複数のチャンクに存在するPrevent
export * from "cjs-module"Prevent

モジュールグループ化アルゴリズム

以下の疑似 JavaScript は、アルゴリズムを説明しています。

modules.forEach((module) => {
  const group = new ModuleGroup({
    root: module,
  });
  module.dependencies.forEach((dependency) => {
    tryToAdd(group, dependency);
  });
  if (group.modules.length > 1) {
    orderedModules = topologicalSort(group.modules);
    concatenatedModule = new ConcatenatedModule(orderedModules);
    chunk.add(concatenatedModule);
    orderedModules.forEach((groupModule) => {
      chunk.remove(groupModule);
    });
  }
});

function tryToAdd(group, module) {
  if (group.has(module)) {
    return true;
  }
  if (!hasPreconditions(module)) {
    return false;
  }
  const nextGroup = group;
  const result = module.dependents.reduce((check, dependent) => {
    return check && tryToAdd(nextGroup, dependent);
  }, true);
  if (!result) {
    return false;
  }
  module.dependencies.forEach((dependency) => {
    tryToAdd(group, dependency);
  });
  group.merge(nextGroup);
  return true;
}

最適化ベイルアウトのデバッグ

webpack CLI を使用する場合、--stats-optimization-bailout フラグはベイルアウトの理由を表示します。 webpack 設定を使用する場合は、stats オブジェクトに以下を追加します。

module.exports = {
  //...
  stats: {
    // Display bailout reasons
    optimizationBailout: true,
  },
};

3 貢献者

skipjackTheLarkInnbyzyk