Audits и их реализация

Система аудитов в библиотеке Lighthouse представляет собой модульную структуру, где каждая проверка (audit) является независимым классом с четко определённым интерфейсом. Аудиты работают поверх результатов трассировки, сетевых логов и артефактов, собранных во время прогона.

Каждый аудит:

  • получает входные данные (artifacts)
  • выполняет вычисления
  • возвращает структурированный результат (score, displayValue, details)

Базовая единица — класс, наследующийся от Audit.


Структура аудита

Каждый аудит реализуется как ES6-класс:

const Audit = require('lighthouse').Audit;

class MyAudit extends Audit {
  static get meta() {
    return {
      id: 'my-audit',
      title: 'Описание аудита',
      failureTitle: 'Описание при провале',
      description: 'Подробное описание проверки',
      requiredArtifacts: ['MyArtifact'],
    };
  }

  static audit(artifacts, context) {
    // логика проверки
    return {
      score: 1,
      displayValue: 'OK',
    };
  }
}

module.exports = MyAudit;

Метаданные аудита (meta)

Метод meta определяет ключевые характеристики:

Обязательные поля:

  • id — уникальный идентификатор аудита
  • title — отображаемое название при успешном результате
  • failureTitle — альтернативное название при провале
  • description — описание для отчёта
  • requiredArtifacts — список зависимостей

Дополнительные поля:

  • scoreDisplayMode — режим отображения:

    • numeric
    • binary
    • manual
    • notApplicable
    • informative
  • supportedModes — режимы Lighthouse (navigation, timespan, snapshot)


Артефакты (Artifacts)

Аудиты не работают напрямую с браузером. Они используют заранее собранные данные:

  • DOM-дерево
  • Network requests
  • Trace events
  • Accessibility tree

Пример:

static get meta() {
  return {
    requiredArtifacts: ['URL', 'ConsoleMessages'],
  };
}

Использование:

static audit(artifacts) {
  const messages = artifacts.ConsoleMessages;
}

Контекст выполнения (context)

Второй аргумент метода audit содержит:

  • settings — настройки Lighthouse
  • options — параметры аудита
  • computedCache — кэш вычислений

Пример:

static audit(artifacts, context) {
  const throttling = context.settings.throttling;
}

Результат аудита

Аудит возвращает объект:

{
  score: 0.0 - 1.0,
  displayValue: string,
  explanation: string,
  details: object
}

Поля:

score

  • число от 0 до 1
  • может быть null (если не применимо)

displayValue

  • краткий результат
  • используется для UI

explanation

  • объяснение причины провала

details

  • структурированные данные (таблицы, списки)

Типы оценок (scoreDisplayMode)

1. numeric

Оценка от 0 до 1:

score: 0.85

2. binary

Только 0 или 1:

score: hasError ? 0 : 1

3. informative

Без оценки:

score: null

4. manual

Требует ручной проверки


Работа с деталями (details)

Для вывода сложных данных используется поле details.

Таблица:

details: {
  type: 'table',
  headings: [
    {key: 'url', itemType: 'url', text: 'URL'},
    {key: 'size', itemType: 'bytes', text: 'Размер'},
  ],
  items: [
    {url: 'https://example.com', size: 12345},
  ],
}

Список:

details: {
  type: 'list',
  items: [
    {text: 'Ошибка 1'},
    {text: 'Ошибка 2'},
  ],
}

Использование вычисляемых значений (Computed Artifacts)

Для повторного использования логики применяются computed artifacts.

Пример:

const ComputedArtifact = require('lighthouse').computedArtifacts.MyComputed;

static async audit(artifacts, context) {
  const result = await ComputedArtifact.request(artifacts, context);
}

Преимущества:

  • переиспользование кода
  • кэширование
  • изоляция логики

Асинхронные аудиты

Метод audit может быть асинхронным:

static async audit(artifacts) {
  const data = await someAsyncFunction();
  return {
    score: data.ok ? 1 : 0,
  };
}

Пример сложного аудита

class ImageSizeAudit extends Audit {
  static get meta() {
    return {
      id: 'image-size',
      title: 'Оптимизация изображений',
      failureTitle: 'Изображения не оптимизированы',
      requiredArtifacts: ['NetworkRecords'],
    };
  }

  static audit(artifacts) {
    const images = artifacts.NetworkRecords.filter(r =>
      r.resourceType === 'Image'
    );

    const oversized = images.filter(img => img.transferSize > 100000);

    return {
      score: oversized.length === 0 ? 1 : 0,
      displayValue: `${oversized.length} больших изображений`,
      details: {
        type: 'table',
        headings: [
          {key: 'url', text: 'URL'},
          {key: 'size', text: 'Размер'},
        ],
        items: oversized.map(img => ({
          url: img.url,
          size: img.transferSize,
        })),
      },
    };
  }
}

Конфигурация аудитов

Аудиты подключаются через конфигурацию:

module.exports = {
  audits: [
    'my-audit',
    'image-size',
  ],
};

Или с параметрами:

{
  path: 'my-audit',
  options: {
    threshold: 1000,
  },
}

Группировка аудитов

Аудиты объединяются в категории:

categories: {
  performance: {
    audits: [
      {id: 'image-size', weight: 1},
    ],
  },
}

Вес влияет на итоговый score категории.


Обработка ошибок

При ошибке аудит должен возвращать корректный результат:

try {
  // логика
} catch (e) {
  return {
    score: 0,
    explanation: 'Ошибка выполнения аудита',
  };
}

Лучшие практики реализации

Минимальные зависимости

  • запрашивать только нужные artifacts

Чистая логика

  • отделение вычислений от отображения

Детерминированность

  • одинаковый вход → одинаковый результат

Производительность

  • избегать тяжелых вычислений
  • использовать computed artifacts

Расширение функциональности

Аудиты можно:

  • комбинировать
  • использовать как основу для кастомных метрик
  • интегрировать в CI/CD

Интеграция с CLI и Node API

Через Node API:

const lighthouse = require('lighthouse');

const result = await lighthouse(url, {
  port: 9222,
}, {
  extends: 'lighthouse:default',
  audits: ['my-audit'],
});

Взаимодействие с gatherers

Аудиты не собирают данные напрямую. Для этого используются gatherers:

  • gatherer → собирает данные
  • audit → анализирует

Связь через artifacts:

requiredArtifacts: ['MyCustomArtifact']

Тестирование аудитов

Используется mocha/jest:

it('should pass audit', async () => {
  const artifacts = {...};
  const result = await MyAudit.audit(artifacts);
  assert.equal(result.score, 1);
});

Влияние на итоговый отчёт

Каждый аудит влияет на:

  • категорию
  • общий score
  • рекомендации

Чем выше точность и релевантность аудита, тем полезнее итоговый отчёт Lighthouse.


Расширенные сценарии

Условные аудиты

if (!artifacts.URL.finalUrl.includes('https')) {
  return {
    score: null,
  };
}

Пороговые значения

const score = value < threshold ? 1 : 0;

Мультифакторные проверки

const score = (a + b + c) / 3;

Внутренний цикл выполнения

  1. Сбор данных (gather phase)
  2. Формирование artifacts
  3. Выполнение аудитов
  4. Агрегация результатов
  5. Формирование отчёта

Аудиты являются центральным этапом анализа, преобразуя сырые данные в осмысленные метрики и рекомендации.