Modern QA2026Шлюзы производительности Web Vitals в CI
Join

Course05 Performance & Chaos Engineering

Cutting-edge · Chapter 05

Шлюзы производительности 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
  +------------------+

Обработка провалов бюджета производительности

Когда проверка бюджета производительности проваливается, команде нужен чёткий процесс:

Процесс сортировки

  1. Это реальная регрессия или нестабильность теста? Перезапустите проверку. Если при повторном запуске тест проходит, исследуйте стабильность тестов.
  2. Что изменилось? Сравните проваливающийся PR с базовой линией главной ветки. Представление различий Lighthouse CI помогает в этом.
  3. Это приемлемо? Некоторые функции обоснованно увеличивают размер бандла или LCP. Если компромисс оправдан, обновите бюджет с комментарием, объясняющим причину.
  4. Можно ли оптимизировать? Распространённые исправления включают ленивую загрузку, разделение кода, оптимизацию изображений и заголовки кеширования.

Процесс исключений из бюджета

Иногда увеличение бюджета оправданно. Задокументируйте это:

{
  "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 дней на решение

Бюджеты производительности — это не однократная настройка. Для эффективности они требуют постоянного обслуживания, калибровки и приверженности команды. Вознаграждение — продукт, который остаётся быстрым по мере роста.