有人可以解释Webpack的CommonsChunkPlugin

我得到了一个基本要点,即CommonsChunkPlugin查看所有入口点,检查它们之间是否存在通用的软件包/依赖项,并将它们分成自己的捆绑包。

因此,假设我具有以下配置:

...
enrty : {
    entry1 : 'entry1.js', //which has 'jquery' as a dependency
    entry2 : 'entry2.js', //which has 'jquery as a dependency
    vendors : [
        'jquery',
        'some_jquery_plugin' //which has 'jquery' as a dependency
    ]
},
output: {
    path: PATHS.build,
    filename: '[name].bundle.js'
}
...

如果我捆绑而不使用 CommonsChunkPlugin

我将获得3个新的捆绑包文件:

  • entry1.bundle.js包含来自entry1.js的完整代码jquery并包含其自己的运行时
  • entry2.bundle.js包含来自entry2.js的完整代码jquery并包含其自己的运行时
  • vendors.bundle.js包含来自jquery的完整代码some_jquery_plugin并包含其自己的运行时

这显然很不好,因为我可能会jquery在页面中加载3次,因此我们不希望这样做。

如果我捆绑使用 CommonsChunkPlugin

根据传递给CommonsChunkPlugin以下任何参数的参数,将会发生:

  • 情况1:如果通过,{ name : 'commons' }我将得到以下捆绑文件:

    • entry1.bundle.js which contains the complete code from entry1.js, a requirement for jquery and does not contain the runtime
    • entry2.bundle.js which contains the complete code from entry2.js, a requirement for jquery and does not contain the runtime
    • vendors.bundle.js which contains the complete code from some_jquery_plugin, a requirement for jquery and does not contain the runtime
    • commons.bundle.js which contains the complete code from jquery and contains the runtime

    This way we end up with some smaller bundles overall and the runtime is contained in the commons bundle. Pretty ok but not ideal.

  • CASE 2 : If I pass { name : 'vendors' } I will end up with the following bundle files:

    • entry1.bundle.js which contains the complete code from entry1.js, a requirement for jquery and does not contain the runtime
    • entry2.bundle.js which contains the complete code from entry2.js, a requirement for jquery and does not contain the runtime
    • vendors.bundle.js which contains the complete code from jquery and some_jquery_plugin and contains the runtime.

    This way, again, we end up with some smaller bundles overall but the runtime is now contained in the vendors bundle. It's a little worse than the previous case, since the runtime is now in the vendors bundle.

  • CASE 3 : If I pass { names : ['vendors', 'manifest'] } I will end up with the following bundle files:

    • entry1.bundle.js which contains the complete code from entry1.js, a requirement for jquery and does not contain the runtime
    • entry2.bundle.js which contains the complete code from entry2.js, a requirement for jquery and does not contain the runtime
    • vendors.bundle.js which contains the complete code from jquery and some_jquery_plugin and does not contain the runtime
    • manifest.bundle.js which contains requirements for every other bundle and contains the runtime

    This way we end up with some smaller bundles overall and the runtime is contained in the manifest bundle. This is the ideal case.

What I do not understand/I am not sure I understand

  • In CASE 2 why did we end up with the vendors bundle containing both the common code (jquery) and whatever remained from the vendors entry (some_jquery_plugin)? From my understanding, what the CommonsChunkPlugin did here was that it gathered the common code (jquery), and since we forced it to output it to the vendors bundle, it kind of "merged" the common code into the vendors bundle (which now only contained the code from some_jquery_plugin). Please confirm or explain.

  • In CASE 3 I do not understand what happened when we passed { names : ['vendors', 'manifest'] } to the plugin. Why/how was the vendors bundle kept intact, containing both jquery and some_jquery_plugin, when jquery is clearly a common dependency, and why was the generated manifest.bundle.js file created the way it was created (requiring all other bundles and containing the runtime) ?

番长樱梅2020/03/23 14:35:07

这就是CommonsChunkPlugin工作原理。

一个公共块“接收”由几个入口块共享的模块。Webpack存储库中可以找到复杂配置的一个很好的例子

CommonsChunkPlugin在Webpack的优化阶段运行,这意味着它在内存被密封并写入磁盘之前就在内存中运行。

当定义了几个通用块时,将按顺序对其进行处理。在您的情况3中,就像两次运行插件一样。但是请注意,它们CommonsChunkPlugin可能具有更复杂的配置(minSize,minChunks等),这会影响模块的移动方式。

情况1:

  1. 有3 entry块(entry1entry2vendors)。
  2. 该配置将commons设置为公共块。
  3. 该插件处理commons公共块(由于该块不存在,因此将创建它):
    1. 它收集其他块中多次使用的模块entry1entry2vendors使用,jquery以便从这些块中删除该模块并将其添加到该commons块中。
    2. commons块被标记为entry,而该块entry1entry2并且vendors块被作为未标记entry
  4. 最后,由于commons块是entry块,因此它包含运行时和jquery模块。

情况2:

  1. 有3 entry块(entry1entry2vendors)。
  2. 该配置将vendors设置为公共块。
  3. 该插件处理vendors公共块:
    1. 它收集其他块中多次使用的模块entry1entry2使用,jquery以便从这些块中删除该模块(请注意,vendors由于该vendors块已包含该模块,因此未将其添加到该中)。
    2. vendors块被标记为entry,而该块entry1entry2块旗标被作为entry
  4. 最后,由于vendors块是entry块,因此它包含运行时和jquery/ jquery_plugin模块。

情况3:

  1. 有3 entry块(entry1entry2vendors)。
  2. 该配置将vendors块和manifest块设置为公共块。
  3. 该插件将创建manifest块,因为它不存在。
  4. 该插件处理vendors公共块:
    1. It collects the modules that are used more than once in the other chunks: entry1 and entry2 use jquery so the module is removed from these chunks (note that it is not added to the vendors chunk because the vendors chunk already contains it).
    2. The vendors chunk is flagged as an entry chunk while the entry1 and entry2 chunks are unflagged as entry.
  5. The plugin processes the manifest common chunk (since the chunk does not exist, it is created):
    1. It collects the modules that are used more than once in the other chunks: as there are no modules used more than once, no module is moved.
    2. The manifest chunk is flagged as entry chunk while the entry1, entry2 and vendors are unflagged as entry.
  6. Finally, since the manifest chunk is an entry chunk it contains the runtime.

Hope it helps.