本文講解的是最近在作的一個多頁面項目,結合webpack4的splitChunks進行代碼包分拆的過程html
項目有home和topic兩個入口文件,主要包括:react
兩個入口文件都用react-loadable作了異步加載webpack
import Loadable from 'react-loadable';
...
const LoadableLogin = Loadable({
loader: () => import('../../common/components/login'),
loading: Loading,
});
...
複製代碼
webpack部分配置相關以下:web
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就會將他們打包成一個包,不會將他們拆分紅爲多個包。瀏覽器
假設咱們生成了一個公用文件名字叫vendor,a.js,和b.js都依賴他,而且咱們設置的鏈接符是"~"那麼,最終生成的就是 vendor~a~b.jsbash
若是咱們設置爲1,那麼每一個入口文件就只會打包成爲一個文件babel
若是咱們設置爲1,那麼每一個入口文件就只會打包成爲一個文件antd
maxInitialRequest / maxAsyncRequests <maxSize <minSize。echarts
test能夠配置正則和寫入function做爲打包規則。其餘屬性都可繼承splitChunks,這裏必須說一下priority,設置包的打包優先級,很是重要!(後面結合實踐)框架
最少引入的次數
咱們以一個最簡單的配置開始,將公共代碼打包出來
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次下載文件,太多可能會拔苗助長。你們能夠根據本身的項目作不一樣的拆分方法,總而言之,就是爲了讓項目更完美的在線上運行,給用戶更好的體驗~