DarkRiDDeR15 мин

Разбор bundle: найти источник роста без гадания

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

Проблема bundle-анализа начинается с общей цифры: JavaScript-артефакт вырос на 180 КБ. Если сразу удалить большую библиотеку, можно убрать не ту причину. Рост мог появиться из-за новой точки входа, отключённого tree-shaking, дубликата зависимости или включённой source map. Цена неверного действия — регресс функциональности и новый спор о том, какая оптимизация вообще дала эффект.

Полевой разбор должен свести изменение output к input. Для этого сохраняем два metafile или отчёта сборки, нормализуем пути и считаем delta bytes для каждого входа. Затем проверяем, в какой output попал input и почему. Только после этого выбираем действие: убрать импорт, изменить split, проверить dependency version или оставить рост как осознанную стоимость.

Сначала ищем изменение, а не виновника

esbuild metafile содержит inputs и outputs, включая количество байт input, попавших в output. Это удобнее, чем смотреть только на размер файла: можно увидеть, что добавилось, исчезло или изменилось. Но bytes в metafile — размер вклада в артефакт, а не обязательно размер передачи по сети и не время выполнения. Для пользовательской скорости нужны отдельные browser measurements.

Source map помогает связать сжатый или преобразованный JavaScript с исходным модулем. При этом карта сама может быть большой и не должна случайно попасть в production response. HTTP SourceMap header и annotation имеют правила, по которым DevTools находит карту. Проверяйте, что путь доступен только в нужной среде и что карта соответствует именно этому bundle.

Цикл разбора роста bundle: сравнить metafile, найти input с delta, проверить chunk и source map, затем повторить сборку.
Схема ведёт от общего симптома к конкретному input. Изменение кода выполняется после проверки состава артефакта, а не по размеру одного файла.
Матрица разбора роста bundle
НаблюдениеГде искатьПроверкаДействие
Новый большой inputmetafile.inputsкто импортирует модульразделить или удалить импорт
Старый input выросdelta bytes и chunktree-shaking и настройки minifyпроверить export и plugin
Дубликат зависимостипути разных версийresolver и lockfileсвести версию или alias
Source map вырослаoutput и responseвключён ли dev artifactразделить delivery и debug
Metafile стабиленbrowser resource timinggzip/brotli, cache, transferизмерить пользовательский путь

Учебный diff двух metafile

Функция принимает минимальный фрагмент esbuild-подобного JSON: имя input и его bytes. Она объединяет имена из двух сборок, считает delta и сортирует рост сверху. Так инженер получает список конкретных файлов для code search. Данные ниже учебные; в рабочем отчёте рядом с diff сохраняйте commit, command, target и output name.

import { summarizeBundleDiff } from './upgrade-2027-04.mjs';

const before = { inputs: {
  'src/app.js': { bytes: 12000 },
  'src/table.js': { bytes: 8000 },
  'node_modules/date.js': { bytes: 5000 },
} };
const after = { inputs: {
  'src/app.js': { bytes: 12000 },
  'src/table.js': { bytes: 11000 },
  'node_modules/date.js': { bytes: 5000 },
  'node_modules/chart.js': { bytes: 42000 },
} };

console.log(summarizeBundleDiff(before, after));
// chart.js +42000; table.js +3000

Результат даёт два адреса: новая chart.js и выросшая table.js. Это ещё не решение. Для chart.js нужно найти entry/import и проверить split; для table.js — посмотреть, почему изменился export или transform. Если общий output вырос меньше суммы input delta из-за компрессии и tree-shaking, это нормально: diff направляет исследование, но не заменяет финальный artefact и браузерный замер.

От bytes к пользовательскому эффекту

Большой input может не попасть в первый экран, а маленький модуль — блокировать критический маршрут. Поэтому после статического diff смотрите chunk graph и network resource timing. Transfer size зависит от compression и cache; decoded body size — другой показатель. Cross-origin ресурс может вернуть нулевой transferSize без Timing-Allow-Origin. Эти ограничения нужно написать рядом с числом, иначе bytes начинают выглядеть как latency.

В source map ищите исходный модуль, но проверяйте соответствие commit. Старая карта при новом bundle создаёт ложную навигацию в DevTools и увеличивает время разбора следующей ошибки. Для production обычно ограничивают доступ к картам или публикуют их в отдельном хранилище с контролем прав. Это уже часть delivery contract, а не косметика сборки.

Действия по порядку

  1. Сохранить два metafile для одинакового input и убедиться, что output names и mode сопоставимы.
  2. Посчитать delta по inputs и outputs, затем найти import path, chunk и owner изменившегося модуля.
  3. Проверить lockfile, duplicate versions, tree-shaking, plugin transform и minify настройки.
  4. Сверить source map с commit и отдельно проверить, не попала ли debug-карта в пользовательскую доставку.
  5. Измерить transfer, decoded size, cache и время загрузки критического маршрута; только потом оценивать эффект оптимизации.

Ограничения и следующий шаг

Metafile показывает структуру конкретного bundler и не знает о поведении браузера, compression, CDN и cache. Delta bytes не является p95 и не гарантирует изменение FCP. Source map может быть недоступна или намеренно скрыта, поэтому связь с исходником иногда требует другого артефакта. Статический diff также не видит работу runtime и dynamic import до его выполнения.

Следующий шаг — добавить автоматический budget по критическим output и список разрешённых изменений. Для каждого превышения pipeline должен печатать top inputs, commit и команду воспроизведения. Тогда фраза «bundle вырос» превращается в короткий проверяемый маршрут: какой файл добавился, в какой chunk попал и какой пользовательский ресурс изменился.

Проверяемые источники

  • esbuild API: Metafile — версия и дата: esbuild API documentation, checked 31 July 2026. Применение: Metafile JSON и поля inputs/outputs/bytes используются для вычисления diff состава bundle. Граница: Документация предупреждает, что текстовый analyze предназначен людям; JSON не измеряет браузерную доставку.
  • MDN: SourceMap HTTP header — версия и дата: MDN Web Docs, page modified 21 November 2025. Применение: Правило SourceMap header и связь DevTools с исходным кодом используются для проверки карты. Граница: MDN не подтверждает доступность карты и не измеряет размер или скорость конкретного ресурса.
  • webpack 5 Guide: Caching — версия и дата: webpack 5 guide, checked 31 July 2026. Применение: Contenthash и стабильная структура output используются как контекст повторяемого артефакта. Граница: Руководство webpack не описывает esbuild metafile и пользовательский performance budget.