Webpack打包优化

前端有一个很常见的需求,就是要把 js 打的包切割,这样用户在访问的时候,可以并行加载多个 js 包,大大提高访问速度,缩短首屏白屏时间。

optimization.splitChunks

直接上代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
entry: {
collection: './src/index.js', // collection为chunk的名字,chunk的入口文件是main.js
},
//输出的路径和文件名,publicPath: '/'很重要,否则部署之后找不到路径
output: {
path: __dirname + '/dist/js',
filename: '[name].[hash].js',
publicPath: '/',
},
plugins: [new ExtractTextPlugin('[name].[hash].css')],
optimization: {
splitChunks: {
chunks: 'async',
minSize: 30000,
maxSize: 0,
minChunks: 1,
maxAsyncRequests: 6,
maxInitialRequests: 4,
automaticNameDelimiter: '~',
name: true,
cacheGroups: {
'react-vendor': {
test: (module) =>
/react/.test(module.context) ||
/redux/.test(module.context) ||
/classnames/.test(module.context) ||
/prop-types/.test(module.context),
priority: 2,
reuseExistingChunk: false,
},
'antd-vendor': {
// || /[\\/]node_modules[\\/]/.test(module.context)
test: (module) => /antd/.test(module.context),
priority: 3,
reuseExistingChunk: false,
},
},
},
},
};

chunks表示显示块的范围,有三个可选值:initial(初始块)、async(按需加载块)、all(全部块),默认为all;

minSize表示在压缩前的最小模块大小,默认是 30kb;

maxSize表示打包出来的新的 chunk 最大的文件大小,超过这个值,将新的 chunk 再进一步拆分成更小的 chunk,单位 B,默认 0。此处要注意 minSize、maxsize、maxAsyncRequests、maxInitalRequests,相互之间可能存在冲突,比如分离出来的包>maxSize,需要进一步拆分 chunk,拆分出来的 chunk 大小<minSize,或者说拆分出来 chunk 之后,chunk 的数量>maxInitalRequests,这个时候怎么办?它们之间是有优先级的:minSize > maxSize > maxInitialRequest/maxAsyncRequests,也就是我必须先满足 minSize 才会考虑是否满足 maxSize,最后才考虑 maxInitialRequest/maxAsyncRequests 的条件

minChunks: 表示被引用次数,默认为 1

maxAsyncRequests表示异步的按需加载模块最大的并行请求数,通过 import()或者 require.ensure()方式引入的模块,分离出来的包是异步加载的。默认为 5

maxInitialRequests表示初始加载网页的最大并行数。默认为 3

automaticNameDelimitername 连接符,分离出来的新 chunk 的名字,默认基于 cacheGroupsKey,chunks 来源的 name 来取,例:缓存组的 cacheGroupsKey 是 vendor,来源 chunk 是的 name 是 adminA,adminB,那么连接符是,分离出的 chunk 名字是 vendoradminA~adminB.js。

nameBoolean | string | function (module, chunks, cacheGroupKey) 分离出来的 chunk 的取名规则。不能和入口文件同名,如果和入口文件同名,那么入口文件将会被移除,不会被打包

  • Boolean :如果是 true,基于 cacheGroupsKey,chunks 来源的 name 来取。如果是 false,按照数字 0 排序。
  • string : string 作为 name, string.js。
  • function (module, chunks, cacheGroupKey)
  1. cacheGroupKey: 缓存组的键名;
  2. chunks: Array 类型,splitChunks.chunks的数组集合,每一个 chunk 对象有很多属性,这里有用也就只有chunks[i].name,即打包来源chunk的键名;
  3. module: 可能有用的值module.context,module.resource,module.type;module.context公共模块来源chunk的所在文件夹,例如通过 npm 下载的包chunks.context == path.resolve(__dirname , 'node_modules')module.resource公共模块来源 chunk 的完整路径,module.type文件类型 javascript/auto,css/auto。
  4. 返回值: 返回值作为文件名,同样不能和入口文件同名,否则入口文件会被移除

如果需要做更精细度的代码分离,需要配置缓存组cacheGroups,cacheGroups 拥有上面所有的属性,除此之外还有priorityreuseExistingChunktestenforce四个属性,并且缓存组能够覆盖上面所有的属性。

  • priority:优先级,default:0;如果两个缓存组都需要将某一公共模块打包,为了不重复打包,肯定只能打包进入其中之一,那么优先考虑 priority 高的。
  • reuseExistingChunk:是否重用已经存在的模块,default:true;例:如果在当前缓存组需要抽离出 jquery.js,但是 jquery.js 已经被其它缓存组抽取出来了,那么将会重用已经抽取出来的 jquery.js。
  • testfunction (module, chunks) | RegExp | string 在 chunks 的基础上,精确的选择那些公共模块应该被打包。
  • enforce:忽略 minSize、maxSize、maxAsyncRequests、maxInitalRequests 等限制条件直接打包。

缓存组也有默认配置 default ,default 的配置会覆盖 splitChunks 中的默认配置,并且其它缓存组的 minSize 的优先级低于 default 缓存组的优先级,所以默认配置最好还是在 splitChunks 配置,不要在缓存组配置

参考链接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
cacheGroups: {
commons: {
test: /[\\/]node_modules[\\/]/,
// cacheGroupKey here is `commons` as the key of the cacheGroup
name(module, chunks, cacheGroupKey) {
const moduleFileName = module
.identifier()
.split('/')
.reduceRight((item) => item);
const allChunksNames = chunks.map((item) => item.name).join('~');
return `${cacheGroupKey}-${allChunksNames}-${moduleFileName}`;
},
chunks: 'all',
},
},

output

output 中的配置filename: '[name].[hash].js',很重要,要把打包出来的 js 文件名用 hash 表示,这样在开发人员更新代码并部署到服务器之后,用户在浏览器使用的时候,不需要清空缓存的操作,浏览器就会向服务端获取最新的代码。否则,浏览器在检测到 js 名称没有改变,就不会去服务器拉取最新的代码。

Donate
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
  • Copyrights © 2018-2020 Jee
  • Visitors: | Views:

如果您觉得此文章帮助到了您,请作者喝杯咖啡吧~

支付宝
微信