81

I get the general gist that the CommonsChunkPlugin looks at all the entry points, checks to see if there are common packages/dependencies between them and separates them into their own bundle.

So, let's assume I have the following configuration:

...
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'
}
...

If I bundle without using CommonsChunkPlugin

I will end up with 3 new bundle files:

  • entry1.bundle.js which contains the complete code from entry1.js and jquery and contains its own runtime
  • entry2.bundle.js which contains the complete code from entry2.js and jquery and contains its own runtime
  • vendors.bundle.js which contains the complete code from jquery and some_jquery_plugin and contains its own runtime

This is obviously bad because I will potentially load jquery 3 times in the page, so we don't want that.

If I bundle using CommonsChunkPlugin

Depending on what arguments I pass to CommonsChunkPlugin any of the following will happen:

  • CASE 1 : If I pass { name : 'commons' } 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 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) ?

4

1 回答 1

106

这就是CommonsChunkPlugin工作原理。

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

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

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

情况1:

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

案例二:

  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. 它收集在其他块中多次使用的模块:entry1entry2使用jquery以便从这些块中删除模块(请注意,它没有添加到vendors块中,因为vendors块已经包含它)。
    2. vendors块被标记为一个entry块,而entry1entry2块未被标记为entry.
  5. 插件处理manifest公共块(由于块不存在,所以创建它):
    1. 它收集在其他块中多次使用的模块:由于没有多次使用的模块,因此不会移动任何模块。
    2. manifest块被标记为entry块,而entry1,entry2vendors未被标记为entry.
  6. 最后,由于manifest块是一个entry块,它包含运行时。

希望能帮助到你。

于 2016-09-20T17:58:44.480 回答