前言
前端时间在做项目加载优化时用到了splitChunks自动拆包,后了解了一下原理写下了此文。
Modules和Chunks
Modules简单来理解就是我们写的功能模块,不管是CommonJS还是ESM都算是一个Module,而Chunks则是webpack根据我们的规则/默认规则打包处理之后生成的产物,比如下图:
SplitChunks如何使用
关于拆包的具体使用,这里贴一个官网的例子简单说说,关于其他配置可参考webpack官网
splitChunks: {
chunks: "async", //chunks有三个值,initial表示直接引入的模块,async表示按需引入的模块,all则表示all in
minSize: 30000, //最小包体积,这里的单位是byte,超过这个大小的包会被splitChunks优化
minChunks: 1, //模块的最小引用次数,如果引用次数低于这个值,将不会被优化
maxAsyncRequests: 5, //设置async chunks的最大并行请求数
maxInitialRequests: 3, //设置initial chunks的最大并行请求数
automaticNameDelimiter: '~', //产出chunks的文件名分割符
name: true, //true:根据提取chunk的名字自动生成,false:根据缓存组IdHint生成,string:生成文件命即为这个string
cacheGroups: { //缓存组,自定义拆包规则在此定义
vendors: { //默认配置,node_modules的chunk
test: /[\/]node_modules[\/]/,
priority: -10
},
default: { //业务代码的chunk
minChunks: 2,
priority: -20,
reuseExistingChunk: true //复用已存在的chunks
}
}
}
而这一套默认的配置,则是在webpack里面默认定义的,我们可以在WebpackOptionsDefaulter.js里面找到它(当然还有别的配置项):
this.set("optimization.splitChunks", {});this.set("optimization.splitChunks.hidePathInfo", "make", options => {return isProductionLikeMode(options);});this.set("optimization.splitChunks.chunks", "async");this.set("optimization.splitChunks.minSize", "make", options => {return isProductionLikeMode(options) ? 30000 : 10000;//默认配置的minsize根据环境配置是不同的,生产环境的最小体积为30000byte,这里没有找到这样设置的理由,估计是因为开发环境的打包速度更为重要吧});this.set("optimization.splitChunks.minChunks", 1);this.set("optimization.splitChunks.maxAsyncRequests", "make", options => {return isProductionLikeMode(options) ? 5 : Infinity;});this.set("optimization.splitChunks.automaticNameDelimiter", "~");this.set("optimization.splitChunks.automaticNameMaxLength", 109);this.set("optimization.splitChunks.maxInitialRequests", "make", options => {return isProductionLikeMode(options) ? 3 : Infinity;});this.set("optimization.splitChunks.name", true);this.set("optimization.splitChunks.cacheGroups", {});this.set("optimization.splitChunks.cacheGroups.default", {//这里也就是我们看到的默认将业务代码和mode_modules单独拆分的初始化代码automaticNamePrefix: "",reuseExistingChunk: true,minChunks: 2,priority: -20});this.set("optimization.splitChunks.cacheGroups.vendors", {automaticNamePrefix: "vendors",test: /[\/]node_modules[\/]/,priority: -10});
接下来举个实际使用例子吧:
splitChunks: {
chunks: 'all',
automaticNameDelimiter: '.',
name: true,
minSize: 30000,
maxSize: 0,
minChunks: 1,
maxAsyncRequests: 10,
maxInitialRequests: 6,
cacheGroups: {
antdesigns: {
name: 'antdesigns',
test: /[\/]node_modules[\/](@antd|antd|@ant-design)[\/]/,
priority: 10
},
reactfileviewer: {
name: 'reactfileviewer',
test: /[\/]node_modules[\/](react-file-viewer)[\/]/,
priority: 10
},
pdfmake: {
name: 'pdfmake',
test: /[\/]node_modules[\/](pdfmake)[\/]/,
priority: 10
},
bizcharts: {
name: 'bizcharts',
test: /[\/]node_modules[\/](bizcharts)[\/]/,
priority: 10
},
commons: {
name: 'commons',
test: /[\/]src[\/]/,
priority: 1
},
vendors: {
name: 'vendors',
test: /[\/]node_modules[\/]/,
priority: -1
},
}
这里值得注意的是,在我们的配置里面,任何一项不满足都不会进入该项的拆包逻辑
SplitChunks原理
接下来我们结合源码看看SplitChunks的运行原理&#x