本文讲解的是最近在作的一个多页面项目,结合webpack4的splitChunks进行代码包分拆的过程html
两个入口文件都用react-loadable作了异步加载react
import Loadable from 'react-loadable';
...
const LoadableLogin = Loadable({
loader: () => import('../../common/components/login'),
loading: Loading,
});
...
复制代码
webpack部分配置相关以下:webpack
module.exports = {
...
mode: 'production',
entry: { // 多入口
home: './src/home',
topic: './src/topic',
},
output: {
path: config.build.assetsRoot,
filename: '[name].js',
publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath,
},
plugins: [
new HtmlWebpackPlugin({ // home页面
filename: 'home.html',
template: './template.html',
}),
new HtmlWebpackPlugin({ // topic页面
filename: 'topic.html',
template: './template.html',
inject: true,
}),
],
...
}
复制代码
好比说某个项目下有三个入口文件,a.js和b.js和c.js都是100byte,当咱们将minSize设置为301,那么webpack就会将他们打包成一个包,不会将他们拆分红为多个包。web
好比说某个项目下有三个入口文件,a.js和b.js和c.js都是100byte,当咱们将minSize设置为301,那么webpack就会将他们打包成一个包,不会将他们拆分红为多个包。浏览器
假设咱们生成了一个公用文件名字叫vendor,a.js,和b.js都依赖他,而且咱们设置的链接符是"~"那么,最终生成的就是 vendor~a~b.jsbash
若是咱们设置为1,那么每一个入口文件就只会打包成为一个文件babel
若是咱们设置为1,那么每一个入口文件就只会打包成为一个文件antd
test能够配置正则和写入function做为打包规则。其余属性都可继承splitChunks,这里必须说一下priority,设置包的打包优先级,很是重要!(后面结合实践)echarts
最少引入的次数框架
maxInitialRequest / maxAsyncRequests <maxSize <minSize。
咱们以一个最简单的配置开始,将公共代码打包出来
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,
},
}
复制代码
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包,仍是挺棒的!追求更精致的咱们,再认真想一想,是否是还能够作一些更好的优化?
到目前为止咱们打包文件的打包是这样的:
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,
},
}
复制代码
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次下载文件,太多可能会拔苗助长。你们能够根据本身的项目作不一样的拆分方法,总而言之,就是为了让项目更完美的在线上运行,给用户更好的体验~