本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。
理解Webpack4用分块策略(common chunk strategy) webpack4 splitchunks
- 最初,chunks(以及内部导入的模块)是通过内部 webpack 图谱中的父子关系关联的。CommonsChunkPlugin 曾被用来避免他们之间的重复依赖,但是不可能再做进一步的优化。从 webpack v4 开始,移除了 CommonsChunkPlugin,取而代之的是 optimization.splitChunks。
module.exports = {
mode: 'production',
entry: path.resolve(__dirname, '../src/entry1.js'),
output: {
path: path.resolve(__dirname, '../dist'),
filename: '[name].[chunkhash:8].js',
chunkFilename: '[name].[chunkhash:8].chunk.js',
},
module: {
rules: [
{
test: /.js$/,
exclude: /node_modules/,
use: 'babel-loader'
}
]
},
optimization: {
splitChunks: {
chunks: 'all', // 拆分范围: 三种模式 async (不拆分入口文件)| initial (只拆分入口文件) | all (拆分所有文件) 默认async
minSize: 30000, // 生成 chunk 的最小体积(以 bytes 为单位)。
minChunks: 1, // 包被引用 >=1 次, 就会进行chunk模块进行拆分, (默认的minChunks=1)
maxAsyncRequests: 5, // 异步模块(非入口模块)内部的并行最大请求数的 ()
maxInitialRequests: 3, //入口模块并行加载最大请求数 (入口文件拆分不超过3个文件, 拆分出太多模块导致请求数量过多而得不偿失)
automaticNameDelimiter: '~', // 生成的名称的分隔符
// name: true, // 当chunk没有名字时,通过splitChunks分出的模块的名字用id替代,当然你也可以通过name属性自定义
// name: '拆分出来的', //可以对拆分出来的文件合并然后重命名
cacheGroups: {
vendors: {
// minChunks: 1, // 第三方包被引用 >=1 次, 就会进行chunk模块进行拆分, (默认的minChunks=1)
test: /[\\/]node_modules[\\/]/, // 只筛选从node_modules文件夹下引入的模块
priority: -10, // 权重
},
default: {
minChunks: 2, // 本地包被引用 >=2 次, 就会进行chunk模块进行拆分,, 权重小于vendors (对比priority)
priority: -20, // 权重, 先vendors引用包, 再找本地包, 因为default 权重小于vendors
reuseExistingChunk: true,
}
}
},
},
plugins: [
new CleanWebpackPlugin(['dist'], {
root: process.cwd()
}),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, '../public/index.html')
}),
new BundleAnalyzerPlugin(),
]
}
启动默认 async 模式, 单文件入口
npm run default
启动默认 async 模式, 多文件入口
npm run entry2
测试maxInitialRequests
npm run maxInitialRequests
测试maxAsyncRequests
npm run maxAsyncRequests
输出结果
当父chunk和子chunk同时引入相同的module时?
- 当父chunk和子chunk同时引入相同的module时,并不会将其分割出来而是删除掉子chunk里面共同的module,保留父chunk的module,这个是因为 optimization.removeAvaliableModules 默认是true
通用vendors如何提取到一个vendors(指定的)?
- todo
默认cacheGroups, 第三方包被引用 >= 1次则会被拆分, 本地包被引用本超过 >=2 则会被拆分,
cacheGroups: {
vendors: {
// minChunks: 1, // 第三方包被引用 >=1 次, 就会进行chunk模块进行拆分, (默认的minChunks=1)
test: /[\\/]node_modules[\\/]/, // 只筛选从node_modules文件夹下引入的模块
priority: -10
},
default: {
minChunks: 2, // 本地包被引用 >=2 次, 就会进行chunk模块进行拆分,, 权重小于vendors (对比priority)
priority: -20, // 权重, 先vendors引用包, 再找本地包, 因为default 权重小于vendors
reuseExistingChunk: true //先vendors引用包, 再找本地包
}
}
1.打包文件重命名?
- 当chunk没有名字时,通过splitChunks分出的模块的名字用id替代,当然你也可以通过name属性自定义
在为不同的拆分 chunk 分配相同的名称时,所有 vendor 模块都放在一个共享的 chunk 中,尽管不建议这样做,因为这可能会导致下载更多代码。
splitChunks.usedExports
optimization: {
splitChunks: {
...
- name: true, // 当chunk没有名字时,通过splitChunks分出的模块的名字用id替代,当然你也可以通过name属性自定义 ~~
+ name: '拆分出来的', //可以对拆分出来的文件合并然后重命名
cacheGroups: {
vendors: {
...
},
default: {
...
}
}
},
},
2.通用vendors如何提取到一个入口vendors~xxx.chunk.js中?
-
maxAsyncRequests: 5, // 异步模块(非入口模块)内部的并行最大请求数的 () maxInitialRequests: 3, //入口模块并行加载最大请求数 (入口文件拆分不超过3个文件, 拆分出太多模块导致请求数量过多而得不偿失)
splitChunks: {
// chunks可以为三种值:async,initial,all;决定代码满足条件后是否进行拆分。
// initial表示只考虑非import()异步导入代码进行拆分,async表示只拆分异步代码块,而all表示同异步都加入拆分范畴。
chunks: 'async',
// 满足尺寸才发生拆分
// 例如导入10kb的依赖包小于30kb便不会拆分代码块
minSize: 30000,
// 当bundle达到maxSize,必须进行拆分
// 例如jquery与lodash合并成了140kb,maxSize定位80kb,便会拆分两个依赖
maxSize: 0,
// 最少被引用的chunk个数
// 例如一个入口块和一个异步块都引用了lodash,minChunks大于2时就不会添加新chunk来装lodash
minChunks: 1,
// 异步代码块最多可拆分次数
// 假设某个import()模块有2MB,maxSize设定为500kb,如果此属性为1,模块最多就只能拆分一个bundle出去。
maxAsyncRequests: 5,
// 这属性和maxAsyncRequests道理一致,不过是作用与initial模块的
maxInitialRequests: 3,
// bundle自动命名使用的连接字符
automaticNameDelimiter: '~',
// bundle自动命名时名称长度限制
automaticNameMaxLength: 30,
// 可为bool、string类型,true是会使用默认命名,否则使用序号命名;string指定文件名称
name: true,
// 自定义拆分组
cacheGroups: {
// 每个属性就是一个分组
vendors: {
// 导入路径的正则匹配,这为所有node_modules引用的模块代码
test: /[\\/]node_modules[\\/]/,
// 优先级默认为0,如果两个组引用了同一个模块,优先级高的组可以获得此模块
priority: -10
},
default: {
minChunks: 2,
priority: -20,
// 是否复用其他chunk内已拥有的模块
// 默认为false,关闭表示拆分出复用部分的模块,给双方引用
reuseExistingChunk: true
}
}
}
一些提示
- 默认配置在大多数场景下都有不错的表现
- webpack的externals更适合把第三方库移到CDN上
- test匹配规则也可以是一个方法,分组更灵活
更多相关的资料
webpack 4: 代码拆分、代码块关系图及优化插件splitChunks 为 splitChunks 添加 maxSize 选择 不清楚 splitChunks.maxAsyncRequest 有什么用 reuseExistingChunk 的使用例子
欢迎在评论区讨论,掘金官方将在掘力星计划活动结束后,在评论区抽送100份掘金周边,抽奖详情见活动文章」