Механизм разделения кода (code splitting) в esbuild построен вокруг строго определённой модели модулей. Единственный поддерживаемый сценарий для генерации разделённых чанков — использование формата ESM (ECMAScript Modules).
Любая попытка использовать code splitting в других форматах приводит к фактическому отключению этой возможности на уровне архитектуры сборщика.
Code splitting в esbuild существует только в связке:
format: "esm"splitting: trueПри любом другом формате поведение меняется радикально:
format: "cjs" → разделение кода отключается
полностьюformat: "iife" → разделение кода невозможно
концептуальноЭто ограничение не является искусственным, оно связано с тем, как формируются графы зависимостей и как осуществляется ленивое подключение модулей.
ESM обладает встроенной поддержкой:
import()Пример базовой структуры:
import { render } from "./view.js";
export function start() {
render();
}
И динамическая граница разделения:
button.addEventListener("click", async () => {
const module = await import("./heavy.js");
module.run();
});
Именно import() создаёт естественную точку разрыва, из
которой esbuild формирует отдельный чанк.
При splitting: true esbuild выполняет следующие
шаги:
import())Пример конфигурации:
import { build } from "esbuild";
build({
entryPoints: ["src/app.js"],
outdir: "dist",
bundle: true,
format: "esm",
splitting: true
});
Модульная система CommonJS:
require()Пример:
const mod = require("./mod.js");
Проблема заключается в том, что:
Поэтому при format: "cjs" esbuild полностью отключает
splitting.
Хотя ESM поддерживается в Node.js, реализация splitting в esbuild ориентирована на:
В результате:
import-поддержки
окруженияПри включённом splitting структура выходных файлов меняется:
Пример условной структуры:
dist/
app.js
chunk-A.js
chunk-B.js
shared.js
ESM-based splitting исключает:
require() в рантаймеЛюбой код, зависящий от синхронного исполнения модулей, нарушает модель разделения.
Code splitting тесно связан с tree shaking:
Однако важное ограничение:
Единственный поддерживаемый механизм создания ленивых границ:
async function loadFeature() {
const feature = await import("./feature.js");
feature.init();
}
Любые попытки имитации splitting через:
requireне создают физических чанков при сборке.
ESM-модель позволяет esbuild автоматически выявлять:
И выносить их в shared chunk без ручной настройки.
Пример:
// entry-a.js
import { util } from "./util.js";
// entry-b.js
import { util } from "./util.js";
Результат:
util.js становится отдельным чанкомЦиклы в ESM:
При splitting это приводит к:
esbuild сохраняет корректность, но не оптимизирует циклы агрессивно, чтобы не нарушить семантику ESM.
В отличие от некоторых сборщиков, esbuild:
Единственные факторы влияния:
Выходной код требует окружения, поддерживающего:
<script type="module"> в браузереНарушение этих условий приводит к:
Splitting в esbuild можно формализовать как:
И вся архитектура code splitting опирается на одно условие:
наличие стандартизированного механизма асинхронной загрузки модулей на уровне языка