ModuleConcatenationPlugin

過去,webpack 在打包時的一個取捨是,套件中的每個模組都會被包覆在個別函數封閉中。這些封裝函數會讓 JavaScript 在瀏覽器中執行得更慢。相比之下,Closure Compiler 和 RollupJS 等工具會將所有模組的範圍「提升」或串接成一個封閉,並讓您的程式碼在瀏覽器中執行得更快。

此外掛將在 webpack 中啟用相同的串接行為。預設情況下,此外掛已在 生產 mode 中啟用,否則會停用。如果您需要覆寫生產 mode 最佳化,請將 optimization.concatenateModules 選項 設定為 false。若要在其他模式中啟用串接行為,您可以手動新增 ModuleConcatenationPlugin 或使用 optimization.concatenateModules 選項

new webpack.optimize.ModuleConcatenationPlugin();

此串接行為稱為「範圍提升」。

範圍提升特別是 ECMAScript 模組語法所實現的功能。因此,webpack 可能會根據您使用的模組類型和 其他條件 回退到一般打包。

最佳化中止

正如文章所述,webpack 嘗試達成部分範圍提升。它會將模組合併到單一範圍中,但並非在所有情況下都能做到。如果 webpack 無法合併模組,則有兩個替代方案:防止和根目錄。防止表示模組必須在自己的範圍中。根目錄表示將建立新的模組群組。下列條件會決定結果

條件結果
非 ES6 模組防止
由非匯入匯入根目錄
從其他區塊匯入根目錄
由多個其他模組群組匯入根目錄
使用 import() 匯入根目錄
ProvidePlugin 影響或使用 module防止
HMR 已接受根目錄
使用 eval()防止
在多個區塊中防止
從「cjs-module」匯出 *防止

模組群組演算法

下列偽 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