過去,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,
},
};