详解webpack4之splitchunksPlugin代码包分拆本⽂讲解的是最近在做的⼀个多页⾯项⽬,结合webpack4的splitChunks进⾏代码包分拆的过程
项⽬框架
项⽬有home和topic两个⼊⼝⽂件,主要包括:
react、mobx、antd作为项⽬的基本框架,
echarts和d3(画图)是项⽬中部分页⾯⽤到⽐较⼤的组件库
src下的⼯作的组件和代码
其他的⾮公共代码。
两个⼊⼝⽂件都⽤react-loadable做了异步加载
import Loadable from 'react-loadable';
...
const LoadableLogin = Loadable({
loader: () => import('../../common/components/login'),
loading: Loading,
});
...
webpack部分配置相关如下:
...
mode: 'production',
entry: { // 多⼊⼝
home: './src/home',
topic: './src/topic',
},
output: {
path: config.build.assetsRoot,
filename: '[name].js',
publicPath: v.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath,
},
plugins: [
react router 方法new HtmlWebpackPlugin({ // home页⾯
filename: 'home.html',
template: './template.html',
}),
new HtmlWebpackPlugin({ // topic页⾯
filename: 'topic.html',
template: './template.html',
inject: true,
}),
],
...
}
splitChunks
chunks:
all: 不管⽂件是动态还是⾮动态载⼊,统⼀将⽂件分离。当页⾯⾸次载⼊会引⼊所有的包
async:将异步加载的⽂件分离,⾸次⼀般不引⼊,到需要异步引⼊的组件才会引⼊。
initial:将异步和⾮异步的⽂件分离,如果⼀个⽂件被异步引⼊也被⾮异步引⼊,那它会被打包两次(注意和all区别),⽤于分离页⾯⾸次需要加载的包。
minSize: ⽂件最⼩打包体积,单位byte,默认30000
⽐如说某个项⽬下有三个⼊⼝⽂件,a.js和b.js和c.js都是100byte,当我们将minSize设置为301,那么webpack就会将他们打包成⼀个包,不会将他们拆分成为多个包。
⽐如说某个项⽬下有三个⼊⼝⽂件,a.js和b.js和c.js都是100byte,当我们将minSize设置为301,那么webpack就会将他们打包成⼀个包,不会将他们拆分成为多个包。
automaticNameDelimiter:连接符
假设我们⽣成了⼀个公⽤⽂件名字叫vendor,a.js,和b.js都依赖他,并且我们设置的连接符是"~"那么,最终⽣成的就是vendor~a~b.js
maxInitialRequests ⼊⼝点处的最⼤并⾏请求数,默认为3
如果我们设置为1,那么每个⼊⼝⽂件就只会打包成为⼀个⽂件
maxAsyncRequests 最⼤异步请求数量,默认5
如果我们设置为1,那么每个⼊⼝⽂件就只会打包成为⼀个⽂件
优先级关系
maxInitialRequest / maxAsyncRequests <maxSize <minSize。
cacheGroups 定制分割包的规则
test可以配置正则和写⼊function作为打包规则。其他属性均可继承splitChunks,这⾥必须说⼀下 priority,设置包的打包优先级,⾮常重要!(后⾯结合实践)
minChunks
最少引⼊的次数
实践
我们以⼀个最简单的配置开始,将公共代码打包出来
splitChunks: {
chunks: 'all', // initial、async和all
minSize: 30000, // 形成⼀个新代码块最⼩的体积
maxAsyncRequests: 5, // 按需加载时候最⼤的并⾏请求数
maxInitialRequests: 3, // 最⼤初始化请求数
automaticNameDelimiter: '~', // 打包分割符
name: true,
cacheGroups: {
vendors: { // 打包两个页⾯的公共代码
minChunks: 2, // 引⼊两次及以上被打包
name: 'vendors', // 分离包的名字
chunks: 'all'
},
}
},
两个⼊⼝⽂件的公共代码被打包到vendor⽂件夹下⾯,包括echarts d3 amcharts等⼀些三⽅包和src下的公共代码。
这当然不是我们想要的结果!存在以下问题:
其实当我们进⼊⽹站,⼀般第⼀步都是进⼊⼀个登陆页⾯,需要的只是项⽬的基本框架代码,例如react,react-dom.antd 等,我们可以⽤all(或者initial)将它们单独打包,作为⾸页必须载⼊的包
我们打包的公共包,⾸次加载页⾯的时候,只想把同步加载的加载进来,所以需要⼀个同步的Common包
像echarts,d3,以及⼀些src下⾯⼀些异步加载的包,将它们利⽤async将打包成⼀个独⽴异步加载包
我们修改cacheGroups为:
cacheGroups: {
vendors: { // 项⽬基本框架等
chunks: 'all',
test: /(react|react-dom|react-dom-router|babel-polyfill|mobx)/,
priority: 100,
name: 'vendors',
},
'async-commons': { // 异步加载公共包、组件等
chunks: 'async',
minChunks: 2,
name: 'async-commons',
priority: 90,
},
commons: { // 其他同步加载公共包
chunks: 'all',
minChunks: 2,
name: 'commons',
priority: 80,
},
}
这次webpack帮我们打出来的包主要有:
async-common:是两个⼊⼝⽂件都异步加载的三⽅包和利⽤react-loader做的懒加载代码,有echarts,d3等
vendors: 包括react,react-dom,antd等
commons: 引⽤超过两次的同步代码
这⾥说两个需要注意的地⽅:
注意这⾥我们priority的设置,vendors>async-commons>commons,我们⾸先将react,react-dom等优先打包出来,然后再打包公共部分,如果将vendors的优先级设置⼩于两个Common的优先级,那么react,react-dom将会打包到common 包,将不会再⽣成vendors包。
如果我们这⾥将commons的配置去掉,将会⽣成⼀个topic~home的包,我们配置了async-common提取出异步加载的公共包后,将会默认将同步加载的公共包打包⽣成以automaticNameDelimiter连接符‘~'⽣成的名字'topic~home'包,内容其实和commons包内容完全⼀样,
ok!按照我们的要求,这样⾸次页⾯加载只会引⼊vendors,commons包,⽽不会引⼊async-common包,还是挺棒的!追求更精致的我们,再认真想想,是不是还可以做⼀些更好的优化?
到⽬前为⽌我们打包⽂件的打包是这样的:
⽤gzip压缩后,最⼤的async-common包有391kb。公司说最近因为⼀些状况,布置到⽣产后速度慢的时候,有时候只能有20kb/s的下载速度==。。。。于是继续split!
分析⼀下:
async-common中包含了⾃⼰写的src组件和第三⽅组件
async-common中⽐较⼤是echarts,zrender(echarts引⼊)和d3,结合项⽬来说,只有部分页⾯我们需要echarts(d3同),所以我们可以考虑将d3和echarts这两个⽐较⼤的包提取出来,等到某个页⾯需要的时候,再让其异步加载,这样就⼤⼤减⼩了async-common的体积了。
修改
cacheGroups: {
vendors: { // 基本框架
chunks: 'all',
test: /(react|react-dom|react-dom-router|babel-polyfill|mobx)/,
priority: 100,
name: 'vendors',
},
d3Venodr: { // 将体积较⼤的d3单独提取包,指定页⾯需要的时候再异步加载
test: /d3/,
priority: 100, // 设置⾼于async-commons,避免打包到async-common中
name: 'd3Venodr',
chunks: 'async'
},
echartsVenodr: { // 异步加载echarts包
test: /(echarts|zrender)/,
priority: 100, // ⾼于async-commons优先级
name: 'echartsVenodr',
chunks: 'async'
},
'async-commons': { // 其余异步加载包
chunks: 'async',
minChunks: 2,
name: 'async-commons',
priority: 90,
},
commons: { // 其余同步加载包
chunks: 'all',
minChunks: 2,
name: 'commons',
priority: 80,
},
}
当然,每次修改后,需要在htmlWebpackPlugin中配置chunk需要的包
plugins: [
new HtmlWebpackPlugin({ // home页⾯
filename: 'home.html',
template: './template.html',
chunks: ['vendors', 'commons', 'home'],
}),
new HtmlWebpackPlugin({ // topic页⾯
filename: 'topic.html',
template: './template.html',
chunks: ['vendors', 'commons', 'topic'],
}),
]
,
后期还做了其他的拆分和优化,⼤概最⼤的包保持在100k左右,当然也不建议拆的特别⼩,因为浏览器http1可能⼀次性⽀持6次下载⽂件,太多可能会适得其反。⼤家可以根据⾃⼰的项⽬做不同的拆分⽅法,总⽽⾔之,就是为了让项⽬更完美的在线上运⾏,给⽤户更好的体验~
以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。