手上的公司項目熱重載一直很慢,每次熱重載大概要 15s
左右,最近實在忍無可忍,決定排查一下。html
項目是基於 vue-cli2 搭建的,前人將 webpack 升級到了 webpack4。出於歷史緣由,公司項目的模塊是根據模板(.html)劃分的,所以項目中存在超過 30 個模板
。這讓我想起了以前在優化一個 webpack3 項目的時候,也遇到過相似的多模板熱重載緩慢的狀況,當時是使用 html-webpack-plugin-for-multihtml 庫 解決了問題,所以我想,此次會不會也是 html-webpack-plugin 的鍋呢?vue
我嘗試把 html-webpack-plugin 升級到了最新的 @4.0.0-beta.8 版本,發現熱重載速度降到了 1s
左右!webpack
問題解決了,但是其中的原理是什麼呢?git
cpuprofile-webpack-plugin 是一個圖形化的 webpack 構建性能分析工具,它會統計構建過程當中每一個插件運行的時間,還會生成整個構建過程的火焰圖,以下圖,它記錄了個人項目使用 html-webpack-plugin@3.2.0 時一次熱重載的性能分析:github
圖:cpuprofile-webpack-plugin 分析結果web
咱們發如今整個 15.94s 的熱重載過程當中,html-webpack-plugin 的運行時間佔據了 13.51s
,能夠說幾乎所有時間都用在了這上面,這個圖也驗證了個人猜測。接下來,咱們經過火焰圖進一步分析,首先找一個運行時間較長,比較有表明性的 html-webpack-plugin 執行過程:vue-cli
圖:一次時間較長的 html-webpack-plugin 運行npm
點擊進去,查看更詳細的調用棧分析:json
圖:html-webpack-plugin 詳細的調用棧分析函數
發現所有耗時集中在 html-webpack-plugin/index.js -> templateParametersGenerator -> toJson 函數上。
首先查看了最新版(4.0.0-beta.8)中 templateParametersGenerator 方法的源碼,能夠看出它是用來生成 templateParameters 的默認配置的,而在這個版本中它並沒有調用 toJson 方法
:
圖:4.0.0-beta.8 templateParametersGenerator 的調用
圖:4.0.0-beta.8 templateParametersGenerator 的定義
而後回溯 3.2.0 版本以前的提交,終於見到了它的調用,webpack 文檔中解釋 compilation.getStats().toJson() 是用來生成編譯過程的性能分析 json 文件的方法,那麼罪魁禍首就是它了。
圖:3.2.0 templateParametersGenerator 的定義
後來我嘗試了把 html-webpack-plugin 的版本回退到 4.x 的第一個版本 4.0.0-alpha,發現熱重載性能依然是沒問題的,所以提交的定位就在 3.2.0 到 4.0.0-alpha 之間,通過一番查找,終於找到了這個 fix,出於性能緣由移除 compilation.getStats()
:
圖:fix: Remove compilation.getStats() call for performance reasons
其實此次排查我也走了很多彎路,以前一直在嘗試經過閱讀代碼查找,找了一天都找不出來,後來使用了性能分析工具才知道本身以前有多蠢 :-)。本文只是給你們講一個性能分析的故事,爲你們提供一些思路,但願你們的代碼都沒有bug~
因爲個人代碼裏踩了這個坑,因此給你們講一下,html-webpack-plugin 4.x 對鉤子函數進行了重構
,注意是重構,不是更新,也就是說,雖然名字改了,可是全部功能都是沒有變化且一一對應的,做者的 commit 裏使用的 badge 也是 refactor
:
圖:鉤子函數重構的 commit
圖:3.x 鉤子函數文檔
圖:4.x 鉤子函數文檔
圖:4.x 鉤子函數文檔