Система плагинов в esbuild построена вокруг событийной модели, где
ключевыми точками расширения выступают onResolve,
onLoad, onStart, onEnd и
onTransform. Каждый из этих хуков внедряется в основной
конвейер сборки, который реализован на Go, тогда как плагины исполняются
в JavaScript через мост взаимодействия между средами.
Именно этот мост становится первым источником накладных расходов: каждое попадание модуля под правило плагина требует сериализации контекста, передачи данных в JS-рантайм и возврата результата обратно в Go-ядро.
Процесс сборки в esbuild можно упростить до цепочки:
resolve)load)transform)Плагины подключаются в эти этапы через регистрацию обработчиков:
onResolve({ filter, namespace })onLoad({ filter, namespace })onTransform({ filter })Каждый обработчик не является изолированным: он встраивается в глобальный pipeline и начинает участвовать в проверке каждого модуля, проходящего через соответствующую стадию.
Ключевой момент производительности — это фильтрация.
Каждый filter в esbuild компилируется в регулярное
выражение. При большом количестве файлов:
Использование широких шаблонов вроде:
filter: /.*/
превращает плагин в глобальный обработчик всех модулей, что приводит к деградации производительности пропорционально размеру графа зависимостей.
onResolve вызывается для каждого импорта, который
проходит этап разрешения.
Типичные причины замедления:
Плагин с фильтром по типу:
filter: /.*/
фактически превращается в обработчик всего dependency graph.
Любая логика внутри onResolve выполняется синхронно:
Каждый такой вызов блокирует поток обработки модуля.
Без кеша результат разрешения одного и того же модуля пересчитывается многократно, особенно при повторных импортных цепочках.
onLoad отвечает за получение содержимого модуля. На этом
этапе:
Если плагин читает файлы напрямую через fs.readFileSync,
это добавляет синхронную задержку в основной поток сборки.
esbuild уже умеет эффективно читать файлы. Переопределение этого поведения без необходимости создаёт лишний I/O overhead.
Любые операции типа:
onLoadрезко увеличивают стоимость каждого модуля.
onTransform применяется к содержимому модулей после
загрузки.
Проблема этого этапа заключается в том, что:
При нескольких плагинах с onTransform формируется
цепочка трансформаций:
код → плагин A → плагин B → плагин C → esbuild transform → output
Каждое звено увеличивает latency линейно, а иногда и сверхлинейно из-за повторного парсинга AST.
Рост количества подключённых плагинов влияет не только суммарно, но и мультипликативно.
При N плагинах и M модулях сложность может приближаться к:
O(N × M)
Использование namespace позволяет существенно сократить
число срабатываний плагина.
Без namespace:
С namespace:
Это снижает количество вызовов onLoad и
onResolve, особенно в проектах с виртуальными модулями.
Оптимизация filter — ключевой элемент производительности плагинов.
Пример более эффективного подхода:
filter: /^src\/components\//
Плохой вариант:
filter: /components/
Во втором случае совпадения происходят на большом числе путей, включая нежелательные.
Хотя esbuild поддерживает асинхронные плагины, неправильное использование приводит к деградации:
Особенно критично:
Кеширование в плагинах уменьшает повторные вычисления в
onResolve и onLoad.
Типичные стратегии:
const cache = new Map();
Ключ: path.resolve(importPath)
Сохранение результата AST или строки кода для повторного использования
Эффект кеширования особенно заметен при больших монорепозиториях, где одни и те же модули импортируются многократно.
Плагины в esbuild не изолированы.
Проблемы возникают при:
onResolve правилахpath без контроляЭто может приводить к:
Ключевой архитектурный фактор esbuild — ядро на Go и плагины на JavaScript.
Каждый вызов плагина включает:
Даже минимальная логика в плагине добавляет измеримый overhead, особенно при тысячах модулей.
Плагины, обрабатывающие всё без фильтрации.
AST-анализ без ограничений.
Любые HTTP-запросы в процессе сборки.
Несколько плагинов, каждый из которых трансформирует один и тот же код.
В проектах с тысячами модулей:
Основная проблема проявляется не в отдельных плагинах, а в их совокупном влиянии на общий pipeline обработки модулей.