谁能解释一下 Webpack 的 CommonsChunkPlugin

Posted

技术标签:

【中文标题】谁能解释一下 Webpack 的 CommonsChunkPlugin【英文标题】:Can someone explain Webpack's CommonsChunkPlugin 【发布时间】:2017-01-25 16:01:40 【问题描述】:

我知道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.jsjquery 的完整代码,并包含自己的运行时 entry2.bundle.js 包含来自 entry2.jsjquery 的完整代码,并包含自己的运行时 vendors.bundle.js 包含来自 jquerysome_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 包含来自 jquerysome_jquery_plugin 的完整代码并包含运行时。

这样,我们最终会得到一些较小的包,但运行时现在包含在vendors 包中。这比前一种情况要差一些,因为运行时现在位于 vendors 包中。

案例3:如果我通过 names : ['vendors', 'manifest'] ,我将得到以下捆绑文件:

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

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

我不明白/我不确定我是否明白

CASE 2 中,为什么我们最终会得到包含公共代码 (jquery) 和 vendors 条目 (some_jquery_plugin) 中剩余的任何内容的 vendors 包)?据我了解,CommonsChunkPlugin 在这里所做的是它收集了公共代码 (jquery),并且由于我们强制它输出到 vendors 包,它有点将公共代码“合并”到vendors 捆绑包(现在只包含来自some_jquery_plugin 的代码)。 请确认或解释。

CASE 3 中,当我们将 names : ['vendors', 'manifest'] 传递给插件时,我不明白发生了什么。为什么/如何保持vendors 捆绑包保持原样,同时包含jquerysome_jquery_plugin,而jquery 显然是一个常见的依赖项,以及为什么生成的manifest.bundle.js 文件按照它的创建方式创建(需要所有其他包并包含运行时)?

【问题讨论】:

对于案例 1,我认为您应该指定 minChunks 属性。 从您的问题中我学到了很多,非常感谢! 非常感谢您提出这个问题并解决我一直以来对这个插件的困惑❤ 也许有人知道,这些示例在 Webpack 4 中会是什么样子? 【参考方案1】:

这就是CommonsChunkPlugin 的工作原理。

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

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

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

案例 1:

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

案例 2:

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

案例 3:

    有 3 个 entry 块(entry1entry2vendors)。 配置将vendors块和manifest块设置为通用块。 插件创建manifest 块,因为它不存在。 插件处理vendors公共块:
      它收集在其他块中多次使用的模块:entry1entry2 使用 jquery,因此模块从这些块中删除(注意它没有添加到 vendors 块中因为vendors 块已经包含它)。 vendors 块被标记为 entry 块,而 entry1entry2 块未被标记为 entry
    插件处理manifest公共块(由于块不存在,所以创建):
      它收集在其他块中多次使用的模块:因为没有模块被多次使用,所以没有模块被移动。 manifest 块标记为 entry 块,而 entry1entry2vendors 未标记为 entry
    最后,由于 manifest 块是 entry 块,它包含运行时。

希望对你有帮助。

【讨论】:

我想问/澄清几件事,也请在您的答案中添加这些要点:1)您能否对案例 1 进行相同的逐步解释,以便答案 1000% 完成? 2) 使用 names : ['vendors', 'manifest'] 运行插件就像运行两次一样,一次使用 name : 'vendors' ,一次使用 name : 'manifest' ,对吗? 3)当我们说“插件处理一个公共块”时,我们的意思是它会在内存中创建它将在bundle.js 文件中吐出的内容,对吗? 4)在“处理所有常见块”之前,它根本没有将任何输出写入文件,它都在内存中 我还有一个问题,如果你想回答的话。假设在我上面的示例中,entry1.jsentry2.js 在它们之间有另一个公共文件,而不是jquery 文件,我们称之为ownLib.js。在案例 2 和案例 3 中,ownLib.js 最终会出现在 vendors.bundle.js 中,对吗?除了vendors 块之外,您将如何将供应商文件以外的常见文件分成它们自己的块?抱歉打扰了,我还在学习如何使用 webpack 是的,这是正确的:ownLib.js 将被放置在第一个公共块中。如果你想在另一个块中收集公共依赖项,你必须传递这样的东西: names : ['common', 'vendors', 'manifest'] . 好问题,好答案,好讨论。看来我终于明白了。 我花了最后 阅读 CommonsChunkPlugin 文档,这是我读到的第一个地方,在执行后,已处理的块“未标记为条目”。这基本上解释了我遇到的所有问题——如果我可以多次投票,我会的。

以上是关于谁能解释一下 Webpack 的 CommonsChunkPlugin的主要内容,如果未能解决你的问题,请参考以下文章

如何在vue-cli webpack中全局引入jquery

谁能解释一下预定义的 GenericModel 类的这种语法? [复制]

解释一下:webpack、gulp 和 react、redux

谁能解释一下这个 NSPredicate 语法

GWT RPC 中同步和异步接口的作用是啥。谁能详细解释一下?

谁能解释一下 vuetify 主题代码