天天看點

webpack建構優化實戰

背景

随着項目的推移, 第三庫使用數量增加,業務代碼更是成倍增加,不知不覺發現webpack建構速度卻越來越慢,從當初的30s,變成5分鐘以上。 與此同時,一個同學的項目也遇到了打包慢的問題。 于是下定決心,花兩周潛心研究下如何提升webpack建構性能。

初步成果

兩周後,收獲滿滿的。初步戰果如下:

(1) 自己的項目: vue2(全家桶)+element-ui+axios+echarts+lodash+… 約120個頁面

dev:從90s+ 優化到 41s

product: 從9分鐘+ 優化到 43s

(2) 同學的項目: react + redux + antd + moment+ rc-table + … 約40個頁面

dev: 從2分鐘+ 優化到 12s

product: 從9分鐘+優化到 13s

總結優化方法

首先,優化思路是從webpack建構過程去分析,主要是解析和壓縮優化。

分析工具

(1) webpack-bundle-analyzer

可視化檢視打包後的檔案,以及檔案包含的内容。

主要注意兩點:

  1. 每個打包後檔案的大小,其實業務代碼chunk包一般在20k以内。如果大了,就可能是把第三方庫打包進去了。
  2. 打包後的檔案是否有重複引用的庫,應該提出來。

    舉個栗子:

    優化前

    webpack建構優化實戰
    從圖中我們發現,打包後的檔案中, 很多包含了node_modulles/echarts, zrender兩個庫。 此時,我們就可以用DllPlugin插件,把這兩個第三方庫提出來, 減少單個業務代碼頁面打包後的檔案大小, 避免重複編譯。

優化後

webpack建構優化實戰

提取第三方庫後,我們發現頁面小了很多。 這時候又發現很多個檔案都包含了公共代碼src/utils/_serivce.js , 這種公共的業務代碼也是常見的問題, 通常有以下幾種辦法

  • 按需加載 import { a } from xxx, 每個頁面隻引用需要的。需要配合export使用,修改源檔案導出方式。
  • 公用方法挂載到根執行個體, 如vue中, Vue.prototype._utils = _utils 。 也需要修改源檔案,且不宜過大。
  • Tree Shaking 打包後,抖落掉不需要的代碼, 不用修改源碼。

(2)webpack - -profile

可以檢視打包過程中,每個步驟的速度。如果某個步驟卡了很長時間,就把對應關鍵字放到github上搜尋, 可以發現一些很好的解決方法。

其中,同學的那個項目,打包過程中卡住在91% additional asset processing, 而且卡住了幾分鐘。 後來在github的webpack項目的issue中找到解決辦法, 更新webpack版本至2.7, 以及把extract-text-webpack-plugin庫更新至2.1.2。 居然一下快了幾分鐘~

另外, 把優化方法分成通用,開發,生産三類。

優先級從高到低,如下:

通用優化

  1. 使用 DllPlugin

    原理是把第三方庫檔案分離出來單獨編譯,并且緩存; 極大的減少業務頁面的編譯時間, 以及編譯後的檔案大小。

    優化時間: 3分鐘+

    詳細:

    https://webpack.js.org/plugins/dll-plugin/ (官網)

    https://www.cnblogs.com/ghost-xyx/p/6472578.html

  2. 更新webpack和node

    (1)webpack最新版本為v4+, 官方稱對比v3, 性能提升了60%。這次優化時,還是用v2.7, 因為更新v4失敗了。

    優化時間: 待實踐。

    詳細: https://blog.csdn.net/qq_26733915/article/details/79446460

    (2)更新node, node目前穩定版本為v8.9.4。保持最新版本能夠保證編譯性能,npm保持最新也能建立更高效的子產品樹以及提高解析速度。

    優化時間: 30s+

    詳細: https://www.cnblogs.com/xinjie-just/p/7061619.html

  3. 多線程解析

    (1) happypack, 多線程解析檔案,如babel-loader等耗時較長的。

    還可以配合cache-loader使用。

    優化時間: 15s左右

    詳細: https://github.com/amireh/happypack

    要求: webpack 2+

    (2) thread-loader: 還沒實踐過,原理也是多線程解析。

    優化時間: 待實踐

    詳細: https://webpack.js.org/loaders/thread-loader/

  4. 緩存

    cache-loader

    優化時間: 約5s

    詳細: https://webpack.js.org/loaders/cache-loader/

  5. 提取公共代碼

    CommonsChunkPlugin

    這次實踐中使用了CommonsChunkPlugin,并沒有什麼明顯效果, 然後就換成了DllPlugin。

    也許,這兩個項目都是單頁應用,多頁應用可能效果比較好。還是個疑惑的地方~

    優化時間: 待實踐

    詳細: https://webpack.js.org/plugins/commons-chunk-plugin/

  6. 其它

    (1) loaders應盡可能配置解析路徑include參數,排除路徑exclude參數, 減少解析時查詢範圍。

    (2) Tree Shaking. 按需加載思想差不多,去掉多餘的代碼。

    優化時間: 待實踐。

    詳細: https://webpack.js.org/guides/tree-shaking/

    (3) 第三庫的選擇, 盡量少用,或用精簡的庫替代;一些工具函數,最好用原生替代。

開發環境優化

  1. 在記憶體中編譯 webpack-dev-middleware等
  2. devtool 設定成cheap-module-eval-source-map, 已經能滿足調試需求, 編譯能更快。

    優化時間: 10s 左右

生産環境優化

  1. 多線程壓縮

    庫: webpack-parallel-uglify-plugin

    顧名思義, 多線程壓縮,配合緩存大大減少了壓縮時間,替代了自帶的UglifyJsPlugin

    優化時間: 40s+

    詳細:

// 多線程壓縮插件
const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');

plugins: [
    new ParallelUglifyPlugin({
      cacheDir: '.cache/',
      uglifyJS:{
        output: {
          comments: false
        },
        compress: {
          dead_code: true,
          warnings: false,
          drop_debugger: true,
          drop_console: true
        }
      },
      sourceMap: false
    })
   ]
           

2.多線程編譯

庫: parallel-webpack

優化時間: 待實踐

詳細: https://github.com/trivago/parallel-webpack

3.去掉source-map

大多數情況,生産環境不需要詳細源碼。

優化時間: 10s+

分享優化過程

解決問題的思路有時候更重要

  1. 很多技術官網是解決問題最快的方式, 如webpack建構優化官網文章
  2. 針對大部分第三方庫的疑難雜症,在github上對應該庫的issue,是最快解決問題的地方
  3. 一時沒有找到解決辦法, 休息一下,下次也許就會有不一樣的了解。

立個flag

  • 盡快完成待實踐的技術部分,出下一篇優化文章。
  • 研究優化首頁加載。

繼續閱讀