手上的公司项目热重载一直很慢,每次热重载大概要 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 钩子函数文档