性能优化 2026 Q1
719 字 · 2 分钟#性能#工程化
这篇是一月中旬写的阶段记录,写的时候优化只推进完前半部分,后面几个方向刚列了标题还没动手。之后一直没顾上补,索性按当时的样子放出来,做了多少写多少。
这一轮性能优化的重点不是运行时(变更检测、渲染效率这些),而是构建产物:控制 bundle 体积、调整 chunk 拆分,减少首屏要加载的资源,把非关键代码拆到异步 chunk 里。
用 stats.json 定位体积问题
优化的第一步永远是定位问题。项目是 Angular,构建走 esbuild,可以生成 stats.json 来分析打包结果:
- 命令行:
ng build --stats-json - 或在构建配置里开
statsJson: true(见 官方文档)
生成之后上传到 esbuild.github.io/analyze,treemap 里各依赖的体积占比一目了然。
动手前还改造了一下构建命令:原来的流程没法向构建透传自定义参数,改造后支持 pnpm run build --stats-json,另外加了一个统一入口,一次性构建全部五个应用——先单独构建最大的主应用,其余四个分两批并行,全程自动带上 --stats-json,产物都能拿来做体积对比。
(分析截图里全是公司内部的包名,就不贴了。)
统一包版本,避免重复打包
产物里出现同一个依赖的多个版本,体积白白翻倍,还可能引发运行时差异。analyze 页面提示「This bundle has n warnings」时,多半就是重复版本。
用 pnpm overrides 把依赖和传递依赖锁到同一个版本:
{
"pnpm": {
"overrides": {
"d3-color": "3.0.1"
}
}
}
这一项每个应用平均减小约 0.1 MB,五个应用累计省 0.5 MB。
优化自研包的打包方式
内部有一个公式计算包,是体积重灾区。在不改功能的前提下调整打包方式、剔除冗余代码和依赖,main.js 从 1.73 MB 压到 82.97 KB,降了约 95%,gzip 后只有 19.9 KB。
每个应用平均减小约 0.4 MB,累计省 2 MB。后续还有空间:CJS 转 ESM、启用 tree-shaking,把面向对象的部分改成函数式实现。
按需引入,让 tree-shaking 真正生效
典型案例是 highlight.js。原来 import hljs from 'highlight.js' 全量引入,所有语言模块一起被打包。但富文本编辑器实际只需要十几种语言,改成引核心模块加手动注册:
import hljs from 'highlight.js/lib/core'
import bash from 'highlight.js/lib/languages/bash'
import javascript from 'highlight.js/lib/languages/javascript'
import python from 'highlight.js/lib/languages/python'
import sql from 'highlight.js/lib/languages/sql'
// ...实际用到的十几种语言
hljs.registerLanguage('bash', bash)
hljs.registerLanguage('javascript', javascript)
hljs.registerLanguage('python', python)
hljs.registerLanguage('sql', sql)
// ...
这个依赖从约 1 MB 压到 78 KB,降了约 93%。每个应用平均减小约 0.9 MB,累计省 5 MB。
还没做的
写到这里的时候,下面几个方向只列了计划:
- 剔除不必要的依赖、字体和 CSS
- 把 CJS 包转成 ESM,让 tree-shaking 能覆盖到
- chunk 拆分:懒加载和动态导入降首屏体积,非关键模块合理拆出去
做完再补。