webpack4 之 cacheGroups 分包【究極奧義】

近來遇項目打包之事,撰文記之。以期分享,皆有所獲。html

前提

前提有兩點,須要獲得你的認同:vue

  1. 【後臺管理系統】框架和 UI 組件庫最強組合爲 vue-element-admin + Element UI!(●'◡'●)node

  2. webpack4 最核心的特性是 【splitChunks】,splitChunks 最核心的配置是 cacheGroups!webpack

基於這個兩個前提,咱們再進行下一步。web

分析工具

webpack 打包分析有它就夠了:webpack-bundle-analyzernpm

  • 安裝
npm install --save-dev webpack-bundle-analyzer
複製代碼
  • 配置:由於 vue-element-admin 基於 vueCli4,因此在 vue.config.js chainWebpack 中設置
config.plugin('BundleAnalyzerPlugin').use(BundleAnalyzerPlugin).tap(() => [
      {
        rel: 'BundleAnalyzerPlugin',
        analyzerMode: 'server', // 'server': 啓動端口服務;'static': 生成 report.html;'disabled': 配合 generateStatsFile 使用;
        generateStatsFile: false, // 是否生成stats.json文件
        analyzerHost: '127.0.0.1',
        analyzerPort: '8877',
        reportFilename: 'report.html',
        defaultSizes: 'parsed',
        openAnalyzer: false,
        statsFilename: 'stats.json',
        statsOptions: null,
        excludeAssets: null
      }
複製代碼

其中 analyzerMode 的設置比較重要。element-ui

  • 運行:
npm run dev 或 npm run build
複製代碼
  • 訪問:
http://127.0.0.1:8877
複製代碼

現狀問題

看一下我們的打包分析圖:json

得出如上圖的分包並不難,vue-element-admin 自帶這些配置。緩存

config.optimization.splitChunks({
        chunks: 'all',
        cacheGroups: {
          libs: {
            name: 'chunk-libs',
            test: /[\\/]node_modules[\\/]/,
            priority: 10,
            chunks: 'initial' // only package third parties that are initially dependent
          },
          elementUI: {
            name: 'chunk-elementUI', // split elementUI into a single package
            priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
            test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
          },
          commons: {
            name: 'chunk-commons',
            test: resolve('src/components'), // can customize your rules
            minChunks: 3, //  minimum common number
            priority: 5,
            reuseExistingChunk: true
          }
        }
      })
複製代碼

若是你暫時還看不懂這些配置項,先別急,後面會一一陳述。markdown

你只用先知道:它拆了初始化加載的第三方包、拆了 Element UI 庫、拆了 src/components。

一切彷佛好像還不錯,可是咱們並不知足。

實際上,我們跑一下 npm run build:test 也會報警告。

那麼還有哪些點能夠繼續優化?結合以上分析圖和 test warning,很明顯,咱們須要思考:

  1. Echarts 的體積大小不能忽視,如何處理它?是首頁加載仍是異步加載?要按需引入嗎?
  2. vue.js 等庫還能不能再拆?
  3. 首頁 Entrypoints 所依賴的包還能不能再優化?
  4. 包的體積應控制在什麼範圍?包太大,加載會太慢!包過小,會消耗 HTTP 請求鏈接!更多:合併 HTTP 請求是否真的有意義?
  5. 更多......

淦!打包什麼的,多打幾遍就完事了。十遍不行就一百遍,一百遍不行就一千遍,一千遍不行就......

優化的結果

淦完後得出以下打包分析圖:

本瓜成功的將打包大小從 3.1MB 變成了 2.36MB,文件數從 68個 打包到了 43個 !!!,既實現了拆包(拆公共庫),也實現了幷包(合併極小的包)。

雖然這不會是最終的結果,但本瓜能夠先下一個結論:

配置 cacheGroups,權衡拆包與幷包兩者,即是 webpack 分包的究極奧義!

如下是 cacheGroups 配置:

config.optimization.splitChunks({
        chunks: 'all',
         cacheGroups: {
            vue: {
              name: 'chunk-vuejs',
              test: /[\\/]node_modules[\\/]_?vue(.*)/,
              priority: 20
            },
            elementUI: {
              name: 'chunk-elementUI', // split elementUI into a single package
              priority: 30, // the weight needs to be larger than libs and app or it will be packaged into libs or app
              test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
            },
            commons: { // split async commons chunk
              name: 'chunk-async-commons',
              minChunks: 2,
              priority: 40,
              chunks: 'async'
            },
            echarts: { // split echarts libs
              name: 'chunk-echarts',
              test: /[\\/]node_modules[\\/]_?echarts(.*)/,
              priority: 50,
              chunks: 'async'
            },
            zrender: { // split zrender libs
              name: 'chunk-zrender',
              test: /[\\/]node_modules[\\/]_?zrender(.*)/,
              priority: 55,
              chunks: 'async'
            },
            'manage-sendMsg': { // resolve src
              name: 'chunk-manage-sendMsg',
              test: resolve('src/views/manage/sendMsg'),
              priority: 80,
              chunks: 'async'
            },
            'manage-packageLink': { // resolve src
              name: 'chunk-manage-packageLink',
              test: resolve('src/views/manage/packageLink'),
              priority: 80,
              chunks: 'async'
            },
            ......
      })
複製代碼

其實咱單獨從配置上去作優化,可操做的空間並不大。咱們還應該從打包分析結果去回看咱們的代碼細節,調整業務代碼來優化打包結果,或許是最直接有效的優化思路之一。包括:如何整合或解耦業務?如何作組件化?組件怎麼引?插件怎麼引?引多少?......每一個點都能再操做操做!

  • 尤爲注意
CommonJs(require) ES6(import)
輸出的是一個值的拷貝 輸出的是值的引用
運行時加載 編譯時輸出接口

cacheGroups

下面咱們再具體看看 cacheGroups 最關鍵的配置:

【重要】

  • name

chunk 的文件名

  • test

過濾 modules,默認爲全部的 modules,可匹配模塊路徑或 chunk 名字,當匹配到某個 chunk 的名字時,這個 chunk 裏面引入的全部 module 都會選中;

  • priority

權重,數字越大表示優先級越高。一個 module 可能會知足多個 cacheGroups 的正則匹配,到底將哪一個緩存組應用於這個 module,取決於優先級;

  • chunks(很是很是很是重要)

有三個值:all、async、initial。

這裏是一段示例代碼,來看看設置不一樣的 chunks,它們有什麼樣的打包區別:

//app.js
import "my-statis-module";

if(some_condition_is_true){
  import ("my-dynamic-module")
}
console.log("My app is running")
複製代碼

asyn : (default)

會生成兩個打包文件:

  1. bundle.js (包含 app.js + my-statis-module)
  2. chunk.js (只包含 my-dynamic-module)

initial :

會生成三個打包文件:

  1. app.js (只包含 app.js)
  2. bundle.js (只包含 my-static-module)
  3. chunk.js (只包含 my-dynamic-module)

all :

會生成兩個打包文件:

  1. app.js (只包含 app.js)
  2. bundle.js (包含 my-static-module + my-dynamic-module)

設置 "all" 大小將最小,區別使用這三者,是核心中的核心。


【瞭解】
  • minSize

表示被拆分出的 bundle 在拆分以前的體積的最小數值,只有 >= minSize 的 bundle 會被拆分出來;

  • maxSize

表示被拆分出的 bundle 在拆分以前的體積的最大數值,默認值爲 0,表示 bundle 在拆分前的體積沒有上限;maxSize 若是爲非 0 值時,不能小於 minSize;

  • minChunks

表示在分割前,可被多少個chunk分享的最小值

  • reuseExistingChunk

表示是否使用已有的 chunk,true 則表示若是當前的 chunk 包含的模塊已經被抽取出去了,那麼將不會從新生成新的,即幾個 chunk 複用被拆分出去的一個 module;

意外收穫

代碼層面:這樣寫,user.png 會被單獨打成一個包。打包出來 148B ,屬實不必!

<img v-show="imageUrl" :src="imageUrl" class="sort-img">
<img v-show="!imageUrl" src="~@/assets/user.png" class="sort-img">
複製代碼

若是改爲這樣,則不會再被單獨打包了。

<img :src="imageUrl?imageUrl:'~@/assets/user.png'" class="sort-img">
複製代碼

回看其它代碼,本瓜發現全部在條件判斷裏面引入的文件都會被單獨打包。然而它們其中有些是能夠調整寫法的,真不必將幾 KB 的文件單獨打包成一個幾 B 的包文件。

從打包的結果去檢驗代碼,也是一種不錯的優化手段!

策略小結

基於本次分包,本瓜簡單梳理一下策略:

  1. 公共的庫是必定要儘可能拆的。
  2. 公共的庫儘可能作到按需加載,這也是優化首屏加載須要注意的。
  3. 分包不能太細,0KB 至 10 KB 的包是極小的包,應當考慮合併。10 KB 至 100 KB 的包是小包,比較合適;100 KB 至 200 KB 的包只能是比較核心重要的包,須要重點關注,大於 200KB 的包就須要考慮拆包了。固然,也不排除一些特殊狀況。
包大小 策略
0 KB 至 10 KB 合併包
10 KB 至 100 KB 大小合適
100 KB 至 200 KB 核心包,重點關注
大於 200 KB 考慮拆包
特殊狀況 特殊處理

本次就先到這,打包無止境,願這個世上沒有打包攻城獅。

關注公衆號【掘金安東尼】,你的三連,個人動力!!!

相關文章
相關標籤/搜索