В экосистеме esbuild терминология «bundle» и «prebundle» не является
строго формализованными режимами CLI с отдельными флагами, однако
отражает два принципиально разных подхода к обработке модулей: полная
сборка приложения и предварительная упаковка зависимостей для ускорения
последующих этапов работы.
Разделение этих подходов особенно заметно в современных
инструментальных цепочках (Vite, Snowpack-подобные архитектуры,
кастомные dev-server решения), где esbuild используется как
низкоуровневый движок трансформации и компоновки модулей.
Бандлинг (bundle):
полная сборка графа модулей
Базовая модель
Режим bundle подразумевает построение полного графа зависимостей от
точки входа и последующую агрегацию всех модулей в один или несколько
выходных файлов.
Основная идея:
- анализируется entry point
- рекурсивно обходятся import/require зависимости
- все модули включаются в единый граф
- применяется трансформация (JSX, TypeScript, ESM → CJS при
необходимости)
- выполняется минификация и tree-shaking (если включено)
- формируется финальный бандл
Поведение esbuild в режиме
bundle
При использовании esbuild.build с параметром
bundle: true происходит:
- объединение локальных модулей проекта
- инлайнинг зависимостей (если не marked as external)
- устранение неиспользуемого кода (dead code elimination)
- оптимизация импортов
Пример конфигурации:
import * as esbuild from 'esbuild';
esbuild.build({
entryPoints: ['src/index.js'],
bundle: true,
outfile: 'dist/app.js',
platform: 'browser',
format: 'esm',
});
Особенности поведения
1. Полная инклюзия
зависимостей
Все зависимости, не отмеченные как external, включаются в итоговый
файл.
2. Единый граф оптимизации
Tree-shaking и minification работают на уровне всего графа, а не
отдельных пакетов.
3. Более высокая стоимость
сборки
При росте проекта увеличивается время:
- обхода графа
- трансформации модулей
- генерации итогового кода
4. Упрощённый runtime
На выходе получается минимальное количество файлов, часто один
бандл.
Prebundle
(предварительная упаковка зависимостей)
Концептуальная модель
Prebundle — это этап, при котором зависимости подготавливаются
отдельно от основного кода приложения. Цель — ускорить последующую
сборку и/или запуск dev-сервера за счёт кэширования и упрощения
обработки сторонних модулей.
В контексте esbuild это чаще всего:
- предварительная компиляция
node_modules
- преобразование CommonJS/ESM пакетов в оптимизированный формат
- кэширование результатов трансформации
Типичный сценарий
Prebundle используется в следующих случаях:
- dev server (например, Vite)
- ускорение холодного старта
- уменьшение количества ESM запросов в браузере
- стабилизация несовместимых пакетов
Отличие prebundle от bundle
1. Область обработки
Bundle:
- проект + зависимости
- единый граф
Prebundle:
- только зависимости (обычно node_modules)
- приложение остаётся отдельно
2. Время выполнения
Bundle:
- дороже при каждом изменении входа
- пересборка может затрагивать весь граф
Prebundle:
- дорогая операция выполняется один раз
- далее используется кэш
3. Частота выполнения
Bundle:
- выполняется на каждый билд (или инкрементально)
Prebundle:
выполняется редко:
- при установке зависимостей
- при изменении lockfile
- при обновлении пакетов
4. Роль в архитектуре
Bundle:
- финальный шаг production build
Prebundle:
- промежуточный шаг оптимизации dev-окружения
Технические различия
обработки модулей
Работа с ESM и CJS
Bundle
- преобразует смешанный граф модулей
- может инлайнить CommonJS через трансформацию
- решает interop на уровне всего приложения
Prebundle
- нормализует зависимости до единого формата
- часто приводит CJS к ESM-совместимому виду
- фиксирует экспортную структуру для последующего использования
Кэширование
Bundle
- кэширование ограничено внутренними механизмами incremental
build
- при изменении entry point часто пересобирается значительная часть
графа
Prebundle
- агрессивное кэширование результатов трансформации
- повторное использование уже собранных модулей без повторного
парсинга
Обработка внешних пакетов
Bundle
- зависимости включаются внутрь бандла
- возможна настройка
external
Prebundle
- все пакеты рассматриваются как отдельные единицы
- часто формируются оптимизированные ESM-блоки
Сценарии применения bundle
Production-сборка
Основное назначение bundle-режима — создание финального
артефакта:
- минимизация количества HTTP-запросов
- агрегация кода
- оптимизация загрузки
Пример:
esbuild.build({
entryPoints: ['src/main.ts'],
bundle: true,
minify: true,
sourcemap: true,
outfile: 'dist/main.js',
});
Библиотеки
Bundle используется для:
- генерации UMD/CJS/ESM пакетов
- создания распределяемых артефактов
Особенность:
- часто исключаются peerDependencies через external
Сценарии применения
prebundle
Dev-сервер
Prebundle особенно важен в архитектуре dev-серверов:
- ускоряет cold start
- снижает нагрузку на resolver
- уменьшает число преобразований в runtime
Оптимизация node_modules
Типичный кейс:
- десятки/сотни зависимостей
- множество CJS-пакетов
- необходимость привести их к ESM
Prebundle превращает их в:
- оптимизированные ESM-модули
- кэшированные артефакты
Устранение проблем
совместимости
Некоторые пакеты:
- используют dynamic require
- имеют нестандартные exports
- содержат смешанные форматы
Prebundle решает это через:
- предварительную трансформацию
- стабилизацию экспортов
Производительность:
сравнительный анализ
Время холодного старта
- Bundle: зависит от размера всего графа приложения
- Prebundle: зависит только от количества зависимостей
Prebundle обычно значительно быстрее при повторных запусках
dev-сервера.
Инкрементальные изменения
Bundle:
- изменение одного модуля может затронуть цепочку зависимостей
Prebundle:
- изменения приложения не затрагивают уже обработанные
зависимости
Узкие места
Bundle:
- глубокие dependency chains
- большие monorepo
- тяжелые трансформации (TS + JSX)
Prebundle:
- первичная обработка node_modules
- большие библиотеки с множеством subpath exports
Влияние на архитектуру
проекта
Разделение ответственности
Bundle и prebundle формируют двухуровневую модель:
- уровень зависимостей (prebundle)
- уровень приложения (bundle)
Это позволяет:
- стабилизировать внешние библиотеки
- ускорить итерации разработки
- снизить стоимость повторных сборок
Изоляция зависимостей
Prebundle фактически фиксирует:
- структуру экспортов
- формат модулей
- оптимизированные входные точки
Bundle работает поверх уже стабилизированного слоя.
Vite-подобная модель
В современных сборщиках:
- prebundle выполняется через esbuild optimizeDeps
- bundle применяется только для production
Поток выглядит так:
- анализ зависимостей
- prebundle node_modules
- dev server использует кэшированные модули
- production build запускает полный bundle
Monorepo
В монорепозиториях:
- prebundle может быть ограничен workspace зависимостями
- bundle объединяет локальные пакеты
Ограничения подходов
Bundle
- рост времени сборки при масштабировании проекта
- высокая чувствительность к изменениям в графе
- необходимость тонкой настройки external
Prebundle
- дополнительный этап в pipeline
- возможная рассинхронизация кэша
- необходимость контроля invalidation при обновлениях
зависимостей
Сравнительная модель
поведения
Bundle: динамическая сборка всего приложения
Prebundle: статическая подготовка зависимостей
Bundle: оптимизация конечного артефакта
Prebundle: оптимизация промежуточного слоя
Bundle: ориентирован на результат
Prebundle: ориентирован на инфраструктуру разработки