我是如何把UMI3应用 HMR 热更新 速度从20S优化到4S的

1,137 阅读5分钟

这个项目是使用公司脚手架搭建而成的,本身是基于UMI3进行封装的,所以直接认为是针对UMI3优化是没啥问题的,所以想分享一下自己在尝试优化UMI3构建相关速度的一些思路和做法

电脑配置

  • 芯片:Apple M1
  • 内存:16GB

前端工具

  • node:16.17.0
  • npm:8.15.0
  • yarn:1.22.11

项目依赖

  • @umijs/core:3.5.15

路由体量

routes文件有接近4000行,暂且认为有几百个route吧,懒得查了

差异对比

直接上最终优化数据对比表格,每次对比都会包含有无缓存对比。

分支Dev TimeHMR TimeBuild TimeBuild SizeAnalyze备注
main3.88m20.09s8.93m91.21 MB-无缓存
main1.30m19.99m5.03m--有缓存
feature/best-hmr1.22m4.52s3.87m40.72 MB-无缓存
feature/best-hmr45.52s4.54s1.90m--有缓存

!! 该结果在同事的window电脑也跑了,基本无变化,优化的热更新速度基本也保持在4s

尝试的方案

× 尝试 umi3 推荐的mfsu

用不了,各种报错,启动不了。修了第一个bug,还会有第二个第三个,无穷无尽,最后顶不住了直接放弃。

小结

放弃

! 尝试 umi3官方提供的一些思路

我这边直接把所有方法都过了一遍

官方方法是否使用效果
配置 nodeModulesTransform 为 { type: 'none' }有一些包必须要transform不然项目无法启动,按照官方方式配置type和exclude,直接报错,放弃了
查看包结构必用,没啥好说的
配置 externals这个项目有些特殊,暂时跳过cdn相关的优化。。。
减少补丁尺寸浏览器兼容补丁,尽量还是不要动吧
调整 splitChunks 策略,减少整体尺寸效果出类拔萃
通过 NODE_OPTIONS 设置内存上限跳过
调整 SourceMap 生成方式试了很多帖子的配置方式,综合看下来,官方默认的就挺好,再改本地开发调试就不舒服了
monaco-editor 编辑器打包项目没用到这个
替换压缩器为 esbuild开发环境没用,生产有效果
不压缩没啥效果

所以综合下来,结合ANALYZE优先使用splitChunks的方式解决,分析了一下现有的分包策略,发现已经做了,但是因为参数配置有问题所以导致打包出的体积非常夸张。

放一下代码,具体参数和配置这里就不额外分析了 官方都有

chainWebpack(config) {
    config.merge({
        optimization: {
            splitChunks: {
                chunks: 'all',
                minSize: 3000,
_               minChunks: 6,
+               minChunks: 2,
+               maxAsyncRequests: 40,
+               maxInitialRequests: 40,
                automaticNameDelimiter: '.',
                cacheGroups: {
                    // 省略配置
                }
            }
        }
    })
}

结论

splitChunks可行,改动之后Build 相关的 Size 和 Time 都一定程度的提升。

  • Dev Time → 3.71m 无变化
  • HMR TIme → 21.58s 无变化
  • Build TIme → 无缓存6.41m 有缓存3.27m
  • Build Size Parsed → 40.27 MB

× 使用speed-measure-webpack-plugin进行分析

本身想着用这个插件,看看plugin和loader的消耗时间,但是这个项目不知道为啥用了之后,构建极慢,几个小时都走不完,几经周折,最后放弃借助该插件分析,后面就自己人肉冲了。

小结

放弃

√  路由JSON文件优化(不通用,可以忽略)

这个应该算是该项目的专属问题了,可能没有太大的参考意义。这里简单提一下。

就是因为某些业务需求,组内的前端小伙伴把route相关信息搬走了,搬到src文件夹下面了,所以原route的JSON文件就没有人任何作用了,但是一直留着没有删除。

就尝试删除试试,没想到带来意外惊喜。

小结

猜测是,公司脚手架或者umi会默认读取配置文件下JSON文件啥的巴拉巴拉,只要读了肯定会占用一定的内存资源,后面就没仔细研究了。毕竟项目还没有优化好,所以重心优先放到优化上,后面有时间在抽空回来看。

  • Dev Time → 3.38m 无变化
  • HMR TIme → 11.36s
  • Build TIme → -- 不牵扯
  • Build Size Parsed → -- 不牵扯

√  深扒UMI的Webpack Loader配置

研究官方配置,过了一遍他们默认集成的loader,发现官方有两个额外的Loader

  • ts-in-node_modules
  • js-in-node_modules

已知

  • 我们开发环境都是在google浏览器操作
  • npm包都是已经编译打包过的,基本没有任何一个包会直接提供未编译的ts和js文件进行使用(万事无绝对)
  • 回过头再看配置 nodeModulesTransform 为 { type: 'none' }这个官方推荐优化项
  • umi的二次编译是为了补丁相关,常规情况下生产环境才会考虑

所以我们

chainWebpack(config) {
+    if (process.env.NODE_ENV !== 'production') {
+        config.module
+        .rule('js-in-node_modules')
+        .include.clear()
+        // 这里单独处理了一下这个包,因为这个包产出的文件还是包含了一定量的es6语法
+        .add(/node_modules[\\/]@tms[\\/]platform-site-pro-tui-table-render/);
+
+        config.module.rules.delete('ts-in-node_modules');
+    }
}

小结

这里额外放两篇文章,哈哈哈,回复人都是同一个。

构建速度巨量提升,直接看数据

  • Dev Time → 无缓存 1.22m 有缓存49.19s
  • HMR TIme → 10.36s 一点点变化  可以忽略
  • Build TIme → -- 不牵扯
  • Build Size Parsed → -- 不牵扯

√  按需加载router的弊端

一开始看到过这个帖子,后续考虑文件是否都会被重新走一遍,就尝试【注释掉所有路由】【注释掉一部分】【全部放开】,热更新有明显变化就开始研究相关issue

[Build Performance] chunk graph very much slow

文中都写了就不再赘述

小结

HMR速度巨量提升,直接看数据

  • Dev Time → 无缓存 1.22m 有缓存49.19s
  • HMR TIme → 4.44s 提升一倍
  • Build TIme → -- 不牵扯
  • Build Size Parsed → -- 不牵扯