跳到主要内容

Lighthouse 性能审计

问题

什么是 Lighthouse?如何使用 Lighthouse 进行性能审计?如何在 CI/CD 中集成 Lighthouse?

面试速答版

什么是 Lighthouse? Google 开源的网页质量审计工具,是前端性能体检的事实标准:

  • 常用核心类别包括 PerformanceAccessibilityBest PracticesSEO。类别与审计项会随 Lighthouse 版本调整,PWA 不应再背成固定的“第五个顶级评分”。
  • Performance 评分使用实验室数据:网络、CPU、视口和缓存条件由运行配置决定,并不固定等于“Slow 4G + 4x”,也不等于真实用户数据(RUM)。
  • 90+ 是绿色优秀、50-89 橙色待改进、0-49 红色差。Performance 是最常被关注的,权重最高。

如何使用 Lighthouse 进行性能审计? 四种使用方式按场景选:

  • Chrome DevTools Lighthouse 面板:最快,F12 → Lighthouse → 跑一次拿报告,本地开发常用。
  • PageSpeed Insights 网页版:拿真实用户的 CrUX 数据 + Lighthouse 实验室数据,更接近线上情况。
  • CLIlighthouse https://xxx --output html 适合脚本化。
  • Node.js API:嵌到自动化流程里。
  • 看报告重点:官方评分页当前仍展示 Lighthouse 10 的 TBT 30% + LCP 25% + CLS 25% + FCP 10% + SI 10% 模型,但权重会随版本变化。不要只追总分,要看具体指标、Insights 和 trace 证据。

如何在 CI/CD 中集成 Lighthouse?Lighthouse CI@lhci/cli)做性能门禁:

  • 在 GitHub Actions/GitLab CI 里跑 lhci autorun,每次 PR 自动跑 Lighthouse 几次取中位数。
  • lighthouserc.js 里配 assertions——比如 'first-contentful-paint': ['error', { maxNumericValue: 2000 }],超阈值直接 PR fail。
  • 报告上传到 LHCI Server 或 GitHub Pages 留档,能看历史趋势。
  • 配合性能预算用——例如中端移动设备、冷缓存和模拟 4G 的关键营销页,可以先以首屏压缩后 JS 200KB、LCP 2.5s 作为初始预算,再用真实用户基线校准,而不是把该数字套给所有页面。

答案

Lighthouse 是 Google 开源的网页质量审计工具,用于测量和改进网页的性能、可访问性、最佳实践、SEO 等维度。它适合可重复的实验室审计和 CI 回归,不是线上 RUM 的替代品。


Lighthouse 简介

审计维度

类别和报告结构是版本化的

Lighthouse 的默认类别、审计 ID、Insights 和评分权重都可能变化。CI 应锁定 Lighthouse/LHCI 版本并记录版本号;升级时先在基准页面上比较报告差异,再更新门禁。

评分计算

分数范围评级颜色
90-100优秀🟢 绿色
50-89需改进🟠 橙色
0-49🔴 红色

Performance 评分权重

下表是官方评分文档当前展示的 Lighthouse 10 权重,用于理解分数构成,不应假设未来版本永远不变。

指标权重说明
TBT (Total Blocking Time)30%阻塞时间
LCP (Largest Contentful Paint)25%最大内容绘制
CLS (Cumulative Layout Shift)25%累积布局偏移
FCP (First Contentful Paint)10%首次内容绘制
SI (Speed Index)10%速度指数

使用方式

1. Chrome DevTools

1. 打开 Chrome DevTools (F12)
2. 切换到 Lighthouse 面板
3. 选择审计类别和设备类型
4. 点击 "Analyze page load"

Lighthouse 适合快速体检。需要定位主线程、网络瀑布、LCP/INP 根因时,应转到 Performance 面板录制真实用户路径,并查看其中的 Insights;新版 Lighthouse 的性能建议也逐步采用相同的 Insights 模型。

2. Chrome 扩展(可选)

1. 安装 Lighthouse Chrome 扩展
2. 点击扩展图标
3. 选择审计选项
4. 生成报告

3. 命令行工具

npm install -g lighthouse
# 基本使用
lighthouse https://example.com

# 指定输出格式
lighthouse https://example.com --output html --output-path ./report.html

# 指定设备
lighthouse https://example.com --preset=desktop

# 只审计性能
lighthouse https://example.com --only-categories=performance

# JSON 输出
lighthouse https://example.com --output json --output-path ./report.json

4. Node.js API

import lighthouse from 'lighthouse';
import chromeLauncher from 'chrome-launcher';

async function runLighthouse(url: string) {
// 启动 Chrome
const chrome = await chromeLauncher.launch({ chromeFlags: ['--headless'] });

// 运行 Lighthouse
const options = {
logLevel: 'info' as const,
output: 'json' as const,
onlyCategories: ['performance'],
port: chrome.port,
};

const result = await lighthouse(url, options);

// 关闭 Chrome
await chrome.kill();

return result;
}

// 使用
const result = await runLighthouse('https://example.com');
console.log('Performance Score:', result?.lhr.categories.performance.score);

核心性能指标

Performance 指标详解

指标全称良好需改进
FCPFirst Contentful Paint<1.8s1.8-3s>3s
LCPLargest Contentful Paint<2.5s2.5-4s>4s
TBTTotal Blocking Time<200ms200-600ms>600ms
CLSCumulative Layout Shift<0.10.1-0.25>0.25
SISpeed Index<3.4s3.4-5.8s>5.8s

指标含义

// FCP - 首次内容绘制
// 浏览器首次渲染任何文本、图片、非空白 canvas 或 SVG 的时间

// LCP - 最大内容绘制
// 视口内最大的图片、视频或文本块完成渲染的时间
// 常见 LCP 元素:<img>、<video>、背景图、大块文本

// TBT - 总阻塞时间(实验室指标)
// 加载期从 FCP 到达到可交互状态之间,长任务超过 50ms 部分的总和
// 长任务 = 执行时间 > 50ms 的任务

// CLS - 累积布局偏移
// 衡量视觉稳定性,页面加载期间意外布局移动的总和

// SI - 速度指数
// 页面内容可见的填充速度,越低越好

从 Lighthouse Insights 定位问题

新版报告不应只按旧的 Opportunities 列表逐项“刷分”。更有效的做法是把 Insight 当作调查入口,再回到 Performance trace 验证:

Insight 方向回答的问题下一步证据
LCP breakdown/discoveryLCP 慢在 TTFB、发现、下载还是渲染?Network 瀑布、LCP 元素、优先级
Render-blocking requests哪些资源阻塞首屏?请求开始时间、CSS 使用率、依赖链
Third parties哪些第三方消耗下载和主线程?域名、CPU 时间、请求阻塞实验
Legacy/duplicated JavaScript是否下发重复依赖或不必要的旧语法?bundle 分析、source map、浏览器目标
Layout shifts哪些元素造成意外偏移?Layout Shift cluster 与 affected nodes
INP breakdown交互慢在输入、处理还是呈现?录制具体交互、事件回调和渲染阶段
诊断原则

一条 Insight 只是“可能有收益”的假设。先看它是否位于关键路径,再做一次小改动,用相同环境重复测试并检查现场数据,避免为了消除报告提示反而增加 preload、缓存复杂度或客户端代码。


常见优化建议

1. 减少渲染阻塞资源

<!-- ❌ 阻塞渲染 -->
<link rel="stylesheet" href="styles.css">
<script src="app.js"></script>

<!-- ✅ 优化后 -->
<!-- 关键 CSS 内联 -->
<style>/* 关键样式 */</style>

<!-- 非关键 CSS 延迟加载 -->
<link rel="preload" href="non-critical.css" as="style" onload="this.rel='stylesheet'">

<!-- JS 异步加载 -->
<script src="app.js" defer></script>

2. 减少未使用的 JavaScript

// 使用代码分割
const LazyComponent = lazy(() => import('./LazyComponent'));

// 使用 Tree Shaking
// 只导入需要的函数
import { debounce } from 'lodash-es';
// 而不是
import _ from 'lodash';

3. 服务静态资源使用高效缓存策略

# nginx 配置
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}

4. 延迟加载屏幕外图片

<img src="image.jpg" loading="lazy" alt="描述">

5. 避免巨大的网络负载

// 使用现代图片格式
<picture>
<source srcset="image.avif" type="image/avif">
<source srcset="image.webp" type="image/webp">
<img src="image.jpg" alt="描述">
</picture>

// 压缩资源
// Brotli 压缩(比 gzip 小 15-20%)

CI/CD 集成

GitHub Actions

# .github/workflows/lighthouse.yml
name: Lighthouse CI

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
lighthouse:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'

- name: Install dependencies
run: npm ci

- name: Build
run: npm run build

- name: Start server
run: npm run preview &

- name: Wait for server
run: sleep 10

- name: Run Lighthouse
uses: treosh/lighthouse-ci-action@v11
with:
urls: |
http://localhost:3000
http://localhost:3000/about
uploadArtifacts: true
temporaryPublicStorage: true
configPath: './lighthouserc.json'

Lighthouse CI 配置

下面是一组适合“中端移动设备、冷缓存、关键公开页面”的初始示例。真实项目应先跑基线,再根据页面类型调整;登录页、后台和营销页不应共用一套阈值。

lighthouserc.json
{
"ci": {
"collect": {
"url": ["http://localhost:3000"],
"numberOfRuns": 3
},
"assert": {
"assertions": {
"categories:performance": ["warn", { "minScore": 0.9 }],
"categories:accessibility": ["warn", { "minScore": 0.9 }],
"categories:best-practices": ["warn", { "minScore": 0.9 }],
"categories:seo": ["warn", { "minScore": 0.9 }],
"first-contentful-paint": ["error", { "maxNumericValue": 2000 }],
"largest-contentful-paint": ["error", { "maxNumericValue": 2500 }],
"cumulative-layout-shift": ["error", { "maxNumericValue": 0.1 }],
"total-blocking-time": ["error", { "maxNumericValue": 300 }]
}
},
"upload": {
"target": "temporary-public-storage"
}
}
}

总分受多个指标和运行噪声影响,更适合作为趋势或 warning;稳定、可解释的单项指标和资源预算才适合逐步升级为 error。temporary-public-storage 可能公开报告,不要用于包含登录态、内部 URL 或敏感页面的 CI。

自动化脚本

// lighthouse-ci.ts
import lighthouse from 'lighthouse';
import chromeLauncher from 'chrome-launcher';

interface AuditResult {
url: string;
scores: Record<string, number>;
passed: boolean;
}

async function auditUrl(url: string): Promise<AuditResult> {
const chrome = await chromeLauncher.launch({
chromeFlags: ['--headless', '--no-sandbox']
});

const result = await lighthouse(url, {
port: chrome.port,
output: 'json',
});

await chrome.kill();

const lhr = result?.lhr;
if (!lhr) throw new Error('Lighthouse failed');

const scores: Record<string, number> = {};
Object.entries(lhr.categories).forEach(([key, category]) => {
scores[key] = Math.round((category.score || 0) * 100);
});

// 检查是否通过阈值
const passed = scores.performance >= 90 &&
scores.accessibility >= 90 &&
scores['best-practices'] >= 90;

return { url, scores, passed };
}

async function runAudit() {
const urls = [
'http://localhost:3000',
'http://localhost:3000/about',
];

const results = await Promise.all(urls.map(auditUrl));

console.table(results.map(r => ({
URL: r.url,
Performance: r.scores.performance,
Accessibility: r.scores.accessibility,
'Best Practices': r.scores['best-practices'],
SEO: r.scores.seo,
Passed: r.passed ? '✅' : '❌',
})));

const allPassed = results.every(r => r.passed);
process.exit(allPassed ? 0 : 1);
}

runAudit();

性能监控集成

PageSpeed Insights API

async function getPageSpeedInsights(url: string) {
const apiKey = process.env.PSI_API_KEY;
const endpoint = `https://www.googleapis.com/pagespeedonline/v5/runPagespeed`;

const params = new URLSearchParams({
url,
key: apiKey || '',
strategy: 'mobile',
category: 'PERFORMANCE',
category: 'ACCESSIBILITY',
});

const response = await fetch(`${endpoint}?${params}`);
const data = await response.json();

return {
performance: data.lighthouseResult.categories.performance.score * 100,
fcp: data.lighthouseResult.audits['first-contentful-paint'].displayValue,
lcp: data.lighthouseResult.audits['largest-contentful-paint'].displayValue,
cls: data.lighthouseResult.audits['cumulative-layout-shift'].displayValue,
};
}

定时监控

// 使用 cron 定时运行
import cron from 'node-cron';

cron.schedule('0 */6 * * *', async () => {
// 每 6 小时运行一次
const result = await auditUrl('https://mysite.com');

if (result.scores.performance < 80) {
// 发送告警
await sendAlert({
type: 'performance_degradation',
score: result.scores.performance,
});
}

// 保存历史数据
await saveToDatabase(result);
});

报告分析

常见问题诊断

问题可能原因解决方案
LCP 高图片未优化WebP/懒加载/preload
FCP 高渲染阻塞资源async/defer/内联关键CSS
TBT 高长任务代码分割/Web Worker
CLS 高图片无尺寸设置 width/height
低分第三方脚本延迟加载/async

追踪优化效果

// 记录优化前后的分数变化
interface PerformanceRecord {
date: Date;
scores: {
performance: number;
accessibility: number;
bestPractices: number;
seo: number;
};
metrics: {
fcp: number;
lcp: number;
tbt: number;
cls: number;
};
}

// 生成趋势图
function generateTrendReport(records: PerformanceRecord[]) {
const trend = records.map(r => ({
date: r.date.toISOString().split('T')[0],
performance: r.scores.performance,
lcp: r.metrics.lcp,
}));

console.table(trend);
}

常见面试问题

Q1: Lighthouse 评估哪些维度?

答案

维度说明核心指标
Performance页面性能FCP、LCP、TBT、CLS、SI
Accessibility可访问性颜色对比度、ARIA 标签
Best Practices最佳实践HTTPS、无控制台错误
SEO搜索优化meta 标签、语义化

类别和审计项会随版本调整。PWA 的 manifest、离线和可安装能力仍然重要,但不应再把 PWA 背成所有当前版本固定存在的第五个顶级评分。

Q2: 如何提高 Lighthouse Performance 分数?

答案

Q3: Lighthouse 分数不稳定怎么办?

答案

  1. 多次运行并使用中位运行结果
# 在 lighthouserc.json 中设置 collect.numberOfRuns,例如 5
lhci autorun
  1. 使用稳定的测试环境
// 使用 Docker 隔离环境
// 关闭浏览器扩展
// 使用有线网络
  1. 排除网络因素
// 使用 throttling 模拟一致的网络条件
const options = {
throttling: {
cpuSlowdownMultiplier: 4,
downloadThroughputKbps: 1638,
uploadThroughputKbps: 675,
rttMs: 150,
},
};
  1. 锁定版本和页面状态:锁定 Chrome、Lighthouse、Node、字体、测试数据和登录态;避免 A/B 实验、广告和后台任务污染结果。

  2. 不要只看总分:同时保存 LCP/TBT/CLS、请求数量和传输体积,使用绝对阈值加相对回归,避免一次波动误伤 PR。

Q4: 如何在 CI/CD 中使用 Lighthouse?

答案

# GitHub Actions 示例
- name: Lighthouse CI
uses: treosh/lighthouse-ci-action@v11
with:
urls: http://localhost:3000
configPath: ./lighthouserc.json

# 阈值检查
assertions:
categories:performance: ["error", { "minScore": 0.9 }]
largest-contentful-paint: ["error", { "maxNumericValue": 2500 }]

Q5: Lighthouse 和真实用户数据的区别?

答案

特性Lighthouse (Lab Data)RUM (Field Data)
数据来源模拟环境真实用户
一致性取决于用户环境
实时性即时需要收集
网络条件固定模拟实际网络
用途开发调试监控真实性能

最佳实践:两者结合使用

  • Lighthouse:开发阶段快速反馈
  • RUM (Core Web Vitals):监控真实用户体验

相关链接