Система плагинов в Esbuild построена вокруг минималистичной, но
строго определённой модели расширения поведения сборщика. В отличие от
более сложных инструментов, где плагины имеют множество жизненных циклов
и хуков, Esbuild ограничивается компактным набором возможностей, где
центральную роль играют два ключевых элемента: name и
setup.
Эта модель обеспечивает высокую предсказуемость поведения, низкие накладные расходы и возможность глубокой интеграции с процессом бандлинга без усложнения внутренней архитектуры сборщика.
Плагин в Esbuild представляет собой объект, содержащий:
namesetupДополнительные поля не используются самим Esbuild и игнорируются системой, что подчёркивает строгую спецификацию API.
const examplePlugin = {
name: 'example-plugin',
setup(build) {
// логика плагина
}
};
Каждый плагин регистрируется в массиве plugins при
вызове esbuild.build() или
esbuild.context().
import * as esbuild from 'esbuild';
await esbuild.build({
entryPoints: ['src/index.js'],
bundle: true,
outfile: 'dist/bundle.js',
plugins: [examplePlugin]
});
Поле name задаёт уникальное имя плагина в контексте
сборки. Оно используется исключительно для:
При возникновении ошибок в хуках Esbuild включает имя плагина в стек вызовов, что позволяет быстро определить источник проблемы.
Пример типичного сообщения:
error: example-plugin: could not resolve "./module"
Таким образом, name выполняет исключительно
диагностическую функцию и не участвует в управлении жизненным циклом
сборки.
Рекомендуется использовать:
-plugin при необходимостиПримеры корректных значений:
aliasts-pathsnode-modules-polyfillcss-modulessetup — это единственная функция, через которую плагин
взаимодействует с процессом сборки. Она вызывается один раз при
инициализации сборки и получает объект build, через который
регистрируются все хуки.
setup(build) {
// регистрация логики
}
После завершения выполнения setup плагин считается
полностью инициализированным.
Объект build предоставляет API для интеграции с системой
разрешения модулей, чтения файлов и управления процессом компиляции.
Ключевые методы:
onResolveonLoadonStartonEndХотя они относятся к другим аспектам архитектуры, регистрация всех
этих хуков происходит исключительно внутри setup.
Каждый плагин инициализируется ровно один раз на каждую сборку или контекст. Это означает:
setup выполняется синхронно, даже если внутри
регистрируются асинхронные операции через хуки. Это важное архитектурное
ограничение:
setupОсновная задача setup — декларативно описать поведение
плагина через хуки.
Пример базовой структуры:
const plugin = {
name: 'demo',
setup(build) {
build.onResolve({ filter: /.*/ }, args => {
return { path: args.path, namespace: 'demo' };
});
build.onLoad({ filter: /.*/ }, args => {
return {
contents: 'export const value = 42',
loader: 'js'
};
});
}
};
Здесь setup выступает как конфигурационный слой, который
связывает логические обработчики с внутренним пайплайном Esbuild.
Так как setup выполняется один раз, он часто
используется для создания локального состояния плагина:
const cachePlugin = {
name: 'cache',
setup(build) {
const cache = new Map();
build.onLoad({ filter: /.*/ }, args => {
if (cache.has(args.path)) {
return cache.get(args.path);
}
const result = {
contents: 'export const cached = true',
loader: 'js'
};
cache.set(args.path, result);
return result;
});
}
};
Такой подход позволяет:
После завершения setup нельзя:
На этапе setup граф модулей ещё не построен,
поэтому:
Если в сборке используется несколько плагинов, их setup
вызываются последовательно в порядке массива:
plugins: [pluginA, pluginB, pluginC]
Порядок влияет на:
Хотя name и setup не взаимодействуют
напрямую, они образуют единую концепцию:
name задаёт идентичностьsetup определяет поведениеЭта связка позволяет Esbuild:
В реальных сценариях setup часто используется как точка
композиции нескольких подсистем:
const plugin = {
name: 'complex-plugin',
setup(build) {
registerResolver(build);
registerLoader(build);
registerOptimizer(build);
}
};
function registerResolver(build) {
build.onResolve({ filter: /^@app\// }, args => {
return { path: args.path.replace('@app/', 'src/') };
});
}
function registerLoader(build) {
build.onLoad({ filter: /\.txt$/ }, args => {
return {
contents: JSON.stringify({ file: args.path }),
loader: 'json'
};
});
}
function registerOptimizer(build) {
build.onEnd(result => {
// постобработка результата сборки
});
}
Такая структура демонстрирует, что setup выступает как
оркестратор, а не как место реализации всей логики.
Архитектурно плагин Esbuild можно представить как функцию конфигурации системы обработки модулей:
name — метка узла в диагностическом графеsetup — декларация правил трансформацииbuild — интерфейс подключения к пайплайнуЭта модель исключает избыточные абстракции и оставляет только минимально необходимый слой расширения функциональности.