В системе плагинов Esbuild ключевую роль играет механизм хуков, через
которые расширяется процесс сборки. Каждый хук возвращает объект
результата или undefined, и именно возвращаемые значения
определяют поведение пайплайна, порядок обработки модулей, а также
приоритет между несколькими обработчиками одного и того же события.
Хуки Esbuild работают по принципу цепочки обработчиков. Для каждого события (разрешение пути, загрузка модуля, трансформация кода) может быть зарегистрировано несколько функций. Каждая из них может:
undefined, передавая управление следующему
обработчикуКлючевое правило: первый хук, вернувший значимый результат, может прервать дальнейшую цепочку обработки.
onResolve: приоритеты и возврат значенийХук onResolve используется для определения того, как
Esbuild должен интерпретировать импортируемый путь:
{
path: string,
namespace?: string,
external?: boolean,
sideEffects?: boolean,
pluginData?: any,
watchFiles?: string[]
}
undefinedЕсли хук возвращает undefined, Esbuild продолжает искать
следующий подходящий onResolve, зарегистрированный для
данного фильтра. Это создает естественный механизм приоритетов: порядок
регистрации имеет значение.
Если один из хуков возвращает объект с path, цепочка
обработки для данного запроса может быть завершена, если не существует
более специфичных условий или namespace-правил.
Пример поведения:
undefined{ path: '...' }Приоритет onResolve определяется не только порядком
регистрации, но и точностью фильтра:
filter имеет приоритет над общимnamespace перекрывает общий
namespacesuffix и prefix повышает
приоритетТаким образом, фактическая система приоритетов является комбинацией:
специфичность > порядок регистрации > namespace
external в
возвратеЕсли хук возвращает:
{ external: true }
то модуль исключается из бандла независимо от других обработчиков. Это один из самых сильных приоритетов в системе.
onLoad: конкуренция источников загрузки{
contents: string | Uint8Array,
loader?: string,
resolveDir?: string,
pluginData?: any,
watchFiles?: string[]
}
onLoad вызывается после успешного
onResolve. Здесь также действует цепочка:
contents, завершает загрузкуundefined, выполняется следующий
onLoadЕсли модуль попадает в определённый namespace, он будет
обрабатываться только хуками, зарегистрированными для этого
namespace.
Это создаёт строгую изоляцию:
namespace: "file" — стандартные файлыnamespace: "http" — удалённые ресурсыХуки разных namespace не конкурируют между собой, что формирует отдельные приоритетные контуры.
Если несколько хуков обрабатывают один файл, приоритет определяется следующим образом:
Первый хук, вернувший contents, блокирует остальные.
onLoad и последующая стадияПосле onLoad начинается этап трансформации (внутренний
или через onTransform, если используется косвенная логика
плагина).
Хотя Esbuild не предоставляет классический onTransform
как основной API, плагины часто реализуют трансформацию через:
contents в onLoadpluginData для передачи состояния между
хукамиЕсли несколько хуков участвуют в изменении содержимого, возникает правило:
contents определяет итоговое
значениеpluginDataЭто создаёт скрытый приоритет: поздние хуки имеют доминирующее влияние на содержимое.
pluginData
как механизм приоритетного состоянияpluginData не влияет напрямую на приоритет выполнения,
но используется для его эмуляции.
onResolve и onLoadТипичный паттерн:
pluginDataЭто создаёт логический приоритет, не зависящий от порядка регистрации.
Когда несколько плагинов обрабатывают один и тот же модуль, возможны три сценария:
Самый простой случай:
Более точный filter перекрывает общий:
/\.js$/ проигрывает /src\/.*\.js$/Если namespace различается, конкуренции нет. Это жёсткое разделение контекстов.
onResolve:path — изменяет маршрут модуляexternal — исключает модульnamespace — перенаправляет в другой контекстwatchFiles — добавляет зависимости для наблюденияКаждое из этих полей может изменить приоритет всей цепочки сборки.
onLoad:contents — финальный источник данных модуляloader — определяет тип интерпретации (js, json, text и
др.)resolveDir — влияет на дальнейшие import
внутри файлаПомимо явных правил существует ряд неочевидных приоритетов:
Встроенные загрузчики имеют самый низкий приоритет, но являются fallback-слоем.
Ранние плагины часто перехватывают поток до стандартной обработки.
Изолированные контексты практически не конфликтуют, но имеют абсолютный приоритет внутри своего пространства.
Если хук возвращает разные поля, важно понимать:
Это означает, что:
каждый хук должен возвращать полностью консистентный результат
Если хук выбрасывает исключение:
В отличие от return undefined, исключение не является
“мягким” отказом и имеет более высокий приоритет влияния на
пайплайн.
Система приоритетов Esbuild в хуках формируется из нескольких слоёв:
Эта многослойная модель делает поведение хуков предсказуемым при строгом соблюдении структуры, но чувствительным к порядку и деталям реализации.