Шлюзы производительности Web Vitals в CI
Updated Jul 2026
От Lighthouse к CI-пайплайну
Наличие конфигурации Lighthouse CI — это только полдела. Настоящая ценность возникает при интеграции проверок производительности в ваш CI-пайплайн, чтобы каждый pull request автоматически проверялся на соответствие бюджетам производительности. Этот файл покрывает все паттерны интеграции с CI.
GitHub Actions: полный рабочий процесс проверки бюджета производительности
# .github/workflows/performance-budget.yml
name: Performance Budget Check
on:
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
cache: npm
- name: Install dependencies and build
run: npm ci && npm run build
- name: Deploy preview
run: npm run deploy:preview
env:
PREVIEW_TOKEN: ${{ secrets.PREVIEW_TOKEN }}
- name: Run Lighthouse CI
uses: treosh/lighthouse-ci-action@v11
with:
configPath: ./lighthouserc.json
uploadArtifacts: true
temporaryPublicStorage: true
- name: Check bundle size budget
run: npx bundlesize --config bundlesize.config.json
- name: Check API response time budget
run: |
FAILED=0
for endpoint in "/api/products" "/api/cart" "/api/search?q=test"; do
RESPONSE_TIME=$(curl -o /dev/null -s -w '%{time_total}' \
"https://staging.example.com${endpoint}")
echo "$endpoint: ${RESPONSE_TIME}s"
if (( $(echo "$RESPONSE_TIME > 0.5" | bc -l) )); then
echo "FAIL: $endpoint exceeded 500ms budget (actual: ${RESPONSE_TIME}s)"
FAILED=1
fi
done
if [ "$FAILED" -eq 1 ]; then
exit 1
fi
- name: Post results as PR comment
if: always()
uses: marocchino/sticky-pull-request-comment@v2
with:
header: performance-budget
path: lighthouse-results-summary.md
Многоступенчатый пайплайн производительности
Для зрелых команд валидация производительности должна быть многоступенчатым процессом:
# .github/workflows/performance-gates.yml
name: Performance Gates
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
# Stage 1: Build-time checks (fast, every PR)
build-time-budget:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci && npm run build
- name: Check bundle sizes
run: npx bundlesize --config bundlesize.config.json
- name: Check for new dependencies > 50KB
run: |
npx webpack-bundle-analyzer dist/stats.json \
--mode json --no-open -r bundle-report.json
node scripts/check-large-deps.js bundle-report.json
# Stage 2: Lighthouse audit (medium speed, every PR)
lighthouse-audit:
needs: build-time-budget
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci && npm run build
- name: Start local server
run: npm run serve &
env:
PORT: 3000
- name: Wait for server
run: npx wait-on http://localhost:3000 --timeout 30000
- name: Run Lighthouse CI
uses: treosh/lighthouse-ci-action@v11
with:
urls: |
http://localhost:3000/
http://localhost:3000/products/1
configPath: ./lighthouserc.json
# Stage 3: API performance (on merge to main only)
api-performance:
if: github.event_name == 'push'
needs: [build-time-budget, lighthouse-audit]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run k6 API performance tests
uses: grafana/k6-action@v0.4.0
with:
filename: tests/performance/api-budget.js
flags: --out json=k6-results.json
env:
K6_TARGET_URL: ${{ secrets.STAGING_URL }}
- name: Validate k6 thresholds
run: |
# k6 exits non-zero if thresholds fail
echo "k6 thresholds validated successfully"
- name: Upload results
uses: actions/upload-artifact@v4
with:
name: k6-api-budget-results
path: k6-results.json
Скрипт k6 для бюджета производительности
Дополните Lighthouse (фронтенд) бюджетами k6 (бэкенд API):
// tests/performance/api-budget.js
import http from 'k6/http';
import { check } from 'k6';
export const options = {
scenarios: {
budget_check: {
executor: 'shared-iterations',
vus: 5,
iterations: 50,
maxDuration: '2m',
},
},
thresholds: {
// API performance budgets
'http_req_duration{name:products_list}': ['p(95)<200'],
'http_req_duration{name:product_detail}': ['p(95)<150'],
'http_req_duration{name:search}': ['p(95)<300'],
'http_req_duration{name:cart}': ['p(95)<250'],
// Global budgets
http_req_failed: ['rate<0.01'],
},
};
const BASE_URL = __ENV.K6_TARGET_URL || 'https://staging.example.com';
export default function () {
// Products list
let res = http.get(`${BASE_URL}/api/products`, { tags: { name: 'products_list' } });
check(res, { 'products 200': (r) => r.status === 200 });
// Product detail
res = http.get(`${BASE_URL}/api/products/1`, { tags: { name: 'product_detail' } });
check(res, { 'product detail 200': (r) => r.status === 200 });
// Search
res = http.get(`${BASE_URL}/api/search?q=laptop`, { tags: { name: 'search' } });
check(res, { 'search 200': (r) => r.status === 200 });
// Cart operations
res = http.post(`${BASE_URL}/api/cart`, JSON.stringify({ product_id: 1, qty: 1 }), {
headers: { 'Content-Type': 'application/json' },
tags: { name: 'cart' },
});
check(res, { 'cart 200': (r) => r.status === 200 });
}
Интеграция в полный пайплайн производительности
Проверки бюджета производительности — одна стадия более широкой стратегии производительности:
Developer Commits Code
|
v
+------------------+
| Build-Time | <-- Bundle size check, dependency audit
| Budget (< 1 min) | Runs on every PR
+--------+---------+
|
v
+------------------+
| Lighthouse CI | <-- Core Web Vitals, accessibility, SEO
| (2-5 min) | Runs on every PR
+--------+---------+
|
v
+------------------+
| API Performance | <-- k6 endpoint latency budgets
| Budget (2-3 min) | Runs on merge to main
+--------+---------+
|
v
+------------------+
| Staging Load | <-- Full k6 load test with production traffic model
| Test (15-30 min) | Runs before production deployment
+--------+---------+
|
v
+------------------+
| Production | <-- Canary + RUM validation
| Validation | Continuous after deployment
+------------------+
Обработка провалов бюджета производительности
Когда проверка бюджета производительности проваливается, команде нужен чёткий процесс:
Процесс сортировки
- Это реальная регрессия или нестабильность теста? Перезапустите проверку. Если при повторном запуске тест проходит, исследуйте стабильность тестов.
- Что изменилось? Сравните проваливающийся PR с базовой линией главной ветки. Представление различий Lighthouse CI помогает в этом.
- Это приемлемо? Некоторые функции обоснованно увеличивают размер бандла или LCP. Если компромисс оправдан, обновите бюджет с комментарием, объясняющим причину.
- Можно ли оптимизировать? Распространённые исправления включают ленивую загрузку, разделение кода, оптимизацию изображений и заголовки кеширования.
Процесс исключений из бюджета
Иногда увеличение бюджета оправданно. Задокументируйте это:
{
"budgetExceptions": [
{
"date": "2026-01-15",
"metric": "largest-contentful-paint",
"oldBudget": 2500,
"newBudget": 2800,
"reason": "New hero image carousel adds 300ms but increases conversion by 5%",
"reviewer": "qa-architect",
"revertDate": "2026-03-15"
}
]
}
Метрики для отслеживания во времени
Помимо прохождения/провала, отслеживайте эти тренды в вашей панели производительности:
| Метрика | Цель отслеживания | Порог алерта |
|---|---|---|
| Тренд LCP (30 дней) | Обнаружение постепенной деградации | Увеличение на 10% от базовой линии |
| Тренд размера бандла | Обнаружение раздувания JavaScript | Увеличение на 5% за квартал |
| Тренд оценки Lighthouse | Общая траектория качества | Оценка падает ниже 85 |
| Частота провалов бюджета | Здоровье процесса | > 20% PR проваливаются по производительности |
| Время исправления провалов бюджета | Отзывчивость команды | > 3 дней на решение |
Бюджеты производительности — это не однократная настройка. Для эффективности они требуют постоянного обслуживания, калибровки и приверженности команды. Вознаграждение — продукт, который остаётся быстрым по мере роста.