来源:devto:articles · 原作者 SwiftKit · 原文
系统转载,非作者本人发布。
PageSpeed Insights 非常适合单个 URL。但面对 300 个产品页,或者“每次发布后所有落地页”这样的场景,你需要的是在脚本里运行 Lighthouse。好消息是:Lighthouse 是一个 npm 包,你不需要 API 密钥就能自己运行它。
最小脚本
import lighthouse from 'lighthouse';
import * as chromeLauncher from 'chrome-launcher';
const chrome = await chromeLauncher.launch({
chromeFlags: ['--headless=new', '--no-sandbox', '--disable-dev-shm-usage'],
});
try {
const { lhr, report } = await lighthouse('https://www.wikipedia.org', {
port: chrome.port,
output: ['json', 'html'],
onlyCategories: ['performance', 'accessibility', 'best-practices', 'seo'],
logLevel: 'error',
});
console.log(Math.round(lhr.categories.performance.score * 100));
// report[1] is the full HTML report: save it, it's what people actually read.
} finally {
await chrome.kill();
}
对于桌面预设,将 Lighthouse 自身的配置作为第三个参数传入:
const desktop = (await import('lighthouse/core/config/desktop-config.js')).default;
await lighthouse(url, flags, desktop);
我遇到的两个小坑:
- 在 chrome-launcher 1.x 中,
kill()不保证返回 promise,所以chrome.kill().catch(...)可能会抛错。改用 try/catch 包裹它。 - 如果你在 Docker 中使用 Playwright 镜像,将 chrome-launcher 指向 Playwright 的浏览器:
chromePath: chromium.executablePath()。
从结果中保留什么
lhr 对象非常庞大。对于批量表格,我每页保留以下内容:
const score = (c) => Math.round(lhr.categories[c].score * 100);
const ms = (id) => Math.round(lhr.audits[id].numericValue);
const row = {
performance: score('performance'),
seo: score('seo'),
lcpMs: ms('largest-contentful-paint'),
tbtMs: ms('total-blocking-time'),
cls: lhr.audits['cumulative-layout-shift'].numericValue,
// Top fixes, ranked by time saved:
opportunities: Object.values(lhr.audits)
.filter((a) => a.details?.type === 'opportunity' && a.details.overallSavingsMs >= 100)
.sort((a, b) => b.details.overallSavingsMs - a.details.overallSavingsMs)
.slice(0, 8)
.map((a) => ({ title: a.title, savingsMs: Math.round(a.details.overallSavingsMs) })),
};
在读取任何内容之前,也要检查 lhr.runtimeError。加载失败的页面仍会返回 lhr,只是分数是无效的。
一次只运行一个审计
同时审计 10 个页面很诱人。但别这样做:Lighthouse 会模拟慢速设备并测量 CPU 工作量,因此在同一台机器上并行审计会互相拖慢,并把每个性能分数都拉低。请逐个运行,每次都用全新的 Chrome。这样虽然更慢,但数字才有意义。
分数为何会波动
我在自己的笔记本和一个 2 GB 云容器上运行了相同的页面:
| 页面 | 笔记本(移动端) | 云容器(移动端) |
|---|---|---|
| wikipedia.org 性能 | 98 | 92 |
| wikipedia.org LCP | 1,379 ms | 1,497 ms |
一个更重的营销网站在云端的性能得分仅为 25,LCP 超过 9 秒。同样的代码,同一天。
实验室分数取决于机器的 CPU,而移动端预设会在此基础上叠加 CPU 降速。因此:
- 在同一台机器、同一次运行中比较页面,不要跨工具比较。
- PageSpeed Insights 在 Google 拥有足够流量时也会显示真实用户数据(CrUX)。这是一种不同的测量,而且往往对 SEO 更关键。
- 追踪趋势(相同页面、相同配置,每周一次),而不是单个数字。
打包好的版本
如果你不想自己运行 Chrome 集群,我把它放到了 Apify 上,名为 Lighthouse Audit:粘贴 URL,选择移动端、桌面端或两者,即可获得分数、Core Web Vitals、最重要的修复建议、失败的 SEO/无障碍检查,以及每个页面的完整 HTML 报告。出于上述原因,它一次只运行一个审计。失败的页面不收费。
你们目前是如何跨多个页面追踪性能的?我很好奇大家是使用 CrUX 数据、实验室运行,还是两者都用。
在 AI 辅助下撰写;代码和数字在发布前均已测试。