看了官方文档之后发现 splitChunks.chunks
可以接收initial、async、all
,很困惑这三种分割代码模式的区别,现在我们引入例子来探索一下:
下面有两个脚本文件 a.js、b.js
,两个文件有一些相同的引入,包括动态加载,我们使用Webpack Bundle Analyzer Plugin 插件来分析模块是如何进行拆分的。
1、chunks:’async’ 优化动态加载模块
const path = require('path')
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
module.exports = {
entry: {
a: './code_split_mode/a.js',
b: './code_split_mode/b.js'
},
output: {path: path.resolve(__dirname, 'build'), // 打包文件的输出目录
filename: '[name].bundle.js', // 代码打包后的文件名
publicPath: __dirname + '/build/', // 引用的路径或者 CDN 地址
chunkFilename: '[name].js' // 代码拆分后的文件名
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {loader: 'babel-loader'}
}
]
},
// 拆分代码配置项
optimization: {
splitChunks: {
cacheGroups: {
node_vendors: {test: /[\\/]node_modules[\\/]/,
chunks: 'async',
priority: 1
}
}
}
},
plugins: [new CleanWebpackPlugin(), // 会删除上次构建的文件,然后重新构建
new BundleAnalyzerPlugin()]
}
执行效果:
!
async
模式下的输出
- 在
a,b
中均同步引入的jquery
被打包进了各自的bundle
中没有拆分出来共用,因为这种模式下只会优化动态加载的代码。 -
react
打了两份- 一份在
a
自己的bundle
中,因为它同步引入了react
,而我们只优化动态加载的代码,所以这里的react
不会被优化拆分出去。 - 一份在单独的文件中,它是从
b
里面拆出来的,因为b
中动态加载了react
。
- 一份在
-
lodash
因为在a,b
中都是动态加载,形成了单独的chunk
被a, b
共用。
2、chunks:’initial’ 优化同步加载模块
在 webpack.config.js
配置中将 chunks: 'async'
改成 'initial'
。initial
模式下的输出
initial
即原始的拆分,原则就是有共用的情况即发生拆分。动态引入的代码不受影响,它是无论如何都会走拆分逻辑的(毕竟你要动态引入嘛,不拆分成单独的文件怎么动态引入?!)。而对于同步引入的代码,如果有多处都在使用,则拆分出来共用。
-
jquery
在这种模式下发生了变化。形成了单独的chunk
供a,b
共用。 -
react
没有变,因为它在a,b
中引用的方式不同,所以不会被当成同一个模块拆分出来共用,而是走各自的打包逻辑。在a
中同步引用,被打入了a
的bundle
。在b
中动态引入所以拆分成了单独的文件供b
使用。 -
lodash
没变,形成单独一份两者共用。
3、chunks:’all’ 优化同步和动态加载模块
从上面 initial
模式下我们似乎看出了问题,即 在 a
中同步引入在 b
中动态引入的 react
,它其实可以被抽成文件供两者共用的,只是因为引入方式不同而没有这样做。
所以 all
这种模式下,就会智能地进行判断以解决这个问题。此时不关心引入的模块是动态方式还是同步方式,只要能正确判断这段代码确实可以安全地进行拆分共用,那就干吧。
需要注意的是这里需要设置 minSize
以使 react
能够正确被拆分,因为它小于 30k,在同步方式下,默认不会被拆分出来(联想文章开头提到的那些条件)。
cacheGroups: {
vendor: {
chunks: "all",
test: /[\\/]node_modules[\\/]/,
minSize: 0,
}
}
4、结论
看起来似乎 all
是最好的模式,因为它最大限度地生成了复用的代码,Webpack
默认就走这个模式打包不就得了。
参考链接:
https://github.com/wayou/wayou.github.io/issues/40
https://medium.com/dailyjs/webpack-4-splitchunks-plugin-d9fbbe091fd0