514 lines
10 KiB
Markdown
514 lines
10 KiB
Markdown
# Lighthouse CI使用指南
|
||
|
||
## 概述
|
||
|
||
Lighthouse CI是一个用于自动化性能测试的工具,它可以在CI/CD流程中运行Lighthouse审计,跟踪性能指标变化,并设置性能预算。
|
||
|
||
## 安装
|
||
|
||
```bash
|
||
npm install --save-dev @lhci/cli
|
||
```
|
||
|
||
## 配置
|
||
|
||
### 配置文件
|
||
|
||
项目根目录下的`lighthouserc.json`文件包含所有配置:
|
||
|
||
```json
|
||
{
|
||
"ci": {
|
||
"collect": {
|
||
"numberOfRuns": 3,
|
||
"startServerCommand": "npm run start",
|
||
"startServerReadyPattern": "Local:",
|
||
"url": [
|
||
"http://localhost:3000/",
|
||
"http://localhost:3000/about",
|
||
"http://localhost:3000/services"
|
||
],
|
||
"settings": {
|
||
"preset": "desktop",
|
||
"onlyCategories": [
|
||
"performance",
|
||
"accessibility",
|
||
"best-practices",
|
||
"seo"
|
||
]
|
||
}
|
||
},
|
||
"assert": {
|
||
"assertions": {
|
||
"categories:performance": ["error", {"minScore": 0.9}],
|
||
"categories:accessibility": ["error", {"minScore": 0.9}],
|
||
"categories:best-practices": ["error", {"minScore": 0.9}],
|
||
"categories:seo": ["error", {"minScore": 0.9}]
|
||
}
|
||
},
|
||
"upload": {
|
||
"target": "temporary-public-storage"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 配置说明
|
||
|
||
#### collect配置
|
||
|
||
- **numberOfRuns**: 每个URL运行的次数(默认3次)
|
||
- **startServerCommand**: 启动服务器的命令
|
||
- **startServerReadyPattern**: 服务器就绪的匹配模式
|
||
- **url**: 要测试的URL列表
|
||
- **settings**: Lighthouse设置
|
||
- **preset**: 测试预设(desktop/mobile)
|
||
- **onlyCategories**: 只测试指定类别
|
||
|
||
#### assert配置
|
||
|
||
- **assertions**: 性能断言
|
||
- **categories:performance**: 性能分数最低0.9
|
||
- **categories:accessibility**: 可访问性分数最低0.9
|
||
- **categories:best-practices**: 最佳实践分数最低0.9
|
||
- **categories:seo**: SEO分数最低0.9
|
||
|
||
#### upload配置
|
||
|
||
- **target**: 上传目标
|
||
- **temporary-public-storage**: 临时公共存储
|
||
- **lhci**: Lighthouse CI服务器
|
||
- **filesystem**: 本地文件系统
|
||
|
||
## 使用方法
|
||
|
||
### 本地运行
|
||
|
||
#### 运行完整测试
|
||
|
||
```bash
|
||
npm run lighthouse
|
||
```
|
||
|
||
这将执行以下步骤:
|
||
1. 启动开发服务器
|
||
2. 收集性能数据
|
||
3. 运行断言检查
|
||
4. 上传结果
|
||
|
||
#### 分步运行
|
||
|
||
```bash
|
||
# 1. 收集性能数据
|
||
npm run lighthouse:collect
|
||
|
||
# 2. 运行断言检查
|
||
npm run lighthouse:assert
|
||
|
||
# 3. 上传结果
|
||
npm run lighthouse:upload
|
||
```
|
||
|
||
#### 指定设备类型
|
||
|
||
```bash
|
||
# 桌面端测试
|
||
npm run lighthouse:desktop
|
||
|
||
# 移动端测试
|
||
npm run lighthouse:mobile
|
||
```
|
||
|
||
### CI/CD集成
|
||
|
||
#### GitHub Actions
|
||
|
||
创建`.github/workflows/lighthouse.yml`:
|
||
|
||
```yaml
|
||
name: Lighthouse CI
|
||
|
||
on:
|
||
push:
|
||
branches: [main]
|
||
pull_request:
|
||
branches: [main]
|
||
|
||
jobs:
|
||
lighthouse:
|
||
runs-on: ubuntu-latest
|
||
|
||
steps:
|
||
- uses: actions/checkout@v3
|
||
|
||
- name: Setup Node.js
|
||
uses: actions/setup-node@v3
|
||
with:
|
||
node-version: '18'
|
||
cache: 'npm'
|
||
|
||
- name: Install dependencies
|
||
run: npm ci
|
||
|
||
- name: Build application
|
||
run: npm run build
|
||
|
||
- name: Run Lighthouse CI
|
||
run: npm run lighthouse
|
||
env:
|
||
LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }}
|
||
|
||
- name: Upload Lighthouse results
|
||
uses: actions/upload-artifact@v3
|
||
if: always()
|
||
with:
|
||
name: lighthouse-results
|
||
path: lighthouse-reports
|
||
```
|
||
|
||
#### GitLab CI
|
||
|
||
创建`.gitlab-ci.yml`:
|
||
|
||
```yaml
|
||
lighthouse:
|
||
stage: test
|
||
image: node:18
|
||
script:
|
||
- npm ci
|
||
- npm run build
|
||
- npm run lighthouse
|
||
artifacts:
|
||
paths:
|
||
- lighthouse-reports/
|
||
expire_in: 1 week
|
||
only:
|
||
- main
|
||
- merge_requests
|
||
```
|
||
|
||
## 性能指标
|
||
|
||
### Core Web Vitals
|
||
|
||
Lighthouse CI重点监控以下Core Web Vitals指标:
|
||
|
||
| 指标 | 名称 | 目标值 | 说明 |
|
||
|------|------|--------|------|
|
||
| **LCP** | Largest Contentful Paint | < 2.5s | 最大内容绘制时间 |
|
||
| **FID** | First Input Delay | < 100ms | 首次输入延迟 |
|
||
| **CLS** | Cumulative Layout Shift | < 0.1 | 累积布局偏移 |
|
||
|
||
### 其他重要指标
|
||
|
||
| 指标 | 名称 | 目标值 | 说明 |
|
||
|------|------|--------|------|
|
||
| **FCP** | First Contentful Paint | < 1.8s | 首次内容绘制时间 |
|
||
| **SI** | Speed Index | < 3.4s | 速度指数 |
|
||
| **TBT** | Total Blocking Time | < 200ms | 总阻塞时间 |
|
||
|
||
### 性能预算
|
||
|
||
在`lighthouserc.json`中设置性能预算:
|
||
|
||
```json
|
||
{
|
||
"ci": {
|
||
"assert": {
|
||
"assertions": {
|
||
"first-contentful-paint": ["error", {"maxNumericValue": 2000}],
|
||
"largest-contentful-paint": ["error", {"maxNumericValue": 3000}],
|
||
"cumulative-layout-shift": ["error", {"maxNumericValue": 0.1}],
|
||
"total-blocking-time": ["error", {"maxNumericValue": 300}],
|
||
"speed-index": ["error", {"maxNumericValue": 3000}]
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 性能优化建议
|
||
|
||
### 1. 减少LCP时间
|
||
|
||
**问题**:LCP > 2.5s
|
||
|
||
**解决方案**:
|
||
```typescript
|
||
// 优化图片加载
|
||
<img
|
||
src="/hero.jpg"
|
||
alt="Hero image"
|
||
loading="eager"
|
||
fetchpriority="high"
|
||
/>
|
||
|
||
// 使用Next.js Image组件
|
||
<Image
|
||
src="/hero.jpg"
|
||
alt="Hero image"
|
||
priority
|
||
width={1920}
|
||
height={1080}
|
||
/>
|
||
```
|
||
|
||
### 2. 减少CLS
|
||
|
||
**问题**:CLS > 0.1
|
||
|
||
**解决方案**:
|
||
```typescript
|
||
// 为图片预留空间
|
||
<img
|
||
src="/image.jpg"
|
||
alt="Description"
|
||
width={800}
|
||
height={600}
|
||
style={{ aspectRatio: '800/600' }}
|
||
/>
|
||
|
||
// 避免内容跳动
|
||
<div style={{ minHeight: '200px' }}>
|
||
{loading ? <Skeleton /> : <Content />}
|
||
</div>
|
||
```
|
||
|
||
### 3. 减少TBT
|
||
|
||
**问题**:TBT > 200ms
|
||
|
||
**解决方案**:
|
||
```typescript
|
||
// 代码分割
|
||
const HeavyComponent = dynamic(() => import('./HeavyComponent'), {
|
||
loading: () => <Loading />,
|
||
});
|
||
|
||
// 延迟加载非关键脚本
|
||
useEffect(() => {
|
||
import('heavy-library').then(module => {
|
||
// 使用库
|
||
});
|
||
}, []);
|
||
```
|
||
|
||
### 4. 优化FCP
|
||
|
||
**问题**:FCP > 1.8s
|
||
|
||
**解决方案**:
|
||
```typescript
|
||
// 内联关键CSS
|
||
<style dangerouslySetInnerHTML={{__html: criticalCSS}} />
|
||
|
||
// 预加载关键资源
|
||
<link rel="preload" href="/font.woff2" as="font" type="font/woff2" crossOrigin="anonymous" />
|
||
|
||
// 减少阻塞资源
|
||
<script src="/script.js" defer></script>
|
||
```
|
||
|
||
## 查看报告
|
||
|
||
### 本地报告
|
||
|
||
运行测试后,报告保存在`lighthouse-reports/`目录:
|
||
|
||
```bash
|
||
# 打开最新报告
|
||
open lighthouse-reports/lhci-*.html
|
||
```
|
||
|
||
### 在线报告
|
||
|
||
如果使用临时公共存储,测试后会输出报告URL:
|
||
|
||
```
|
||
✅ Report: https://storage.googleapis.com/lighthouse-infrastructure.appspot.com/reports/xxxxx.html
|
||
```
|
||
|
||
### Lighthouse CI服务器
|
||
|
||
配置Lighthouse CI服务器后,可以查看历史趋势:
|
||
|
||
```json
|
||
{
|
||
"ci": {
|
||
"upload": {
|
||
"target": "lhci",
|
||
"serverBaseUrl": "https://your-lhci-server.com",
|
||
"token": "your-upload-token"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 性能监控仪表板
|
||
|
||
### 创建自定义仪表板
|
||
|
||
```typescript
|
||
// scripts/performance-dashboard.ts
|
||
|
||
import fs from 'fs';
|
||
import path from 'path';
|
||
|
||
interface LighthouseResult {
|
||
url: string;
|
||
performance: number;
|
||
accessibility: number;
|
||
'best-practices': number;
|
||
seo: number;
|
||
lcp: number;
|
||
fcp: number;
|
||
cls: number;
|
||
tbt: number;
|
||
}
|
||
|
||
function generateDashboard(results: LighthouseResult[]) {
|
||
const avgPerformance = results.reduce((sum, r) => sum + r.performance, 0) / results.length;
|
||
const avgAccessibility = results.reduce((sum, r) => sum + r.accessibility, 0) / results.length;
|
||
|
||
console.log(`
|
||
## 性能监控仪表板
|
||
|
||
### 平均分数
|
||
- 性能: ${(avgPerformance * 100).toFixed(0)}/100
|
||
- 可访问性: ${(avgAccessibility * 100).toFixed(0)}/100
|
||
|
||
### 各页面性能
|
||
${results.map(r => `
|
||
#### ${r.url}
|
||
- 性能: ${(r.performance * 100).toFixed(0)}
|
||
- LCP: ${r.lcp}ms
|
||
- FCP: ${r.fcp}ms
|
||
- CLS: ${r.cls}
|
||
`).join('\n')}
|
||
`);
|
||
}
|
||
|
||
// 读取结果并生成仪表板
|
||
const resultsPath = path.join(process.cwd(), 'lighthouse-reports', 'manifest.json');
|
||
const results = JSON.parse(fs.readFileSync(resultsPath, 'utf-8'));
|
||
generateDashboard(results);
|
||
```
|
||
|
||
## 故障排查
|
||
|
||
### 问题1:服务器启动失败
|
||
|
||
**症状**:`Error: Server did not start in time`
|
||
|
||
**解决方案**:
|
||
```json
|
||
{
|
||
"ci": {
|
||
"collect": {
|
||
"startServerReadyPattern": "Local:",
|
||
"startServerReadyTimeout": 60000
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 问题2:性能分数不达标
|
||
|
||
**症状**:`Assertion failed: categories:performance`
|
||
|
||
**解决方案**:
|
||
1. 查看详细报告找出问题
|
||
2. 根据优化建议进行改进
|
||
3. 调整性能预算(临时)
|
||
|
||
```json
|
||
{
|
||
"assertions": {
|
||
"categories:performance": ["warn", {"minScore": 0.8}]
|
||
}
|
||
}
|
||
```
|
||
|
||
### 问题3:测试超时
|
||
|
||
**症状**:`Navigation timeout of 30000 ms exceeded`
|
||
|
||
**解决方案**:
|
||
```json
|
||
{
|
||
"ci": {
|
||
"collect": {
|
||
"settings": {
|
||
"maxWaitForLoad": 45000
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 最佳实践
|
||
|
||
### ✅ 推荐做法
|
||
|
||
1. **设置合理的性能预算**
|
||
- 基于当前性能设置目标
|
||
- 逐步提高标准
|
||
|
||
2. **定期运行测试**
|
||
- 在CI/CD中自动运行
|
||
- 每次部署前检查
|
||
|
||
3. **监控性能趋势**
|
||
- 使用Lighthouse CI服务器
|
||
- 跟踪性能变化
|
||
|
||
4. **优化关键页面**
|
||
- 首页
|
||
- 高流量页面
|
||
- 转化页面
|
||
|
||
### ❌ 避免的做法
|
||
|
||
1. **不要设置过高的目标**
|
||
```json
|
||
// ❌ 不现实
|
||
"categories:performance": ["error", {"minScore": 1.0}]
|
||
|
||
// ✅ 合理
|
||
"categories:performance": ["error", {"minScore": 0.9}]
|
||
```
|
||
|
||
2. **不要忽略移动端性能**
|
||
```bash
|
||
# 同时测试桌面和移动端
|
||
npm run lighthouse:desktop
|
||
npm run lighthouse:mobile
|
||
```
|
||
|
||
3. **不要跳过性能测试**
|
||
- 性能问题会影响用户体验
|
||
- 早期发现问题更容易修复
|
||
|
||
## 参考资源
|
||
|
||
- [Lighthouse CI官方文档](https://github.com/GoogleChrome/lighthouse-ci)
|
||
- [Web Vitals](https://web.dev/vitals/)
|
||
- [性能优化指南](https://web.dev/performance/)
|
||
- [Lighthouse评分指南](https://web.dev/performance-scoring/)
|
||
|
||
## 总结
|
||
|
||
Lighthouse CI已完全集成到项目中,提供了:
|
||
|
||
✅ **自动化性能测试**
|
||
✅ **性能预算监控**
|
||
✅ **CI/CD集成**
|
||
✅ **详细的性能报告**
|
||
✅ **历史趋势跟踪**
|
||
|
||
通过合理使用Lighthouse CI,可以:
|
||
- 保持良好的性能水平
|
||
- 及时发现性能退化
|
||
- 持续优化用户体验
|
||
- 建立性能文化
|