При включённом разделении кода (splitting: true при
сборке в формате ESM) esbuild строит ориентированный граф модулей, в
котором каждый файл становится вершиной, а импорт — ребром. На основе
этого графа формируются чанки — наборы модулей, объединённые в отдельные
выходные файлы.
Чанк в esbuild — это не произвольная группировка, а результат анализа достижимости модулей и точек входа. Если несколько entry-points используют одни и те же модули, такие модули могут быть вынесены в отдельные shared-chunks.
Cross-chunk dependencies возникают тогда, когда один чанк импортирует модуль, который уже был частично или полностью включён в другой чанк, либо когда зависимости между чанками образуют перекрёстные ссылки.
Такая ситуация появляется в нескольких типичных случаях:
Cross-chunk dependency в esbuild — это не просто импорт, а граница между двумя результатами бандлинга, где один итоговый файл зависит от другого.
При анализе модулей esbuild выполняет несколько этапов:
Cross-chunk связь формируется, когда модуль, находящийся в одном чанке, требуется другому чанку, но не может быть локально включён без нарушения принципа единственного экземпляра модуля в ESM-графе.
Cross-chunk dependencies напрямую влияют на размер сборки через несколько механизмов.
Каждый чанк в ESM-сборке содержит:
При росте числа cross-chunk связей увеличивается количество таких связей и, соответственно, объём служебного кода. В больших приложениях это становится заметным фактором.
esbuild старается выносить повторяющиеся модули в shared chunks. Однако cross-chunk зависимости могут усложнять этот процесс:
Это приводит к росту общего числа файлов, даже если суммарный объём кода остаётся близким.
При интенсивных cross-chunk зависимостях возникает фрагментация:
Даже при HTTP/2 или HTTP/3 большое количество чанков увеличивает overhead загрузки.
Tree-shaking в esbuild выполняется на уровне модулей, но cross-chunk зависимости могут ограничивать его эффективность.
Если экспорт используется через цепочку cross-chunk импортов, анализ побочных эффектов становится более консервативным. В результате:
Barrel-файлы (index.ts, index.js) часто
усиливают эффект cross-chunk зависимостей:
// a.ts
export const A = 1;
// index.ts
export * from "./a";
// entry.ts
import { A } from "./index";
В таком сценарии модуль a.ts может оказаться в отдельном
чанке, а index.ts станет промежуточным узлом, увеличивающим
количество межчанковых ссылок. Это добавляет дополнительные слои
индирекции и снижает предсказуемость tree-shaking.
При корректной работе esbuild избегает физического дублирования модулей между чанками. Однако cross-chunk dependencies влияют на то, как именно формируются границы:
В редких случаях, при неоднозначных графах, может появляться эффект избыточного дробления, когда один и тот же функциональный слой представлен несколькими маленькими чанками вместо одного крупного shared-модуля.
import() является ключевым механизмом, который формирует
границы чанков. Каждый динамический импорт создаёт потенциальный новый
чанк:
button.oncl ick = async () => {
const module = await import("./feature.js");
};
Если feature.js зависит от модулей, используемых и в
основном бандле, и в других ленивых чанках, возникает сеть cross-chunk
зависимостей.
Это приводит к:
Циклы в графе модулей усложняют разбиение на чанки. В ESM циклы допустимы, но при код-splitting они приводят к дополнительным связям между чанками.
Типичный сценарий:
В результате esbuild вынужден сохранять структуру графа, добавляя дополнительные ссылки между чанками, что увеличивает размер служебных данных и усложняет загрузку.
Особенно заметный вклад в cross-chunk dependencies дают промежуточные слои:
Такие модули становятся «хабами», через которые проходят зависимости из разных частей приложения. При разбиении на чанки они оказываются в shared слоях, увеличивая плотность cross-chunk связей.
esbuild может генерировать метафайл (metafile), который
отражает структуру чанков и зависимостей между ними. В нём cross-chunk
зависимости видны как связи между outputs.
Анализ таких данных позволяет выявлять:
Высокая связность обычно коррелирует с увеличением итогового размера бандла и ухудшением его загрузочной структуры.
Некоторые структуры кода усиливают cross-chunk зависимости:
В таких случаях граф становится плотным, а чанки — сильно взаимосвязанными, что увеличивает общий объём связующего кода и количество файлов в сборке.
При формировании output esbuild стремится:
Однако cross-chunk dependencies задают структурные ограничения, при которых оптимизация размера конкурирует с необходимостью сохранить корректный порядок загрузки и независимость чанков.