← Все статьи

SiteGuard12 мин чтения

Бюджет производительности сайта: как не пропускать тяжёлые страницы в релиз

Бюджет производительности сайта превращает требования к скорости в проверяемые условия выпуска. Команда заранее выбирает страницы, условия измерения и допустимые пределы. Затем каждая новая сборка проходит одинаковую проверку: превышение согласованного лимита останавливает выпуск до исправления или оформленного исключения. Это помогает заметить лишний JavaScript, тяжёлый блок или замедлившееся появление контента до того, как изменение попадёт к посетителям.

Рабочий performance budget состоит из трёх частей: понятного ограничения, воспроизводимого измерения и обязательного решения при нарушении. Красивый отчёт без последнего шага остаётся отчётом. Ниже разберём небольшой набор правил, конфигурацию Lighthouse CI и учебный пример, в котором новая функция не проходит проверку, хотя сама страница открывается.

Начните с профилей страниц, которые меняет релиз

Бюджет привязывают к пользовательской задаче и состоянию страницы. Для магазина полезны каталог, карточка товара и оформление заказа. Для сервиса заявок — посадочная страница и экран с формой. Главная страница редко представляет весь сайт: у разных шаблонов могут отличаться фотографии, библиотеки, персонализация и набор внешних скриптов.

В каждом профиле зафиксируйте конкретный URL, ожидаемый контент, устройство, состояние посетителя и ответственного. Например, карточка товара с обычной галереей и карточка с интерактивным просмотром — разные состояния. Если проверяется только самая лёгкая карточка, ограничение не защищает более дорогой вариант. При этом запускать все существующие адреса на каждом изменении обычно не требуется.

  • Выберите представитель каждого важного шаблона и отдельно страницу с заведомо тяжёлым содержимым.
  • Зафиксируйте товар, язык, регион, вариант эксперимента и состояние согласия на дополнительные скрипты.
  • Для закрытых разделов предусмотрите воспроизводимую тестовую сессию; не подставляйте случайные личные данные сотрудника.
  • Назначьте владельца профиля, который подтвердит, что проверяемая страница по-прежнему соответствует реальному сценарию.

Расширяйте набор при изменении структуры сайта. Новый конструктор товара или отдельная мобильная версия заслуживают собственного профиля. Замена текста в существующем шаблоне обычно не требует новой системы измерений, но замена первого экрана видеороликом может потребовать пересмотра состава проверок.

Зафиксируйте базовый уровень и смысл лимита

Базовый уровень, или baseline, — сохранённый результат известной версии в согласованных условиях. В карточке измерения нужны идентификатор сборки, дата, профиль страницы, версии инструментов и исходные отчёты. Фраза «раньше было быстрее» не позволяет проверить регрессию. Для сравнения должны существовать данные, которые другой разработчик сможет воспроизвести.

Перед включением обязательного ограничения проведите несколько серий измерений одной сборки. Посмотрите, насколько меняются значения без изменения кода. Если результат скачет из-за случайного содержимого или перегруженного исполнителя CI, сначала исправьте условия. Выбор большого допуска поверх необъяснимого разброса делает правило менее полезным и может скрыть настоящую проблему.

Разделяйте текущую базу, предел допуска и цель улучшения. Допустим, команда хочет постепенно сократить загрузку, но существующий сайт уже тяжёлый. Временный предел может сдерживать дальнейший рост, пока выполняется план оптимизации. Это переходное решение с владельцем и сроком, а не свидетельство хорошей скорости. Нельзя выдавать принятую техническую задолженность за достигнутую цель.

Базу обновляют после осознанного решения. Автоматически принимать каждый успешный релиз за новую норму опасно: небольшие увеличения будут накапливаться, а сравнение только с предыдущей версией перестанет показывать общий рост. Храните также исходную контрольную точку и историю изменения самих лимитов.

Разделите вес ресурсов и время появления контента

Для первого бюджета достаточно нескольких показателей с разным смыслом. Размер ресурсов показывает, что именно страница заставляет передавать при выбранной загрузке. Временная метрика показывает результат выполнения этой загрузки. Один показатель не заменяет другой: сокращение файла не гарантирует такое же сокращение времени, а хороший результат на мощном исполнителе не оправдывает неограниченный рост ресурсов.

В описании Resource Summary Lighthouse учитывает запросы и объём переданных данных. Для JavaScript нас интересует строка Script, а не размер исходников в репозитории. Проверка охватывает ресурсы, наблюдавшиеся при загрузке; код, который появится только после отдельного действия, может потребовать другого сценария измерения. Зафиксируйте эту границу в карточке бюджета.

Лабораторный LCP характеризует появление крупнейшего видимого элемента в данном прогоне. Внутреннее значение аудита largest-contentful-paint хранится в миллисекундах, хотя интерфейс может показывать секунды. Для учебного примера ниже используем два обязательных ограничения. Числа придуманы для объяснения процесса и не являются универсальной нормой для любого сайта.

ПоказательУчебный пределЧто проверяем
Переданный JavaScript307200 байт, или 300 KiBСуммарный размер скриптов выбранной загрузки
Лабораторный LCP2500 мсВремя появления крупнейшего элемента

Здесь KiB означает 1024 байта: 300 × 1024 = 307200. Не переносите число 300 в поле, ожидающее байты. Общий балл Performance также имеет собственную шкалу: в настройке категории значение minScore: 0.9 соответствует 90 баллам из 100, а не 0.9 балла. В нашем примере суммарный балл не используется как условие допуска.

Сделайте среду измерения повторяемой

Измеряйте собранную версию, которую собираетесь выпускать, с рабочими настройками сжатия и отдачи ресурсов. Сервер разработки с дополнительными скриптами и диагностикой не подходит в качестве незаметной замены. Если проверка идёт на отдельном адресе, убедитесь, что там развернута нужная сборка, а не предыдущая версия или страница авторизации.

Закрепите версии Lighthouse CI, используемого Lighthouse, браузера и образа исполнителя. Запишите профиль устройства, размер экрана, метод ограничения сети и CPU. Изменение этих параметров требует повторного измерения базы. По документации о вариативности Lighthouse, результаты зависят в том числе от содержимого страницы, сети, оборудования и конкуренции за ресурсы. Несколько параллельных измерений на одной перегруженной машине способны искажать сравнение.

Особое внимание уделите cookies и динамическим блокам. Сегодня один и тот же адрес может показывать баннер согласия, завтра — персональные рекомендации. Зафиксируйте состояние для основного сравнения, а важные альтернативы вынесите в отдельные профили. Если внешний виджет исключён ради стабильности, явно отметьте это: его вклад тогда не проверяется этим запуском.

Холодный браузерный кеш и повторный визит с прогретым кешем отвечают на разные вопросы. Выберите режим для каждого профиля и проверяйте фактическое состояние, включая service worker. Не смешивайте эти результаты в общей медиане. Отдельно учитывайте кеш CDN и приложения: очистка браузера сама по себе не делает серверный ответ холодным. Для каждого режима нужны собственные условия подготовки и собственная база.

Минимальная настройка Lighthouse CI

Ниже — учебный файл lighthouserc.json. Предполагается, что проверяемая сборка уже запущена на http://localhost:3000, нужная карточка существует, Chrome установлен, а согласованная версия @lhci/cli закреплена в зависимостях проекта. Путь заменяют адресом своей страницы. Для простоты явно выбран настольный профиль; он не подтверждает результат на мобильном устройстве.

{
  "ci": {
    "collect": {
      "url": ["http://localhost:3000/product/demo"],
      "numberOfRuns": 5,
      "settings": {
        "preset": "desktop"
      }
    },
    "assert": {
      "assertions": {
        "resource-summary:script:size": [
          "error",
          {
            "maxNumericValue": 307200,
            "aggregationMethod": "median"
          }
        ],
        "largest-contentful-paint": [
          "error",
          {
            "maxNumericValue": 2500,
            "aggregationMethod": "median"
          }
        ]
      }
    }
  }
}

Синтаксис соответствует документации Lighthouse CI: numberOfRuns задаёт число прогонов, maxNumericValue — числовой предел, aggregationMethod: median — медиану значений проверяемого показателя. Для resource-summary:script:size размер задаётся в байтах. Не смешивайте этот формат с отдельным файлом budget.json, у которого другой способ задания размера.

Пример проверяет два абсолютных предела. Он не вычисляет процент ухудшения относительно прошлой сборки. Если нужен отдельный запрет на относительный рост, добавьте явно реализованное сравнение сохранённых отчётов с базой и собственное правило отказа. Надпись «контроль регрессий» сама по себе такой проверки не создаёт.

Свяжите результат проверки с остановкой выпуска

После сборки приложения и проверки готовности сервера запускайте сбор отчётов, затем проверку ограничений. Ниже сценарий для bash в окружении, где закреплённый CLI уже установлен. Он останавливается при неуспехе любой команды; проверка ограничений запускается только после успешного сбора.

set -euo pipefail
./node_modules/.bin/lhci collect --config=./lighthouserc.json
./node_modules/.bin/lhci assert --config=./lighthouserc.json

Разницу между уровнями объясняет руководство web.dev по Lighthouse CI: нарушение с уровнем error даёт ненулевой код завершения, а warn только сообщает о проблеме. Чтобы это стало запретом выпуска, система CI должна считать такой шаг неуспешным, а публикация должна зависеть от его успеха. Проверьте также обязательность результата в правилах слияния изменений.

Не подавляйте ошибку оболочкой и не включайте для этого шага продолжение после неуспеха. Если команды объединены в один сценарий, он обязан остановиться и при ошибке сбора данных. Иначе команда может случайно принять отсутствие свежего отчёта за отсутствие нарушений. Отчёты сохраняют как артефакты даже при отказе, чтобы разработчик видел причину.

При настройке сделайте контрольное нарушение: временно установите заведомо недостижимый предел в тестовой ветке. Убедитесь, что проверка красная и выпуск действительно заблокирован. Затем верните согласованное значение. Отдельно проверьте недоступный URL или сбой запуска браузера: техническая невозможность измерить страницу не должна превращаться в зелёный результат.

Используйте повторные прогоны без самообмана

В примере пять измерений каждого URL. Это даёт возможность увидеть разброс, но число пять не является доказательством достоверности. Все прогоны могут попасть на перегруженный сервер, получить одинаково неверное содержимое или выполняться в условиях, отличающихся от базы. Полезность повтора определяется сохранением условий и тем, что команда изучает исходные значения.

В выбранной настройке сравнивается медиана каждого показателя. Она может брать своё центральное значение из разных прогонов. Это отличается от median-run, который выбирает один представительный отчёт по ключевым метрикам. Также существует optimistic, выбирающий значение, которому легче пройти правило. Поэтому метод агрегации здесь указан явно, а не оставлен неявной настройкой.

Сохраняйте все результаты, а не только центральное число. Если один запуск резко медленнее остальных, выясните, что произошло. Возможно, появился непредсказуемый запрос, истёк кеш или изменился внешний блок. Медиана может пройти установленный предел, но это не обязывает команду игнорировать выявленную нестабильность: для неё нужен отдельный критерий разбора.

Заранее определите порядок повторной проверки. Например, повтор допускается после подтверждённого сбоя измерительной среды с записью причины. Многократные перезапуски до первого зелёного результата подбирают удобную выборку. При спорном изменении полезнее заново измерить базовую и новую сборки в сопоставимых условиях, чем сравнивать сегодняшний кандидат со старым случайным запуском.

Учебный пример: новый блок увеличил вес карточки

Все данные в этом разделе вымышлены. Команда добавляет на карточку интерактивный блок рекомендаций. До изменения пять значений LCP составляли 2000, 2050, 2100, 2150 и 2200 мс; медиана равнялась 2100 мс. В каждом прогоне передавалось 256000 байт JavaScript, то есть 250 KiB. Это сохранённая база выбранного настольного профиля.

После изменения JavaScript вырос до 358400 байт, или 350 KiB. Значения LCP составили 2400, 2550, 2600, 2700 и 3100 мс. Центральное значение — 2600 мс. Первый прогон укладывается в предел 2500 мс, однако выбранное правило проверяет медиану, поэтому такой удачный запуск не делает сборку приемлемой.

ИзмерениеБазаКандидатПредел
JavaScript250 KiB350 KiB300 KiB
Медиана LCP2100 мс2600 мс2500 мс

Размер увеличился на 100 KiB, или на 40% относительно базы, и превысил предел на 50 KiB. LCP ухудшился на 500 мс относительно базы и превысил предел на 100 мс. Обе обязательные проверки завершаются ошибкой. Команда сначала разбирает изменение, а не поднимает лимит до получившегося значения.

После удаления лишней библиотеки повторная серия дала 286720 байт JavaScript и медиану LCP 2250 мс. Теперь оба абсолютных ограничения соблюдены. При этом размер всё ещё больше базы на 30 KiB, или 12%, а LCP — на 150 мс. Эти изменения остаются предметом приёмки: успешный gate подтверждает выполнение заданных правил, а не отсутствие любого ухудшения.

Разбирайте регрессию от наблюдаемого изменения к причине

Начните с проверки сопоставимости отчётов. Совпадают ли сборка, профиль, содержимое, настройки сервера и измерительная среда? Не заменился ли успешный ответ редиректом? Не пропала ли галерея? Более лёгкая страница может оказаться неполной. Успех ограничения на вес имеет смысл только для ожидаемого содержимого.

Далее сопоставьте список запросов. При росте JavaScript ищите добавленные пакеты, дублирование зависимостей, изменение разделения кода и появление скрипта на страницах, где он не нужен. Сравнивайте переданный объём при одинаковых условиях сжатия. Отдельный отчёт сборщика помогает объяснить состав кода, но его размер файла нельзя автоматически приравнивать к сетевому объёму Lighthouse.

Если размер почти не изменился, а LCP ухудшился, исследуйте последовательность загрузки: когда получен документ, найден важный ресурс, завершена его загрузка и стало возможно отображение. Проверьте, остался ли элемент LCP тем же. Замена крупного изображения текстом меняет предмет измерения, даже если название метрики осталось прежним.

Сформулируйте проверяемую гипотезу и меняйте одну существенную причину за раз. После исправления повторите тот же профиль, сохраните отчёты и объясните результат в описании изменения. Хорошее обоснование связывает конкретную добавленную зависимость или ресурс с наблюдаемым ростом, а не ограничивается словами «оптимизировали производительность».

Оформляйте исключения с владельцем и сроком

Иногда команда сознательно принимает временное превышение: например, необходимая функция выходит раньше завершения оптимизации. Исключение должно описывать точную страницу, показатель, новое временное значение, деловую причину, владельца решения и дату окончания. Приложите отчёты и задачу по возврату в бюджет. Общая фраза «разрешено ухудшение скорости» не ограничивает последствия.

Разрешение относится только к названному профилю и пределу. Превышение на карточке не должно отключать проверки каталога и формы. Остальные условия остаются обязательными. Если система не умеет автоматически отменять исключение по дате, назначьте отдельную проверку срока и ответственного: сама запись даты в комментарии не меняет поведение CI.

Автор изменения предлагает исключение, технический владелец объясняет последствия, а уполномоченный владелец продукта принимает решение. Для маленькой команды это могут быть два человека, но решение и фактический предел должны оставаться видимыми. Продление требует нового объяснения, а не бесконечного переноса даты без просмотра данных.

После исправления верните основное правило и снова проверьте, что нарушение блокирует выпуск. Исключение закрывается вместе с техническим изменением и подтверждающим измерением. Иначе временное послабление остаётся в конфигурации дольше самой причины и незаметно разрешает будущие регрессии.

Согласуйте, что означает готовность к выпуску

До внедрения бюджета договоритесь о трактовке результатов. Разработчик должен понимать, что исправлять, руководитель выпуска — когда остановиться, а владелец сайта — какое ухудшение он согласовывает. Следующая таблица задаёт простой порядок решений; она подходит как основа внутреннего правила, которое команда адаптирует под свой процесс.

РезультатРешение о выпуске
Все обязательные профили измерены, пределы соблюденыПроверка производительности пройдена
Есть нарушение без действующего исключенияОстановить выпуск и разобрать причину
Есть ограниченное действующее исключениеПроверить его условия и остальные обязательные правила
Нет достоверного измерения обязательной страницыНе считать проверку пройденной; восстановить измерение

В отчёте приёмки укажите проверенную сборку, профили, базу, фактические значения, пределы и ссылки на артефакты. Если новый экран пока не покрыт, назовите его явно. «Проверка зелёная» без перечня охвата не объясняет, защищены ли страницы, которые действительно изменились в релизе.

Регулярно пересматривайте сам бюджет: актуальны ли шаблоны, не устарели ли данные, не появилось ли постоянно используемое состояние вне проверки. Пересмотр не означает автоматического смягчения. Он помогает сохранить соответствие между правилами выпуска и тем, как посетители пользуются сайтом.

Дополните CI наблюдением после публикации

Лабораторная проверка ограничена выбранными условиями. Разбор лабораторных и полевых данных на web.dev объясняет, почему результаты реальных посетителей могут отличаться. TBT помогает исследовать блокировку основного потока при загрузке, но не заменяет полевой INP, связанный с реальными взаимодействиями. Прохождение лимита LCP в CI также не подтверждает показатель всех посещений сайта.

После выпуска наблюдайте опубликованную версию и сопоставляйте проблемы с моментом изменения. CI помогает остановить заранее определённые регрессии; данные эксплуатации показывают поведение сайта в условиях, которые тестовый профиль полностью не воспроизводит. Эти результаты полезны и для следующего уточнения бюджета.

После выпуска подключите SiteGuard для внешнего HTTP-контроля доступности важных страниц сайта.