有人可以解释Webpack的CommonsChunkPlugin


82

我得到了一个基本要点,即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其中包含的完整代码entry1.js,是的要求,jquery并且不包含运行时
    • entry2.bundle.js其中包含的完整代码entry2.js,是的要求,jquery并且不包含运行时
    • vendors.bundle.js其中包含的完整代码some_jquery_plugin,是的要求,jquery并且不包含运行时
    • commons.bundle.js其中包含来自的完整代码jquery并包含运行时

    这样,我们最终得到了一些较小的包,并且包中包含运行时commons。不错,但不理想。

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

    • entry1.bundle.js其中包含的完整代码entry1.js,是的要求,jquery并且不包含运行时
    • entry2.bundle.js其中包含的完整代码entry2.js,是的要求,jquery并且不包含运行时
    • vendors.bundle.js其中包含来自jquery和的完整代码,some_jquery_plugin并包含运行时。

    同样,通过这种方式,我们最终得到了一些较小的包,但是运行时现在包含在vendors包中。由于运行时已包含在vendors捆绑包中,因此它比以前的情况要差一些。

  • 情况3:如果通过,{ names : ['vendors', 'manifest'] }我将得到以下捆绑文件:

    • entry1.bundle.js其中包含的完整代码entry1.js,是的要求,jquery并且不包含运行时
    • entry2.bundle.js其中包含的完整代码entry2.js,是的要求,jquery并且不包含运行时
    • vendors.bundle.js包含来自jquery和的完整代码,some_jquery_plugin不包含运行时
    • manifest.bundle.js 其中包含其他所有捆绑包的要求并包含运行时

    这样,我们最终得到了一些较小的包,并且包中包含运行时manifest。这是理想的情况。

我不了解/不确定我是否了解

  • 案例2中,为什么我们最终得到了vendors既包含通用代码(jquery)又包含vendors条目(some_jquery_plugin)剩余内容的捆绑包?据我了解,CommonsChunkPlugin这里所做的是它收集了公共代码(jquery),并且由于我们强制将其输出到vendors捆绑软件中,因此它有点将公共代码“合并”到vendors捆绑软件中(现在仅包含来自some_jquery_plugin)。请确认或解释。

  • 案例3中,我不明白当我们传递{ names : ['vendors', 'manifest'] }给插件时发生了什么。为什么/如何vendors保持捆绑包完好无损,同时包含jquerysome_jquery_plugin,何时jquery显然是常见的依赖关系,以及为什么生成的manifest.bundle.js文件以创建方式创建(需要所有其他捆绑包并包含运行时)?


对于情况1,我认为您应该指定minChunks属性。
Marko

10
我从您的问题中学到了很多,非常感谢!
拉斐尔·伊恩

1
非常感谢你提出这项并在此插件❤清理我的困惑这一切的时候
格伦·穆罕默德·

也许有人知道,这些示例在Webpack 4中将是什么样子?
StalkAlex

Answers:


105

这就是CommonsChunkPlugin工作原理。

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

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

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

情况1:

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

情况2:

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

情况3:

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

希望能帮助到你。


我想问/澄清的几件事,也请在您的答案中添加以下几点:1)您是否可以对情况1进行相同的逐步说明,只是答案是1000%完成?2)运行插件与{ names : ['vendors', 'manifest'] }就像运行它两次,一次与{ name : 'vendors' }一次用{ name : 'manifest' },对不对?3)当我们说“插件处理一个公共块”时,是指它创建了要在bundle.js文件中吐出的内容,在内存中,对吗?4)直到它“处理了所有公共块”为止,它根本没有将任何输出写入文件,而是全部存储在内存中
Dimitris Karagiannis

2
如果您想回答,我还有一个问题。比方说,在我的例子从上面,entry1.jsentry2.js他们之间,另一种常见的文件,比其他的jquery文件,让我们把它ownLib.js。在情况2和情况3中,结果ownLib.js是否vendors.bundle.js正确?您如何做到这一点,以便将除供应商文件以外的通用文件分隔为各自的块,而不是vendors块?抱歉打扰您,但我仍在学习如何使用webpack
Dimitris Karagiannis

7
是的,没错:ownLib.js将被放置在第一个公共块中。如果你想收集公共依赖于另一个chunck,你必须通过这样的:{ names : ['common', 'vendors', 'manifest'] }
Laurent Etiemble

6
好问题,好答案,好讨论。好像我终于明白了。
oluckyman '16

3
我花了最后一天阅读CommonsChunkPlugin文档,这是我第一次阅读执行后的已处理块“未标记为条目”。这基本上可以解释我遇到的所有问题-如果我可以投票不只一次,我会的。
Coderer
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.