本来第一篇博客是打算写 webpack 的,看了几天之后,发现配置项实在是太多了,文档也不是很全,看的我有点儿怀疑我自己。就把目标从通读 webpack 变成了把公司现有的基于 webpack3 的项目升级到 webpack4。升级之前先看了通过 vue-cli 生成的 webpack 配置文件。由于 webpack4 移除了 CommonsChunkPlugin这个插件,在这上面费时间较多。
(关于顺序问题我还没有弄清楚,现在的博客应该没有几个人看,我就先发布了让自己开心一下吧!)
简介
在一个单页面项目中,有我们自己编写的业务代码,使用的第三方库的代码,还有 webpack 构建后的 manifest 文件,从缓存的角度来说,这三种代码需要打包到不同的文件中。如果部分代码是动态导入的,那动态导入的代码需要放在单独的文件中。存在多个入口文件的话,还需要提取出公共模块的代码。CommonsChunkPlugin 就是用来完成上述的代码拆分的。
可配置属性
name:
打包出的chunk的name。就是[name][id][hash][chunkhash]的那个name。
如果设置的值与当前已存在的chunk的name相同,会将代码打包到当前已存在文件内。
如果设置的值不存在,就会创建一个新的文件。filename:
对应output.filename与output.chunkFilename,优先级高于这两个属性。设置值时遵循的规则也与这两个属性相同。(路径之类的也要在这里设置,所以还是直接使用output里面的吧)chunks:
指定从哪些chunk当中去找公共模块,省略该选项的时候,默认就是entry chunks。
推荐提取同步的公共模块时,设置chunks,提取异步的公共模块时,设置children: true。minChunks:
默认值为2。我的理解是有多少个模块引用了它,才可以传入公共chunk。- 数字:数量必须大于等于
2,或者少于等于chunks的数量 - 函数:接受
(module, count)两个参数,返回一个布尔值。可以在函数内进行规定好的逻辑来决定某个模块是否提取成为commons chunk。 Infinity:传入Infinity会马上生成公共chunk,但里面没有模块。
- 数字:数量必须大于等于
children:
指定source chunks,不可以与chunks属性一同设置。通常是与aysnc一起使用,设置为true时,所有公共chunk的子模块都会被选择。
推荐提取异步模块的时候,使用children: true,不然要把需要提取的模块都在chunks中列出来。
提取同步模块的公共模块,不设置chunks,只设置children时,你是提取不出东西来的。在
main.js中加入下列代码,这三个文件都import了同一个async.js文件,在打包时,需要将async.js文件提取出来。1
2
3const Emoji = () => import(/* webpackChunkName: "Emoji111" */ './components/Emoji')
const Photos = () => import(/* webpackChunkName: "Photos222" */ './components/Photos')
const Photos2 = () => import(/* webpackChunkName: "Photos333" */ './components/Photos2')下面两个设置的效果是相同的。
1
2
3
4
5
6new webpack.optimize.CommonsChunkPlugin({
name: 'app',
async: true,
minChunks: 2,
chunks: ['Emoji111','Photos222','Photos333']
})1
2
3
4
5
6new webpack.optimize.CommonsChunkPlugin({
name: 'app',
async: true,
minChunks: 2,
children: true
})
async:不可以与filename一起设置。设置为true的会提取异步加载chunk中的公共模块。此时设置children为false是无效的。true:设置为true时,会从异步加载的chunk中提取公共的模块。'string':设置为字符串时,与true的作用是相同的,但是会将提取出的文件的name设置为该字符串。
(还是那个[name][id][hash][chunkhash]的[name])
项目代码示例
项目的 output 配置如下:
1 | output: { |
打包第三方库
提取 node_modules 文件夹中的文件到 vendor 模块中。1
2
3
4
5
6
7
8
9
10
11new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks (module) {
// any required modules inside node_modules are extracted to vendor
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(path.join(__dirname, '../node_modules')) === 0
)
}
})
打包 webpack 运行文件与模块清单
避免每次打包生成的 vendor.js 对应的哈希值都会变化。1
2
3
4
5
6// 不设置 `minChunks:Infinity` 时也是会将 `manifest` 文件打包出来的。
// 但是 `vue-cli` 生成的文件中是这样写的,我就直接复制过来了。
new webpack.optimize.CommonsChunkPlugin({
name: 'manifest',
minChunks: Infinity
})
打包异步文件
name:此处的 name 指定的是入口文件的 name,而不是打包出来的文件的 name。
1 | new webpack.optimize.CommonsChunkPlugin({ |
上述代码可以简化为:1
2
3
4
5new webpack.optimize.CommonsChunkPlugin({
name: 'app',
async: 'vendor-async',
minChunks: 3
})
打包自定义公共模块
这个配置是生成的文件中没有的,我们的系统只有一个入口文件,也不需要这个。写在这里是怕以后忘记了。
从 first222 与 second111 文件中提取公共模块,并打包到 common 文件。此处的 first222 与 second111 对应的是 entry 处定义的模块名。
1 | entry: { |
1 | new webpack.optimize.CommonsChunkPlugin({ |