文章工具与开发

前端性能预算:把“别变慢”写成构建门禁

性能很少在某一次提交里突然变差,而是在几十次“只多了几 KB”之后。给资源体积设定预算,并让 CI 在超出时失败,是我目前最有效的做法。

网格纸上,几条细线连接着不同形状的叶片(示意插图)
示意插图 · Waylan

性能退化很少来自某一次明显的错误提交。更常见的情况是:引入一个日期库多了十几 KB,加一个图标集又多了一些,每次评审都觉得“这点体积可以接受”。几个月后再测,首屏已经慢了一截,却找不到具体是哪一次改动造成的。

性能预算的思路是把“别变慢”从一种意愿变成一条可以被机器检查的规则:事先约定上限,超出时构建失败,由提交者解释原因或者优化。

预算的两类指标

  • 资源体积:JavaScript、CSS、字体和图片在压缩后的字节数。它与用户体验是间接关系,但在构建时就能精确测量,适合做门禁。
  • 用户体验指标:Core Web Vitals 中的 LCP、INP 和 CLS。web.dev 给出的“良好”阈值分别是 2.5 秒、200 毫秒和 0.1,以第 75 百分位的真实用户数据为准。

体验指标才是最终目标,但它依赖真实设备和网络,波动较大,不适合在每次提交时作为硬性门槛。我的做法是:体积预算放进 CI,体验指标通过线上采集持续观察,两者互相印证。

一个最小的体积检查

不需要引入额外工具,Node 自带的 zlib 就能计算 gzip 后的体积。下面的脚本读取构建产物,按扩展名汇总,超出预算时以非零状态码退出:

js
import { readdirSync, readFileSync } from "node:fs";
import { extname, join } from "node:path";
import { gzipSync } from "node:zlib";

const dir = "dist/assets";
const budgets = { ".js": 150 * 1024, ".css": 30 * 1024 };
const totals = { ".js": 0, ".css": 0 };

for (const file of readdirSync(dir)) {
  const ext = extname(file);
  if (ext in totals) totals[ext] += gzipSync(readFileSync(join(dir, file))).length;
}

let failed = false;
for (const [ext, limit] of Object.entries(budgets)) {
  const used = totals[ext];
  console.log(`${ext.padEnd(5)} ${(used / 1024).toFixed(1)} / ${limit / 1024} KiB (gzip)`);
  if (used > limit) failed = true;
}
process.exit(failed ? 1 : 0);
bash
$ npm run build
$ node scripts/budget.mjs

示例中的数字只是起点,不是推荐值。合理的做法是先测出当前体积,在此基础上留一点余量作为预算,之后只允许经过讨论的上调。

让预算可以执行

  1. 预算跟着页面类型走:文章页和需要编辑器的页面,承载的功能不同,不应共用一个数字。
  2. 超出时给出明细:只报告“超了 8 KB”没有用,要能看到是哪个入口、哪个依赖变大了。
  3. 上调需要理由:允许上调预算,但要写在提交说明里,让这个决定可以被追溯。
  4. 定期回看:每过一段时间检查一次余量,体积下降时顺手把预算收紧。

预算真正约束的不是代码,而是“这点体积可以接受”这句话。

预算解决不了的问题

体积预算无法发现长任务阻塞主线程、布局抖动或者首屏图片没有设置尺寸这类问题,它们需要 Lighthouse 这样的实验室工具和线上数据来发现。预算只是最便宜的一道防线:它不保证页面一定快,但能保证页面不会在无人察觉的情况下慢下去。这也是我在静态优先的架构里尽量把交互写成渐进增强的原因之一。

参考:web.dev · Performance budgets 101 · web.dev · Web Vitals · web.dev · Interaction to Next Paint

读到这里,
感谢你留下这一小段时间。

性能CICore Web Vitals

发表评论…

公开讨论尚未连接

关于整篇文章,也关于让你停下来的那句话。
公开评论基于 GitHub Discussions;接入完成后才可发表。

正在加载评论…
发表评论
支持代码块与表情 · 评论公开可见0 / 6000

正在确认你的身份…

放大图片
搜索

输入关键词搜索标题、正文和标签。