webpack中splitChunks分包策略的實(shí)現(xiàn)
一、為什么需要拆包
隨著應(yīng)用程序規(guī)模的增長,JavaScript 文件的大小也越來越大。一個(gè)大的 JavaScript 文件會(huì)導(dǎo)致頁面加載時(shí)間過長,影響用戶體驗(yàn)。良好的拆包策略可以將一個(gè)大的 JavaScript 文件分割成多個(gè)較小的代碼塊,將公用的代碼抽離成單獨(dú)的 chunk,在需要的時(shí)候按需加載,并充分利用瀏覽器的緩存機(jī)制,如果使用合理,會(huì)極大影響加載時(shí)間。
二、拆包方式
入口起點(diǎn)(entry )
通過使用入口起點(diǎn)的方式,可以將代碼分離成多個(gè)單獨(dú)的文件,這些文件可以通過 webpack 配置一個(gè)數(shù)組結(jié)構(gòu)的 entry 選項(xiàng)指定。并且在其中傳入不同類型的文件,可以實(shí)現(xiàn)將 CSS 和 JavaScript(和其他)文件分離在不同的 bundle。但是,這種方式有一些缺點(diǎn),如無法動(dòng)態(tài)加載,無法共享模塊等。
代碼分離(Code Splitting)
代碼分離指將代碼分成不同的包/塊,然后可以按需加載,而不是加載包含所有內(nèi)容的單個(gè)包。用戶只需要下載當(dāng)前他正在瀏覽站點(diǎn)的這部分代碼,代碼分離可以使用ES6模塊中的 import() 函數(shù)動(dòng)態(tài)的加載模塊。使用動(dòng)態(tài)導(dǎo)入的模塊會(huì)被分割到一個(gè)單獨(dú)的 chunk 中。
打包分離(Bundle Splitting)
webpack 為單個(gè)應(yīng)用程序生成多個(gè) bundle 文件。如果你有一個(gè)體積巨大的文件,并且只改了一行代碼,用戶仍然需要重新下載整個(gè)文件。但是如果你把它分為了兩個(gè)文件,那么用戶只需要下載那個(gè)被修改的文件,而另一個(gè)文件瀏覽器可以從緩存中加載,從而減少重新發(fā)布并由此被客戶端重新下載的代碼量。
綜上所述,合理的拆包策略可以顯著提升應(yīng)用程序的性能。代碼分離通過將代碼按需加載,減小初始下載量;而打包分離將應(yīng)用程序拆分成多個(gè)塊,實(shí)現(xiàn)增量更新,減少不必要的下載。根據(jù)具體場景和需求,選擇合適的拆包方式可以最大程度地優(yōu)化應(yīng)用程序的加載性能。
三、splitChunks介紹
splitChunks 將滿足拆分規(guī)則的構(gòu)建內(nèi)容抽出來單獨(dú)打包,從而達(dá)到抽離公共模塊,減少重復(fù)打包的目的。splitChunks 中的配置項(xiàng)用來確定具體的拆分規(guī)則,其中的 cacheGroups 配置項(xiàng)必須同時(shí)滿足其下的所有條件才能生效。
webpack5 中 splictChunks 的默認(rèn)配置為:
module.exports = { optimization: { splitChunks: { chunks: 'async', // 生成的 chunk 的最小體積,單位為字節(jié)(bytes)。內(nèi)容超過了minSize的值,才會(huì)進(jìn)行打包 minSize: 20000, minRemainingSize: 0, // 在拆分之前,必須共享的模塊的最小 chunk 數(shù)。 minChunks: 1, // 在按需加載時(shí),允許的最大并行請(qǐng)求數(shù)。 maxAsyncRequests: 30, // 入口點(diǎn)允許的最大并行請(qǐng)求數(shù)。 maxInitialRequests: 30, // 超過這個(gè)值就會(huì)進(jìn)行強(qiáng)制分包處理,無視minRemainingSize,maxAsyncRequests,maxInitialRequests enforceSizeThreshold: 50000, cacheGroups: { vendors: { test: /[\\/]node_modules[\\/]/, priority: -10, // 如果當(dāng)前 chunk 包含已從主 bundle 中拆分出的模塊,則它將被重用,而不是生成新的模塊 reuseExistingChunk: true, }, default: { minChunks: 2, priority: -20, reuseExistingChunk: true, }, }, }, }, };
其中chunks屬性可配置值有 all、 async 、 initial ,默認(rèn)值是 async
- async : 異步加載進(jìn)來的包才會(huì)校驗(yàn)分包規(guī)則,進(jìn)行分包抽離。如果動(dòng)態(tài)加載的包也同時(shí)引用了其它包且命中分包規(guī)則也會(huì)被抽離出來。
- initial : 表示只從入口模塊進(jìn)行拆分。
- all : 表示入口模塊和異步加載的模塊都要進(jìn)行拆分。
四、splitChunks 拆包策略
split-by-experience: 根據(jù)經(jīng)驗(yàn)制定的拆分策略,自動(dòng)將一些常用的 npm 包拆分為體積適中的 chunk。適用于大多數(shù)項(xiàng)目。
如下示例,react、antd 會(huì)被包拆分到了單獨(dú)的chunk,其余三方包會(huì)在vendorjs。其余的包也可以配置緩存組。如果拆分力度比較細(xì)的話還是需要寫上一些緩存組的。
splitChunks: { // chunks、minSize、minChunks 將對(duì)所有緩存組生效 chunks: 'all', // 對(duì)所有的chunk進(jìn)行拆分 minSize: 20000, // 拆分 chunk 的最小體積 20000 bytes minChunks: 2, // 需在兩個(gè)模塊中共享才進(jìn)行拆分 cacheGroups: { vendor: { name: 'vendor', // chunk 的名稱 vendor test: /[\\/]node_modules[\\/]/i, // 匹配node_modules下所有的chunk priority: 10, // 優(yōu)先級(jí)10 優(yōu)先將node_modules下的chunk拆分到vendor組 reuseExistingChunk: true, // 重用模塊,而不是重新生成 enforce: true, // 強(qiáng)制拆分 }, default: { // 默認(rèn)組 非node_modules下的文件塊 將執(zhí)行default緩存組規(guī)則 reuseExistingChunk: true, priority: -10, // 優(yōu)先級(jí) -10 enforce: true, // 強(qiáng)制拆分 }, react: { // react組 name: 'react', test: /[\\/]node_modules[\\/]react[\\/]/, // 匹配node_modules下的react庫 priority: 20, // 優(yōu)先級(jí)20 優(yōu)先將node_modules下的react拆分出去 minChunks: 2, reuseExistingChunk: true, }, antd: { // antd組 name: 'antd', test: /[\\/]node_modules[\\/]antd[\\/]/, // 匹配node_modules下的antd庫 priority: 20, // 優(yōu)先級(jí)20 優(yōu)先將node_modules下的antd拆分出去 minChunks: 2, reuseExistingChunk: true, // 重用模塊,而不是重新生成 }, } }
split-by-module: 按 NPM 包的粒度拆分,每個(gè) NPM 包對(duì)應(yīng)一個(gè) chunk。
假如應(yīng)用程序添加或升級(jí)了某個(gè) npm 包,那么 vendor.js 的哈希值將會(huì)發(fā)生改變,這意味著用戶在訪問頁面時(shí)需要重新下載 vendor.js文件。這個(gè)時(shí)候如果對(duì)antd進(jìn)行了升級(jí)或新增/刪除了一個(gè)antd組件,那么用戶不需要重新下載vendor.js文件,而只需要下載antd模塊對(duì)應(yīng)的chunk。因?yàn)槊總€(gè)chunk都有一個(gè)獨(dú)立的哈希值,當(dāng)我們對(duì)單獨(dú)的chunk進(jìn)行修改時(shí),只會(huì)影響到對(duì)應(yīng)的chunk文件,而不會(huì)影響其他chunk文件。這樣就實(shí)現(xiàn)了對(duì)npm包的增量更新。
這種情況下如果npm包比較多的情況下,會(huì)產(chǎn)生高并發(fā)請(qǐng)求。對(duì)于支持http2的瀏覽器是沒有問題的。但是瀏覽器并不支持http2的話,也就是http1.1會(huì)存在對(duì)頭阻塞的問題。不過http2兼容性挺好的
splitChunks: { chunks: 'all', enforceSizeThreshold: 50000, cacheGroups: { vendors: { priority: -10, test: /[\\/]node_modules[\\/]/, name(module2) { return module2.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)?.[1]; }, }, }, minSize: 0, maxInitialRequests: Infinity, },
single-vendor: 將所有 NPM 包的代碼打包到一個(gè)單獨(dú)的 chunk 中。
這種情況的話,只要三方包有改動(dòng),文件hash就會(huì)改變。如果頻繁改動(dòng)npm包的話,瀏覽器緩存效率相對(duì)較低
vendor: { name: 'vendor', // chunk 的名稱 vendor test: /[\\/]node_modules[\\/]/i, // 匹配node_modules下所有的chunk priority: 10, // 優(yōu)先級(jí)10 優(yōu)先將node_modules下的chunk拆分到vendor組 reuseExistingChunk: true, // 重用模塊,而不是重新生成 enforce: true, // 強(qiáng)制拆分 },
split-by-size:根據(jù)模塊大小自動(dòng)進(jìn)行拆分。
符合大小范圍內(nèi)的包就會(huì)被拆出來
splitChunks: { chunks: 'all', minSize: 20000, // 20 KB maxSize: 50000, // 50 KB cacheGroups: { default: { minChunks: 2, priority: -20, reuseExistingChunk: true, }, }, },
五、總結(jié)
要根據(jù)業(yè)務(wù)場景來選擇合適的分包策略,拆到什么力度、什么程度需要自己斟酌。要注意拆包之后相同的模塊不要被重復(fù)打包。
到此這篇關(guān)于webpack中splitChunks分包策略的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)webpack splitChunks分包策略內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
javascript實(shí)現(xiàn)獲取瀏覽器版本、操作系統(tǒng)類型
這篇文章主要給大家分享一段javascript實(shí)現(xiàn)獲取瀏覽器版本、操作系統(tǒng)類型的封裝好的代碼,使用非常方便,也很實(shí)用,推薦給大家。2015-01-01微信小程序用swiper實(shí)現(xiàn)滑動(dòng)刻度尺
這篇文章主要為大家詳細(xì)介紹了微信小程序用swiper實(shí)現(xiàn)滑動(dòng)刻度尺,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-06-06JavaScript實(shí)現(xiàn)點(diǎn)擊單元格改變背景色的方法
這篇文章主要介紹了JavaScript實(shí)現(xiàn)點(diǎn)擊單元格改變背景色的方法,涉及JavaScript響應(yīng)鼠標(biāo)事件動(dòng)態(tài)操作頁面元素屬性的相關(guān)技巧,需要的朋友可以參考下2016-02-02uniapp的webview實(shí)現(xiàn)左滑返回上一個(gè)頁面操作方法
uniapp默認(rèn)左滑是關(guān)閉整個(gè)webview,而不是關(guān)閉當(dāng)前頁,本文給大家介紹uniapp的webview實(shí)現(xiàn)左滑返回上一個(gè)頁面操作方法,感興趣的朋友一起看看吧2023-12-12前端GET/POST請(qǐng)求下載文件多種方式代碼示例
文件都是通過接口獲取的,前端通過調(diào)用接口將接口返回的文件下載,下面這篇文章主要給大家介紹了關(guān)于前端GET/POST請(qǐng)求下載文件的多種方式,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-06-06javascript字符串與數(shù)組轉(zhuǎn)換匯總
本文給大家分享的是Js中字符串轉(zhuǎn)換成數(shù)組,數(shù)組轉(zhuǎn)換成字符串的函數(shù),十分的簡單實(shí)用,有需要的小伙伴可以參考下。2015-05-05關(guān)于微信小程序map組件z-index的層級(jí)問題分析
這篇文章主要給大家介紹了關(guān)于微信小程序map組件z-index的層級(jí)問題的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用微信小程序具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07js動(dòng)態(tài)添加onload、onresize、onscroll事件(另類方法)
window 的 onload、onresize、onscroll 事件,跟其他的事件不一樣,它不能用 attachEvent 或 addEventListener 來添加于是本人想了一些另類的方法,需要了解的朋友可以參考下2012-12-12