ModuleConcatenationPlugin
在过去,webpack在捆绑时的一个权衡是,你的捆绑包中的每个模块都将被包装在单独的函数闭包中。这些包装器函数降低了JavaScript在浏览器中的执行速度。相比之下,像Closure Compiler和RollupJS这样的工具可以将所有模块的作用域“提升”或连接到一个闭包中,并允许你的代码在浏览器中有更快的执行时间。
这个插件将在webpack中启用相同的连接行为。默认情况下,该插件已在生产模式下启用,否则禁用。如果需要覆盖生产模式优化,请设置 optimization.concatenateModules
选择为 false
。要在其他模式下启用连接行为,您可以手动添加 ModuleConcatenationPlugin
或使用优化。optimization.concatenateModules
选择:
new webpack.optimize.ModuleConcatenationPlugin();
这种连接行为称为“作用域提升”。作用域提升是ECMAScript模块语法实现的一个特性。因此,webpack可能会根据您使用的模块类型和其他条件退回到正常的捆绑。
Optimization Bailouts
正如文章所解释的,webpack试图实现部分作用域提升。它会将模块合并到单个作用域中,但不能在所有情况下都这样做。如果webpack不能合并一个模块,两个替代选项是Prevent和Root。Prevent意味着模块必须在它自己的作用域中。Root表示将创建一个新的模块组。以下条件决定了结果:
Condition | Outcome |
---|---|
Non ES6 Module | Prevent |
Imported By Non Import | Root |
Imported From Other Chunk | Root |
Imported By Multiple Other Module Groups | Root |
Imported With import()
|
Root |
Affected By ProvidePlugin Or Using module
|
Prevent |
HMR Accepted | Root |
Using eval()
|
Prevent |
In Multiple Chunks | Prevent |
export * from "cjs-module"
|
Prevent |
Module Grouping Algorithm
下面的伪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;
}
Debugging Optimization Bailouts
当使用webpack CLI时,——stats-optimization-bailout
标志将显示救助原因。当使用webpack配置时,在 stats
对象中添加以下内容:
module.exports = {
//...
stats: {
// Display bailout reasons
optimizationBailout: true,
},
};