Выбор формата в зависимости от окружения

В esbuild выбор формата бандла определяется тем, где и как будет выполняться итоговый JavaScript-код. Один и тот же исходный код может требовать разных представлений в зависимости от среды: браузер без сборщика, Node.js с CommonJS-модулями, современная ESM-инфраструктура, серверные рантаймы или публикация библиотеки. Неправильный выбор формата приводит к несовместимостям импорта, ошибкам загрузки модулей и избыточному полифиллингу.

Основные форматы вывода esbuild

esbuild поддерживает несколько ключевых форматов, задаваемых через опцию format:

  • esm — ECMAScript Modules
  • cjs — CommonJS
  • iife — Immediately Invoked Function Expression
  • umd — универсальный формат (в esbuild поддерживается ограниченно и чаще заменяется связкой cjs/iife)

Каждый формат решает конкретный класс задач и предполагает определённую среду выполнения.


ESM (ECMAScript Modules) и современные окружения

Формат esm является наиболее универсальным для современных сборок и инфраструктур.

esbuild input.js --format=esm

Особенности ESM

  • Использует import и export
  • Поддерживает статический анализ зависимостей
  • Позволяет tree-shaking на уровне модулей
  • Совместим с браузерами (через <script type="module">)
  • Нативно поддерживается Node.js (при "type": "module" или .mjs)

Когда применять ESM

ESM оптимален в случаях:

  • Разработка библиотек с современной архитектурой
  • Приложения, работающие через Vite, Snowpack, modern Webpack/Rollup-пайплайны
  • Серверные приложения на Node.js с включённым ESM
  • Код, требующий tree-shaking и минимизации конечного размера

Ограничения

  • Не всегда совместим со старыми версиями Node.js
  • Требует корректной настройки package.json
  • В браузере требует модульной загрузки (CORS, strict mode)

CommonJS (CJS) и Node.js-экосистема

Формат cjs ориентирован на традиционную Node.js-модель.

esbuild input.js --format=cjs

Особенности CJS

  • Использует require() и module.exports
  • Динамическая система импорта
  • Поддерживается всеми версиями Node.js без дополнительной настройки

Когда применять CJS

  • Библиотеки для старых проектов Node.js
  • CLI-инструменты
  • Серверный код без ESM-инфраструктуры
  • Плагины и расширения для экосистем, ожидающих require

Поведенческие особенности

  • Нет полноценного tree-shaking
  • Модули загружаются синхронно
  • Возможны различия в поведении циклических зависимостей

IIFE и браузерные сценарии без сборщика

Формат iife предназначен для выполнения кода прямо в браузере без системы модулей.

esbuild input.js --format=iife --global-name=MyLib

Структура IIFE

Код оборачивается в функцию, которая выполняется сразу:

var MyLib = (() => {
  // внутренний код
  return exportedAPI;
})();

Когда применять IIFE

  • Подключение через <script> без bundler-инфраструктуры
  • Встраивание библиотек в legacy-проекты
  • Плагины для CMS или браузерных расширений
  • Минимальные утилиты без модульной системы

Особенности

  • Требует globalName для экспорта
  • Отсутствует система импортов
  • Все зависимости должны быть встроены в один файл

Выбор формата в зависимости от типа проекта

Браузерное приложение с современным стеком

Предпочтительный формат — esm.

Причины:

  • Поддержка модульной загрузки
  • Возможность code splitting
  • Совместимость с Vite, Snowpack, esbuild-dev-server
  • Оптимизация загрузки через HTTP/2

Библиотека для npm

Часто требуется мультиформатная сборка:

  • esm для современных сборщиков
  • cjs для Node.js-совместимости
  • иногда iife для CDN

Типичная стратегия:

  • dist/index.mjs — ESM
  • dist/index.cjs — CommonJS
  • dist/index.global.js — IIFE

Такой подход обеспечивает максимальную совместимость без потери производительности в целевых окружениях.


Серверное приложение Node.js

Выбор зависит от конфигурации проекта:

Современный Node.js (ESM включён)

  • esm предпочтителен
  • используется import

Старые проекты

  • cjs остаётся стандартом
  • гарантирует отсутствие проблем с загрузкой модулей

Публикация через CDN

Для прямого подключения в браузере:

  • используется iife
  • обязательен globalName

Причина: отсутствие модульного загрузчика в среде исполнения.


Влияние параметра platform

esbuild использует параметр platform, который тесно связан с выбором формата:

  • browser — оптимизация под браузер
  • node — оптимизация под Node.js
  • neutral — универсальная сборка без специфики среды

Взаимодействие format и platform

  • platform=browser + format=esm — современный frontend
  • platform=node + format=cjs — классический backend
  • platform=browser + format=iife — legacy браузерная доставка

Совместимость с package.json exports

В современных npm-пакетах формат напрямую отражается в поле exports:

{
  "exports": {
    "import": "./dist/index.mjs",
    "require": "./dist/index.cjs"
  }
}

Логика выбора

  • import → ESM
  • require → CJS
  • fallback → iife (редко)

esbuild часто используется для генерации всех целевых файлов одновременно.


Code splitting и влияние формата

Code splitting поддерживается только в ESM:

  • динамические import()
  • разделение чанков
  • асинхронная загрузка

В cjs и iife:

  • код объединяется в единый бандл
  • отсутствует разделение по чанкам

Это делает ESM единственным форматом для современных SPA с ленивой загрузкой модулей.


Оптимизация под целевое окружение через target

Хотя format определяет модульную систему, target определяет синтаксис:

  • es2015, es2020, esnext
  • node12, node18, chrome90 и т.д.

Взаимосвязь

  • ESM + высокий target → минимальная трансформация
  • CJS + низкий target → максимальная совместимость
  • IIFE + низкий target → поддержка старых браузеров

Типовые комбинации конфигурации

Современная библиотека

  • format: esm
  • platform: neutral
  • target: es2018+

Node.js пакет

  • format: cjs
  • platform: node
  • target: node16+

Универсальная библиотека

  • format: esm + cjs + iife
  • multiple outputs
  • отдельные entry points

Ограничения и особенности реальных окружений

Браузеры

  • ESM требует type="module"
  • IIFE не поддерживает import/export
  • CJS не поддерживается

Node.js

  • CJS работает всегда
  • ESM требует настройки
  • IIFE не используется

Bundler-среды

  • предпочтение ESM
  • возможен tree-shaking
  • совместимость с динамическими импортами

Практическая модель выбора формата

Логика выбора формата может рассматриваться как сопоставление двух факторов:

  • система модулей окружения
  • способ доставки кода

Матрица соответствия

  • Browser + без bundler → IIFE
  • Browser + bundler → ESM
  • Node legacy → CJS
  • Node modern → ESM
  • CDN distribution → IIFE
  • Library distribution → ESM + CJS (часто дополнительно IIFE)

Поведение зависимостей при разных форматах

ESM

  • зависимости анализируются статически
  • возможна оптимизация неиспользуемых импортов

CJS

  • зависимости вычисляются динамически
  • сложнее для статического анализа

IIFE

  • все зависимости уже встроены
  • отсутствует механизм внешних импортов

Итоговая модель понимания форматов esbuild

Формат вывода в esbuild является не просто опцией сборки, а механизмом адаптации одного и того же исходного кода под разные модели исполнения JavaScript. Различия между ESM, CJS и IIFE определяют:

  • способ загрузки модулей
  • поведение зависимостей
  • возможности оптимизации
  • совместимость с инфраструктурой

Выбор формата всегда определяется не синтаксисом исходного кода, а требованиями среды, в которой этот код будет выполняться.