Webpack 4 SplitChunksPlugin配置方案(轉)

一般狀況下咱們的 WebApp 是有咱們的自身代碼和第三方庫組成的,咱們自身的代碼是會經常變更的,而第三方庫除非有較大的版本升級,否則是不會變的,因此第三方庫和咱們的代碼須要分開打包,咱們能夠給第三方庫設置一個較長的強緩存時間,這樣就不會頻繁請求第三方庫的代碼了。javascript

那麼如何提取第三方庫呢?在 webpack4.x 中, SplitChunksPlugin 插件取代了 CommonsChunkPlugin 插件來進行公共模塊抽取,咱們能夠對SplitChunksPlugin 進行配置進行 拆包 操做。html

SplitChunksPlugin配置示意以下:前端

optimization: {
    splitChunks: { chunks: "initial", // 代碼塊類型 必須三選一: "initial"(初始化) | "all"(默認就是all) | "async"(動態加載) minSize: 0, // 最小尺寸,默認0 minChunks: 1, // 最小 chunk ,默認1 maxAsyncRequests: 1, // 最大異步請求數, 默認1 maxInitialRequests: 1, // 最大初始化請求書,默認1 name: () => {}, // 名稱,此選項課接收 function cacheGroups: { // 緩存組會繼承splitChunks的配置,可是test、priorty和reuseExistingChunk只能用於配置緩存組。 priority: "0", // 緩存組優先級,即權重 false | object | vendor: { // key 爲entry中定義的 入口名稱 chunks: "initial", // 必須三選一: "initial"(初始化) | "all" | "async"(默認就是異步) test: /react|lodash/, // 正則規則驗證,若是符合就提取 chunk name: "vendor", // 要緩存的 分隔出來的 chunk 名稱 minSize: 0, minChunks: 1, enforce: true, reuseExistingChunk: true // 可設置是否重用已用chunk 再也不建立新的chunk } } } } 複製代碼

SplitChunksPlugin 的配置項不少,能夠先去官網瞭解如何配置,咱們如今只簡單列舉了一下配置元素。vue

若是咱們想抽取第三方庫能夠這樣簡單配置java

splitChunks: {
      chunks: 'all', // initial、async和all minSize: 30000, // 造成一個新代碼塊最小的體積 maxAsyncRequests: 5, // 按需加載時候最大的並行請求數 maxInitialRequests: 3, // 最大初始化請求數 automaticNameDelimiter: '~', // 打包分割符 name: true, cacheGroups: { vendor: { name: "vendor", test: /[\\/]node_modules[\\/]/, //打包第三方庫 chunks: "all", priority: 10 // 優先級 }, common: { // 打包其他的的公共代碼 minChunks: 2, // 引入兩次及以上被打包 name: 'common', // 分離包的名字 chunks: 'all', priority: 5 }, } }, 複製代碼

這樣彷佛大功告成了?並無,咱們的配置有很大的問題:node

  1. 咱們粗暴得將第三方庫一塊兒打包可行嗎? 固然是有問題的,由於將第三方庫一塊打包,只要有一個庫咱們升級或者引入一個新庫,這個 chunk 就會變更,那麼這個chunk 的變更性會很高,並不適合長期緩存,還有一點,咱們要提升首頁加載速度,第一要務是減小首頁加載依賴的代碼量,請問像 react vue reudx 這種整個應用的基礎庫咱們是首頁必需要依賴的以外,像 d3.js three.js這種特定頁面纔會出現的特殊庫是不必在首屏加載的,因此咱們須要將應用基礎庫和特定依賴的庫進行分離。
  2. 當 chunk 在強緩存期,可是服務器代碼已經變更了咱們怎麼通知客戶端?上面咱們的示意圖已經看到了,當命中的資源在緩存期內,瀏覽器是直接讀取緩存而不會向服務器確認的,若是這個時候服務器代碼已經變更了,怎麼辦?這個時候咱們不能將 index.html 緩存(反正webpack時代的 html 頁面小到沒有緩存的必要),須要每次引入 script 腳本的時候去服務器更新,並開啓 hashchunk,它的做用是當 chunk 發生改變的時候會生成新的 hash 值,若是不變就不發生變更,這樣當 index 加載後續 script資源時若是 hashchunk 沒變就會命中緩存,若是改變了那麼會從新去服務端加載新資源。

下圖示意瞭如何將第三方庫進行拆包,基礎型的 react 等庫與工具性的 lodash 和特定庫 Echarts 進行拆分react

cacheGroups: {
        reactBase: { name: 'reactBase', test: (module) => { return /react|redux/.test(module.context); }, chunks: 'initial', priority: 10, }, utilBase: { name: 'utilBase', test: (module) => { return /rxjs|lodash/.test(module.context); }, chunks: 'initial', priority: 9, }, uiBase: { name: 'chartBase', test: (module) => { return /echarts/.test(module.context); }, chunks: 'initial', priority: 8, }, commons: { name: 'common', chunks: 'initial', priority: 2, minChunks: 2, }, } 複製代碼

咱們對 chunk 進行 hash 化,正以下圖所示,咱們變更 chunk2 相關的代碼後,其它 chunk 都沒有變化,只有 chunk2 的 hash 改變了webpack

output: {
    filename: mode === 'production' ? '[name].[chunkhash:8].js' : '[name].js', chunkFilename: mode === 'production' ? '[id].[chunkhash:8].chunk.js' : '[id].js', path: getPath(config.outputPath) } 複製代碼

 

image.png image.png

 

咱們經過 http 緩存+webpack hash 緩存策略使得前端項目充分利用了緩存的優點,可是 webpack 之因此須要傳說中的 webpack配置工程師 是有緣由的,由於 webpack 自己是玄學,仍是以上圖爲例,若是你 chunk2的相關代碼去除了一個依賴或者引入了新的可是已經存在工程中依賴,會怎麼樣呢?git

咱們正常的指望是,只有 chunk2 發生變化了,可是事實上是大量不相干的 chunk 的 hash 發生了變更,這就致使咱們緩存策略失效了,下圖是變動後的 hash,咱們用紅圈圈起來的都是 hash 變更的,而事實上咱們只變更了 chunk2 相關的代碼,爲何會這樣呢?github

 

image.png 緣由是 webpack 會給每一個 chunk 搭上 id,這個 id 是自增的,好比 chunk 0 中的id 爲 0,一旦咱們引入新的依賴,chunk 的自增會被打亂,這個時候又由於 hashchunk 根據內容生成 hash,這就致使了 id 的變更導致 hashchunk 發生鉅變,雖然代碼內容根本沒有變化。 image.png
這個問題咱們須要額外引入一個插件HashedModuleIdsPlugin,他用非自增的方式進行 chunk id 的命名,能夠解決這個問題,雖然 webpack 號稱 0 配置了,可是這個經常使用功能沒有內置,要等到下個版本了。
image.png

 

webpack hash緩存相關內容建議閱讀此文章 做爲拓展

做者:尋找海藍96 連接:https://juejin.im/post/5d00820b5188255ee806a1c7 來源:掘金 著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。
相關文章
相關標籤/搜索