(Webpack) 如何对动态模块依赖进行代码分块

17

我刚意识到,如果你使用require.ensure()动态加载模块,webpack不会将依赖项分析和分块在一起。从某种程度上讲,这是有道理的,因为webpack无法知道是否传输了这些模块,但我们能否强制webpack完成这项工作呢?

示例:

app.js

require.ensure([ 'module1.js' ], ( require ) => {
    // at some point
    require( 'module1.js' );
}, 'Module1');

require.ensure([ 'module2.js' ], ( require ) => {
    // at some point
    require( 'module2.js' );
}, 'Module2');

module1.js

let io = require( 'socket.io-client' );

module2.js

let io = require( 'socket.io-client' );
编译的结果是,这两个模块都将整个socket-io库“链接”到它们的块中。我的初始预期是,CommonsChunkPlugin会捕获这些需要,并将该大型库放入一个公共块中。
new webpack.optimize.CommonsChunkPlugin( 'common' ),

然而,它并不起作用。当然我可以手动“解决”这个依赖关系,但我希望webpack能以某种方式解决这个问题?


将CommonsChunkPlugin选项中的minChunks设置为2会改变情况吗? - Everettss
很遗憾,不行。 - jAndy
2个回答

5
答案隐藏在CommonsChunkPlugin的配置中。
new webpack.optimize.CommonsChunkPlugin({
  name: 'main', // Important to use 'main' or not specify, since 'main' is default
  children: true, // Look for common dependencies in all children,
  minChunks: 2, // How many times a dependency must come up before being extracted
});

children: true 是这个配置的主要部分。 根据文档:

如果设置为true,则选择所有公共块的子级。


异步常见块编辑

如果您想在块中异步下载常用代码,则应通过添加async: true来更改上述配置。

new webpack.optimize.CommonsChunkPlugin({
  name: 'main',
  children: true, 
  minChunks: 2, 
  async: true, // modification
});

从有关async的文档中:

如果设置为 true,将创建一个新的异步公共 chunk 作为 options.name 的子级和 options.chunks 的同级。它与 options.chunks 并行加载。通过提供所需的字符串而不是 true 来更改输出文件的名称也是可能的。

现在根据您的示例创建了包含仅socket.io-client的其他 chunk。这接近于webpack文档中的原始示例。


啊,我真的希望这个解决方案能起作用,但事实证明,在这种情况下并没有帮助。如果我打开 children: true,唯一发生的是我的 "common" 块现在与 main-bundle 连接在一起。但它不会影响动态加载的块。两者仍然将共享的库/依赖链接到它们的块中。 - jAndy
async: true 能行吗? - Everettss
1
确实,这就是诀窍。与 children: true 一起使用可以创建预期的行为(将 socket-io 库链接到主块中)。我原以为那里的 name 属性 只是一些随机 ID 或设置输出文件名... 暂时先谢了,这可能也会让赏金更高。 - jAndy
我也感到惊讶。您可以省略名称配置选项,因为默认值为“main”。如果您想指定公共代码的文件名,应该使用“filename:'shared.js'”。 - Everettss
async: true 会创建一个独立的代码块,其中包含 jsonpLoader 所需的公共内容,只有使用此公共代码的代码块才需要引用它。 - Everettss
显示剩余6条评论

0
到目前为止,我找到了一个可能的解决方案。如果您使用webpackrequire.include()方法来仅包含(而不是评估)"共享库",在这里是socket.io-client,也在父模块中,这里是app.jsCommonChunkPlugin现在将能够正确地解决问题。
require.include( 'socket.io-client' ); // import io from 'socket.io-client'; also works
require.ensure([ 'module1.js' ], ( require ) => {
    // at some point
    require( 'module1.js' );
}, 'Module1');

require.ensure([ 'module2.js' ], ( require ) => {
    // at some point
    require( 'module2.js' );
}, 'Module2');

然而,这对我来说似乎不太正确,因为这是手动解决依赖关系,实际上并不是我想要使用类似于Webpack的东西所必须做的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接