知海

ModuleConcatenationPlugin 插件

webpackjsorg-main插件参考

ModuleConcatenationPlugin 插件

过去,webpack 在打包时的一个权衡是:bundle 中的每个模块都会被包装在独立的函数闭包中。这些包装函数会导致你的 JavaScript 在浏览器中执行得更慢。相比之下,Closure Compiler 和 RollupJS 等工具会将所有模块的作用域“提升”或拼接到一个闭包中,从而使代码在浏览器中的执行速度更快。

该插件将在 webpack 中启用相同的拼接行为。默认情况下,该插件已在 production mode 中启用,在其他模式中禁用。如果需要覆盖 production mode 的优化设置,请将 optimization.concatenateModules option 设置为 false。要在其他模式中启用拼接行为,你可以手动添加 ModuleConcatenationPlugin 或使用 optimization.concatenateModules 选项:

js 复制代码
new webpack.optimize.ModuleConcatenationPlugin();

这种拼接行为被称为“作用域提升”(scope hoisting)。

作用域提升是 ECMAScript Module 语法带来的特性。因此,webpack 可能会根据你使用的模块类型以及 其他条件 回退到普通打包方式。

警告: 请记住,此插件仅适用于由 webpack 直接处理的 ES6 模块。使用转译器时,你需要禁用模块处理(例如 Babel 中的 modules 选项)。

优化回退

如文中所述,webpack 会尝试实现部分作用域提升。它可以将模块合并到单个作用域中,但并非在所有情况下都能做到。如果 webpack 无法合并某个模块,有两种备选结果:Prevent 和 Root。Prevent 意味着该模块必须留在自己的作用域中;Root 意味着将创建一个新的模块组。以下条件决定了最终结果:

条件 结果
非 ES6 模块 Prevent
由非 import 导入 Root
从其他 chunk 导入 Root
被多个其他模块组导入 Root
使用 import() 导入 Root
ProvidePlugin 影响或使用 module Prevent
HMR 已接受 Root
使用 eval() Prevent
存在于多个 chunk 中 Prevent
export * from "cjs-module" Prevent

模块分组算法

以下伪 JavaScript 代码解释了该算法:

js 复制代码
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) => check && tryToAdd(nextGroup, dependent),
    true,
  );
  if (!result) {
    return false;
  }
  for (const dependency of module.dependencies) {
    tryToAdd(group, dependency);
  }
  group.merge(nextGroup);
  return true;
}

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

调试优化回退

使用 webpack CLI 时,--stats-optimization-bailout 标志会显示回退原因。使用 webpack 配置时,请将以下内容添加到 stats 对象中:

js 复制代码
export default {
  // ...
  stats: {
    // Display bailout reasons
    optimizationBailout: true,
  },
};

帮助我们改进文档

发现翻译问题或内容错误?请告诉我们。