淺談webpack SplitChunksPlugin實(shí)用指南
提到前端打包工具,毫無疑問想先到的是webpack。但是前端發(fā)展地很快,時不時會有新東西出現(xiàn),打包工具這邊之前也出現(xiàn)parcel和rollup。各種工具的碰撞,相互汲取優(yōu)點(diǎn),促進(jìn)技術(shù)的發(fā)展。
webpack4中支持了零配置的特性,同時對塊打包也做了優(yōu)化, CommonsChunkPlugin
已經(jīng)被移除了,現(xiàn)在是使用 optimization.splitChunks
代替。
下面就開始介紹splitChunks的內(nèi)容。
默認(rèn)情況
首先webpack會根據(jù)下述條件自動進(jìn)行代碼塊分割:
- 新代碼塊可以被共享引用,或者這些模塊都是來自node_modules文件夾里面
- 新代碼塊大于30kb(min+gziped之前的體積)
- 按需加載的代碼塊,并行請求最大數(shù)量應(yīng)該小于或者等于5
- 初始加載的代碼塊,并行請求最大數(shù)量應(yīng)該小于或等于3
塊打包默認(rèn)情況下只會影響按需加載模塊,因?yàn)閷Τ跏級K也進(jìn)行優(yōu)化打包會影響HTML中的script標(biāo)簽數(shù),增加請求數(shù)。
接下來看些例子來理解默認(rèn)情況的打包。
模塊全部是同步引入
// indexA.js import React from 'react' import ReactDOM from 'react-dom' import _ from 'lodash' console.log(_.join(['a', 'b'], '~')) ReactDOM.render( <div>SplitChunk</div>, document.getElementById('root') )
默認(rèn)情況只會影響按需加載模塊,所以所有內(nèi)容全部被打包到一起了。
有模塊動態(tài)導(dǎo)入
這里首先使用符合ECMAScript 提案 的 import() 語法
// indexA.js import React from 'react' import ReactDOM from 'react-dom' import _ from 'lodash' import(/* webpackChunkName: "async-jquery" */ 'jquery').then(component => { console.log(component) }) console.log(_.join(['a', 'b'], '~')) ReactDOM.render( <div>SplitChunk</div>, document.getElementById('root') )
這里jquery使用動態(tài)導(dǎo)入,打包結(jié)果中可以看到j(luò)query被單獨(dú)打包了
react按需加載
同樣的我們試要react按需加載,使用react-router提供的按需加載方案
AsyncModule模塊按上面方案異步加載Dashboard
import React from 'react' import ReactDOM from 'react-dom' import {BrowserRouter, Route} from 'react-router-dom' import AsyncModule from './AsyncModule.jsx' import _ from 'lodash' import $ from 'jquery' console.log(_.join(['a', 'b'], '~')) ReactDOM.render( <div> <BrowserRouter> <Route path='/' component={AsyncModule} /> </BrowserRouter> </div>, document.getElementById('root') )
從打包結(jié)果可以看到按需加載的模塊被打包到0.js去了。
講完了webpack默認(rèn)情況下對打包塊的優(yōu)化,接下來看splitChunks配置項(xiàng)。
配置項(xiàng)
相關(guān)配置項(xiàng):
module.exports = { //... optimization: { splitChunks: { chunks: 'async', minSize: 30000, minChunks: 1, maxAsyncRequests: 5, maxInitialRequests: 3, automaticNameDelimiter: '~', name: true, cacheGroups: {} } } }
- chunks: 表示哪些代碼需要優(yōu)化,有三個可選值:initial(初始塊)、async(按需加載塊)、all(全部塊),默認(rèn)為async
- minSize: 表示在壓縮前的最小模塊大小,默認(rèn)為30000
- minChunks: 表示被引用次數(shù),默認(rèn)為1
- maxAsyncRequests: 按需加載時候最大的并行請求數(shù),默認(rèn)為5
- maxInitialRequests: 一個入口最大的并行請求數(shù),默認(rèn)為3
- automaticNameDelimiter: 命名連接符
- name: 拆分出來塊的名字,默認(rèn)由塊名和hash值自動生成
- cacheGroups: 緩存組。緩存組的屬性除上面所有屬性外,還有test, priority, reuseExistingChunk
- test: 用于控制哪些模塊被這個緩存組匹配到
- priority: 緩存組打包的先后優(yōu)先級
- reuseExistingChunk: 如果當(dāng)前代碼塊包含的模塊已經(jīng)有了,就不在產(chǎn)生一個新的代碼塊
配置項(xiàng)基本就上面這些,我們重點(diǎn)來看下chunks和cacheGroups。
chunks
chunks的取值是有initial, async, all。默認(rèn)情況下是async,在本文第一部分已經(jīng)介紹了它的表現(xiàn),所以現(xiàn)在來看下其它兩個的表現(xiàn)。
initial
, all
模式會將所有來自node_modules的模塊分配到一個叫vendors的緩存組;所有重復(fù)引用至少兩次的代碼,會被分配到default的緩存組。
// indexA.js import './Dashboard.jsx' // indexB.js import './Dashboard.jsx' // Dashboard.jsx import React from 'react'
// webpack.config.js splitChunks: { chunks: 'initial' }
打包表現(xiàn)正如上面所述,產(chǎn)生了兩個代碼塊vendors, default。
可以通過配置optimization.splitChunks.cacheGroups.default: false禁用default緩存組。
// webpack.config.js splitChunks: { chunks: 'initial', cacheGroups: { default: false } }
至于all和initial的差別,可以看下這篇文章Webpack 4 — Mysterious SplitChunks Plugin (要科學(xué)上網(wǎng))
里面有提到 initial
模式下會分開優(yōu)化打包異步和非異步模塊。而 all
會把異步和非異步同時進(jìn)行優(yōu)化打包。也就是說moduleA在indexA中異步引入,indexB中同步引入, initial
下moduleA會出現(xiàn)在兩個打包塊中,而 all
只會出現(xiàn)一個。
cacheGroups
使用cacheGroups可以自定義配置打包塊。
// indexA.js import React from 'react' import ReactDOM from 'react-dom' import _ from 'lodash' import $ from 'jquery' // indexB.js import React from 'react' import ReactDOM from 'react-dom' import('lodash') import $ from 'jquery' // webpack.config.js optimization: { splitChunks: { cacheGroups: { commons: { name: 'commons', chunks: 'initial', minChunks: 2 } } } }
根據(jù)開頭介紹webapck分割條件,一些公共模塊被打包進(jìn)了commons,自定義打包塊的優(yōu)先級是0,所以現(xiàn)在公共模塊會被打包進(jìn)commons,而不是上述提到的默認(rèn)打包塊vendors(優(yōu)先級為負(fù))。
但是這邊為什么lodash為什么沒打包在一起呢?可以回顧下initial和all的區(qū)別。接下來實(shí)驗(yàn)下all的效果。
// indexA, indexB同上 // webpack.config.js optimization: { splitChunks: { cacheGroups: { commons: { name: 'commons', chunks: 'all', minChunks: 2 } } } }
結(jié)果在預(yù)期中,lodash被打包在一起了。
提取第三方庫
最后看下之前CommonsChunkPlugin常用的分離部分第三方庫功能。這邊你可以想一下怎么操作。
上面已經(jīng)提到了設(shè)置 chunks: initial || all
都可以提取出第三方庫。但是它是把所有第三庫提取出來,所以我們在只提取react和react-dom的情況下,需要自定義一個cacheGroup。
// indexA.js import React from 'react' import ReactDOM from 'react-dom' import _ from 'lodash' import $ from 'jquery' // webpack.config.js entry: { indexA: path.join(__dirname, 'src/indexA.js') }, optimization: { splitChunks: { chunks: 'all', cacheGroups: { vendors: { test: /react/, name: 'vendors' } } } }
我們?nèi)ブ貙懥藇endors打包塊,只打包匹配react的模塊,所以達(dá)到了之前CommonsChunkPlugin的功能。
或者
// index.jsx import React from 'react' import ReactDOM from 'react-dom' // webpack.config.js entry: { indexA: path.join(__dirname, 'src/indexA.js'), vendor: ["react", "react-dom"] }, optimization: { splitChunks: { cacheGroups: { vendor: { name: "vendor", chunks: "initial" } } } }
optimization.runtimeChunk
最后提一下runtimeChunk,通過 optimization.runtimeChunk: true
選項(xiàng),webpack會添加一個只包含運(yùn)行時(runtime)額外代碼塊到每一個入口。(譯注:這個需要看場景使用,會導(dǎo)致每個入口都加載多一份運(yùn)行時代碼)
總結(jié)
webpack4的splitChunks功能是比較強(qiáng)大的,不過推薦還是使用默認(rèn)模式,或者提取一下第三方庫。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Vue.js實(shí)戰(zhàn)之組件之間的數(shù)據(jù)傳遞
這篇文章主要介紹了Vue.js實(shí)戰(zhàn)之組件之間的數(shù)據(jù)傳遞的相關(guān)資料,文中通過示例代碼和圖文介紹的非常詳細(xì),對大家具有一定的參考價值,需要的朋友們下面來一起看看吧。2017-04-04vue-simple-uploader上傳成功之后的response獲取代碼
這篇文章主要介紹了vue-simple-uploader上傳成功之后的response獲取代碼,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧~2020-09-09el-select 下拉框多選實(shí)現(xiàn)全選的實(shí)現(xiàn)
這篇文章主要介紹了el-select 下拉框多選實(shí)現(xiàn)全選的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08Vue?elementui如何實(shí)現(xiàn)表格selection的默認(rèn)勾選
這篇文章主要介紹了Vue?elementui如何實(shí)現(xiàn)表格selection的默認(rèn)勾選問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-06-06Vue.prototype全局變量的實(shí)現(xiàn)示例
在Vue中可以使用Vue.prototype向Vue的全局作用域添加屬性或方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-06-06Vue中的驗(yàn)證登錄狀態(tài)的實(shí)現(xiàn)方法
這篇文章主要介紹了Vue中的驗(yàn)證登錄狀態(tài)的實(shí)現(xiàn)方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-03-03Vue2.0實(shí)現(xiàn)組件數(shù)據(jù)的雙向綁定問題
這篇文章主要介紹了Vue2.0實(shí)現(xiàn)組件數(shù)據(jù)的雙向綁定問題,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2018-03-03巧妙運(yùn)用v-model實(shí)現(xiàn)父子組件傳值的方法示例
這篇文章主要介紹了巧妙運(yùn)用v-model實(shí)現(xiàn)父子組件傳值的方法示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-04-04vue實(shí)現(xiàn)excel文件的導(dǎo)入和讀取完整步驟
Vue的數(shù)據(jù)綁定功能非常強(qiáng)大,很適合用來讀取Excel內(nèi)容,這篇文章主要給大家介紹了關(guān)于vue實(shí)現(xiàn)excel文件的導(dǎo)入和讀取的相關(guān)資料,文中通過代碼示例介紹的非常詳細(xì),需要的朋友可以參考下2023-10-10