Порядок вызова хуков и их типы

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

Вся система хуков логически делится на две крупные группы:

  • хуки этапа построения (build hooks)
  • хуки этапа генерации выходного бандла (output generation hooks)

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


Хуки этапа построения графа модулей

Построение графа начинается с инициализации процесса сборки и завершается фиксацией всех модулей и их связей.

Первым вызывается хук:

buildStart

Он активируется один раз на всю сборку. На этом этапе ещё нет информации о модулях, и его основная роль — подготовка окружения, логирование или инициализация внутренних структур плагина.

Далее начинается процесс разрешения входных точек. Для каждого импорта Rollup последовательно проходит цепочку:

resolveId → load → transform

resolveId

Хук resolveId вызывается при попытке определить, откуда должен быть загружен модуль. Он может изменить путь, подменить модуль или вернуть null, позволяя другим плагинам обработать запрос.

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

load

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

Если load возвращает null, Rollup переходит к стандартному чтению файла.

transform

Следующий этап — transform. Это один из ключевых хуков, поскольку он позволяет изменять код модуля после загрузки, но до анализа зависимостей.

На этом этапе выполняются транспиляции, вставка импортов, замена синтаксиса и любые AST-преобразования.

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


Завершение построения графа

После обработки всех модулей вызывается:

moduleParsed

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

Завершающим хуком фазы построения является:

buildEnd

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


Переход к фазе генерации бандла

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


Хуки генерации выходного кода

Первая точка входа в фазу генерации:

renderStart

Этот хук вызывается перед началом формирования чанков. Он позволяет подготовить состояние, необходимое для генерации кода.

Далее Rollup начинает формировать чанки и для каждого из них последовательно вызывает набор хуков.


renderChunk

Хук renderChunk вызывается для каждого создаваемого чанка. Он получает уже сгенерированный код и может его модифицировать.

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


augmentChunkHash

Этот хук влияет на хеш чанка. Он вызывается перед окончательной фиксацией идентификатора чанка и используется для изменения его стабильности при кешировании.

Порядок вызова связан с вычислением итогового состояния чанка, поэтому любые изменения здесь влияют на финальный output.


generateBundle

Один из самых важных хуков выходной фазы. Он вызывается после того, как все чанки сформированы, но до записи на диск.

В отличие от renderChunk, этот хук получает доступ ко всему бандлу сразу. Плагины могут:

  • добавлять новые файлы
  • удалять существующие
  • изменять содержимое ассетов
  • переименовывать выходные файлы

Порядок вызова generateBundle зависит от порядка подключения плагинов, но выполняется один раз на весь бандл.


writeBundle

После того как все файлы записаны, вызывается writeBundle. На этом этапе изменения в бандле уже невозможны, и хук используется для пост-обработки: публикации, уведомлений, очистки временных данных.


Особенности порядка вызова хуков

Порядок в Rollup определяется несколькими принципами:

  1. Фазовая изоляция — build hooks никогда не пересекаются с output hooks.
  2. Последовательность подключения плагинов — влияет на порядок выполнения однотипных хуков.
  3. Каскадность обработки модулей — каждый модуль проходит одинаковый pipeline.
  4. Прерывание цепочки — некоторые хуки могут остановить дальнейший вызов (например, resolveId или load при возврате значения).

Специфика асинхронных хуков

Большинство хуков поддерживают асинхронное выполнение. Это влияет на порядок не в смысле последовательности вызовов, а в смысле завершения:

  • Rollup ждёт завершения каждого хука перед переходом к следующему этапу
  • параллельность ограничена внутренними механизмами графа зависимостей
  • порядок гарантироваан только логически, но не по времени выполнения внутри async операций

Контекст вызова и повторяемость

Некоторые хуки вызываются многократно:

  • resolveId — для каждого импорта
  • load — для каждого модуля
  • transform — для каждого модуля и каждого плагина
  • renderChunk — для каждого чанка

Другие вызываются строго один раз:

  • buildStart
  • buildEnd
  • renderStart
  • writeBundle

Влияние порядка плагинов на цепочку хуков

Плагины в массиве конфигурации определяют приоритет выполнения:

  • build hooks обычно выполняются слева направо
  • некоторые output hooks — справа налево (в зависимости от типа хука и механизма композиции Rollup)

Это создаёт важную особенность: один и тот же хук может иметь разный эффект в зависимости от позиции плагина.


Связь порядка хуков с формированием графа зависимостей

Последовательность resolveId → load → transform формирует основу графа модулей. Любое изменение порядка этих операций привело бы к изменению структуры графа.

  • resolveId определяет идентичность узла
  • load определяет содержимое узла
  • transform определяет финальную форму узла перед анализом зависимостей

Эта тройка формирует детерминированный цикл обработки каждого модуля.


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

Хуки можно классифицировать по их роли в общем пайплайне:

  • разрешение модулей: resolveId
  • загрузка контента: load
  • трансформация кода: transform
  • анализ структуры: moduleParsed
  • завершение сборки: buildEnd
  • генерация чанков: renderChunk
  • управление итоговым бандлом: generateBundle, writeBundle

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