Bundling в Esbuild основан на построении графа зависимостей и последующей трансформации этого графа в оптимизированный набор выходных файлов. Каждый импорт в коде рассматривается как ребро графа, а каждый модуль — как узел. Входная точка запускает рекурсивный анализ импортов, после чего формируется полная структура зависимостей.
Ключевая особенность подхода Esbuild заключается в том, что вся работа по построению и оптимизации графа выполняется на уровне одного прохода компиляции, без разделения на множество фаз, характерных для более медленных инструментов.
Основные этапы процесса:
Входные точки задают стартовую область анализа. Esbuild поддерживает как одиночный entry point, так и массив точек входа для мультибандлинга.
esbuild src/index.js --bundle --outfile=dist/bundle.js
При анализе входного файла Esbuild:
import и requireПример структуры:
index.js
├── utils.js
│ └── format.js
└── api.js
Каждый файл становится узлом, а зависимости формируют связи.
При включённой опции --bundle Esbuild выполняет
инлайнинг модулей. Это означает, что содержимое зависимостей
встраивается в итоговый файл.
esbuild src/index.js --bundle --outfile=dist/app.js
Результат представляет собой единый JavaScript-файл, где:
Каждый модуль в процессе bundling помещается в изолированную область видимости. Esbuild использует функции-обёртки для предотвращения конфликтов переменных.
Упрощённая модель:
(() => {
// module A
const value = 42;
})();
(() => {
// module B
const value = 100;
})();
Такая модель позволяет сохранять независимость модулей при объединении.
Esbuild трансформирует ESM-синтаксис в внутреннюю систему ссылок.
Исходный код:
// a.js
export const a = 1;
// b.js
import { a } from './a.js';
export const b = a + 1;
После bundling логика преобразуется в единое пространство имён, где зависимости становятся прямыми ссылками:
Это позволяет избежать выполнения дополнительных runtime-обёрток.
Esbuild выполняет удаление неиспользуемого кода на этапе анализа графа.
Удаляются:
Пример:
export const used = 1;
export const unused = 2;
Если unused нигде не импортируется, он исключается из
итогового бандла.
Bundling в Esbuild поддерживает несколько форматов:
Пример генерации IIFE-бандла:
esbuild src/index.js --bundle --format=iife --outfile=dist/app.js
IIFE-формат часто используется для браузерных приложений без модульной системы.
Хотя базовый bundling предполагает один файл, Esbuild поддерживает разбиение на чанки при наличии динамических импортов.
import('./module.js').then(m => {
m.run();
});
В этом случае:
Опция external исключает модули из bundling.
esbuild src/index.js --bundle --external:react
Такой модуль:
Это важно при работе с CDN или системными зависимостями.
Bundling часто комбинируется с минификацией:
esbuild src/index.js --bundle --minify --outfile=dist/app.js
Минификация включает:
Пример трансформации:
const result = 1 + 2;
становится:
const r=3;
Esbuild генерирует sourcemaps, связывающие итоговый бандл с исходными модулями.
esbuild src/index.js --bundle --sourcemap --outfile=dist/app.js
Это позволяет:
Esbuild может генерировать метафайл, описывающий процесс bundling:
esbuild src/index.js --bundle --metafile=meta.json --outfile=dist/app.js
В метафайле содержится:
Эти данные используются для анализа производительности сборки.
После bundling код выполняется как единый скрипт. При этом:
Пример циклической структуры:
// a.js
import { b } from './b.js';
export const a = 1;
// b.js
import { a } from './a.js';
export const b = 2;
Esbuild обеспечивает корректную обработку через отложенное связывание экспортов.
В процессе объединения применяются дополнительные оптимизации:
Эти операции уменьшают итоговый размер и повышают скорость выполнения.
При использовании режима наблюдения Esbuild не пересобирает граф полностью. Вместо этого:
esbuild src/index.js --bundle --watch
Это существенно ускоряет процесс разработки при больших проектах.