名称: perf-lighthouse 描述: “通过CLI或Node API本地运行Lighthouse审计,解析和解释报告,设置性能预算。当测量网站性能、理解Lighthouse分数、设置预算或将审计集成到CI时使用。触发词:lighthouse、运行lighthouse、lighthouse分数、性能审计、性能预算。”
Lighthouse审计
CLI快速入门
# 安装
npm install -g lighthouse
# 基本审计
lighthouse https://example.com
# 仅移动性能(更快)
lighthouse https://example.com --preset=perf --form-factor=mobile
# 输出JSON用于解析
lighthouse https://example.com --output=json --output-path=./report.json
# 输出HTML报告
lighthouse https://example.com --output=html --output-path=./report.html
常见标志
--preset=perf # 仅性能(跳过可访问性、SEO等)
--form-factor=mobile # 移动设备模拟(默认)
--form-factor=desktop # 桌面设备
--throttling-method=devtools # 更准确的节流
--only-categories=performance,accessibility # 特定类别
--chrome-flags="--headless" # 无头Chrome
性能预算
创建 budget.json:
[
{
"resourceSizes": [
{ "resourceType": "script", "budget": 200 },
{ "resourceType": "image", "budget": 300 },
{ "resourceType": "stylesheet", "budget": 50 },
{ "resourceType": "total", "budget": 500 }
],
"resourceCounts": [
{ "resourceType": "third-party", "budget": 5 }
],
"timings": [
{ "metric": "interactive", "budget": 3000 },
{ "metric": "first-contentful-paint", "budget": 1500 },
{ "metric": "largest-contentful-paint", "budget": 2500 }
]
}
]
使用预算运行:
lighthouse https://example.com --budget-path=./budget.json
Node API
import lighthouse from 'lighthouse';
import * as chromeLauncher from 'chrome-launcher';
async function runAudit(url) {
const chrome = await chromeLauncher.launch({ chromeFlags: ['--headless'] });
const result = await lighthouse(url, {
port: chrome.port,
onlyCategories: ['performance'],
formFactor: 'mobile',
throttling: {
cpuSlowdownMultiplier: 4,
},
});
await chrome.kill();
const { performance } = result.lhr.categories;
const { 'largest-contentful-paint': lcp } = result.lhr.audits;
return {
score: Math.round(performance.score * 100),
lcp: lcp.numericValue,
};
}
GitHub Actions
# .github/workflows/lighthouse.yml
名称: Lighthouse
触发条件:
pull_request:
push:
分支: [main]
任务:
lighthouse:
运行环境: ubuntu-latest
步骤:
- 使用: actions/checkout@v4
- 名称: 构建站点
运行: npm ci && npm run build
- 名称: 运行Lighthouse
使用: treosh/lighthouse-ci-action@v11
带参数:
urls: |
http://localhost:3000
http://localhost:3000/about
budgetPath: ./budget.json
uploadArtifacts: true
temporaryPublicStorage: true
环境变量:
LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }}
Lighthouse CI (LHCI)
用于完整CI集成和历史跟踪:
# 安装
npm install -g @lhci/cli
# 初始化配置
lhci wizard
创建 lighthouserc.js:
module.exports = {
ci: {
collect: {
url: ['http://localhost:3000/', 'http://localhost:3000/about'],
startServerCommand: 'npm run start',
numberOfRuns: 3,
},
assert: {
assertions: {
'categories:performance': ['error', { minScore: 0.9 }],
'categories:accessibility': ['warn', { minScore: 0.9 }],
'first-contentful-paint': ['error', { maxNumericValue: 1500 }],
'largest-contentful-paint': ['error', { maxNumericValue: 2500 }],
'cumulative-layout-shift': ['error', { maxNumericValue: 0.1 }],
},
},
upload: {
target: 'temporary-public-storage', // 或 'lhci' 用于自托管
},
},
};
运行:
lhci autorun
解析JSON报告
import fs from 'fs';
const report = JSON.parse(fs.readFileSync('./report.json'));
// 总体分数(0-1,乘以100得到百分比)
const scores = {
performance: report.categories.performance.score,
accessibility: report.categories.accessibility.score,
seo: report.categories.seo.score,
};
// 核心Web指标
const vitals = {
lcp: report.audits['largest-contentful-paint'].numericValue,
cls: report.audits['cumulative-layout-shift'].numericValue,
fcp: report.audits['first-contentful-paint'].numericValue,
tbt: report.audits['total-blocking-time'].numericValue,
};
// 失败的审计
const failed = Object.values(report.audits)
.filter(a => a.score !== null && a.score < 0.9)
.map(a => ({ id: a.id, score: a.score, title: a.title }));
比较构建
# 保存基线
lighthouse https://prod.example.com --output=json --output-path=baseline.json
# 在PR上运行
lighthouse https://preview.example.com --output=json --output-path=pr.json
# 比较(自定义脚本)
node compare-reports.js baseline.json pr.json
简单比较脚本:
const baseline = JSON.parse(fs.readFileSync(process.argv[2]));
const pr = JSON.parse(fs.readFileSync(process.argv[3]));
const metrics = ['largest-contentful-paint', 'cumulative-layout-shift', 'total-blocking-time'];
metrics.forEach(metric => {
const base = baseline.audits[metric].numericValue;
const current = pr.audits[metric].numericValue;
const diff = ((current - base) / base * 100).toFixed(1);
const emoji = current <= base ? '✅' : '❌';
console.log(`${emoji} ${metric}: ${diff}% (${base.toFixed(0)} → ${current.toFixed(0)})`);
});
故障排除
| 问题 | 解决方案 |
|---|---|
| 分数不一致 | 运行多次(--number-of-runs=3),使用中位数 |
| Chrome未找到 | 设置 CHROME_PATH 环境变量 |
| 超时 | 使用 --max-wait-for-load=60000 增加超时时间 |
| 需要认证 | 使用 --extra-headers 或 puppeteer 脚本 |