При сборке проектов Esbuild генерирует различные типы файлов:
По умолчанию Esbuild самостоятельно формирует имена выходных файлов. Для небольших проектов этого часто достаточно, однако в крупных приложениях возникает необходимость контролировать структуру выходного каталога и формат имен файлов.
Для этих задач используются параметры:
chunkNames — настройка имен файлов для автоматически
создаваемых чанков;assetNames — настройка имен статических ресурсов.Обе опции работают через шаблоны именования и позволяют организовать предсказуемую структуру сборки.
Чанк представляет собой отдельный модульный файл, который создается при разделении кода (Code Splitting).
Например:
// main.js
import('./admin.js');
При включенном разделении кода:
await esbuild.build({
entryPoints: ['main.js'],
bundle: true,
splitting: true,
format: 'esm',
outdir: 'dist'
});
Esbuild может сформировать:
dist/
├── main.js
├── admin-ABCD1234.js
└── chunk-EFGH5678.js
Файл chunk-EFGH5678.js является автоматически созданным
чанком, содержащим общий код между несколькими модулями.
Параметр chunkNames позволяет управлять именами подобных
файлов.
chunkNamesawait esbuild.build({
entryPoints: ['src/main.js'],
bundle: true,
splitting: true,
format: 'esm',
outdir: 'dist',
chunkNames: 'chunks/[name]-[hash]'
});
Результат:
dist/
├── main.js
└── chunks/chunk-X8D4KJ2L.js
Шаблон:
chunks/[name]-[hash]
определяет:
chunkNames[name]Имя чанка.
Пример:
chunkNames: 'chunks/[name]'
Результат:
chunks/chunk.js
Обычно для автоматически создаваемых чанков Esbuild использует имя
chunk.
[hash]Уникальный хеш содержимого файла.
Пример:
chunkNames: 'chunks/[name]-[hash]'
Результат:
chunks/chunk-QWERT123.js
Хеш меняется только тогда, когда изменяется содержимое файла.
Это важный механизм для долгосрочного кэширования.
Расширение добавляется автоматически.
Например:
chunkNames: 'chunks/[name]-[hash]'
создает:
chunks/chunk-ABC123.js
Не требуется писать:
chunkNames: 'chunks/[name]-[hash].js'
Это приведет к некорректному результату:
chunk-ABC123.js.js
Часто все динамические части приложения выносят в отдельный каталог.
Пример:
chunkNames: 'js/chunks/[name]-[hash]'
Результат:
dist/
├── main.js
└── js/
└── chunks/
├── chunk-A1B2.js
├── chunk-C3D4.js
└── chunk-E5F6.js
Такая структура делает выходную директорию более понятной.
Современные браузеры активно используют кэш.
Если файл называется:
chunk.js
то после обновления приложения браузер может продолжать использовать старую версию.
Использование:
chunkNames: 'chunks/[name]-[hash]'
дает:
chunk-ABCD1234.js
После изменения кода:
chunk-EFGH5678.js
URL становится новым, поэтому браузер загружает свежий файл.
Такой подход считается стандартом для production-сборок.
Assets — это любые статические ресурсы, которые попадают в сборку.
Наиболее распространенные типы:
png
jpg
jpeg
gif
svg
webp
woff
woff2
ttf
eot
mp4
webm
Например:
import logo from './logo.png';
или
background-image: url('./bg.jpg');
После обработки Esbuild копирует такие файлы в выходной каталог.
Именно для них предназначена настройка assetNames.
assetNamesawait esbuild.build({
entryPoints: ['src/main.js'],
bundle: true,
loader: {
'.png': 'file'
},
outdir: 'dist',
assetNames: 'assets/[name]-[hash]'
});
Результат:
dist/
└── assets/
└── logo-X7A3F9.png
assetNames[name]Имя исходного файла.
Файл:
logo.png
Шаблон:
assetNames: 'assets/[name]'
Результат:
assets/logo.png
[hash]Хеш содержимого.
Пример:
assetNames: 'assets/[name]-[hash]'
Результат:
assets/logo-A7B9C2D1.png
[ext]Расширение файла.
Пример:
assetNames: 'assets/[ext]/[name]-[hash]'
Результат:
assets/png/logo-A7B9C2D1.png
Для шрифтов:
assets/woff2/font-E2F3A4.woff2
Для SVG:
assets/svg/icon-D8K2P1.svg
Одна из наиболее популярных схем.
Конфигурация:
assetNames: 'assets/[ext]/[name]-[hash]'
Структура:
dist/
└── assets/
├── png/
│ ├── logo-A1B2.png
│ └── banner-C3D4.png
│
├── svg/
│ ├── icon-E5F6.svg
│ └── menu-G7H8.svg
│
└── woff2/
└── font-I9J0.woff2
Преимущества:
Иногда расширения недостаточно.
Можно использовать разные сборочные конфигурации.
Например:
assetNames: 'images/[name]-[hash]'
Результат:
images/logo-A1B2.png
images/banner-C3D4.jpg
images/icon-E5F6.svg
Для шрифтов:
assetNames: 'fonts/[name]-[hash]'
Результат:
fonts/inter-G7H8.woff2
fonts/roboto-K1L2.ttf
Такой подход часто применяется в корпоративных проектах.
entryNames, chunkNames и
assetNamesПолная схема именования обычно выглядит так:
await esbuild.build({
entryPoints: ['src/main.js'],
bundle: true,
splitting: true,
format: 'esm',
outdir: 'dist',
entryNames: 'js/[name]-[hash]',
chunkNames: 'js/chunks/[name]-[hash]',
assetNames: 'assets/[ext]/[name]-[hash]'
});
Результат:
dist/
├── js/
│ ├── main-D4K2A1.js
│ └── chunks/
│ ├── chunk-B8F6C2.js
│ └── chunk-P3Q7R9.js
│
└── assets/
├── png/
│ └── logo-A1B2.png
│
├── svg/
│ └── icon-C3D4.svg
│
└── woff2/
└── font-E5F6.woff2
Подобная структура хорошо масштабируется даже для очень больших приложений.
Значение [hash] вычисляется на основе содержимого
файла.
Если файл не изменился:
logo-A1B2C3.png
останется тем же.
Если содержимое изменилось:
logo-X9Y8Z7.png
будет создано новое имя.
Это обеспечивает:
Для production наиболее распространена следующая конфигурация:
await esbuild.build({
entryPoints: ['src/main.js'],
bundle: true,
minify: true,
splitting: true,
format: 'esm',
outdir: 'dist',
entryNames: '[name]-[hash]',
chunkNames: 'chunks/[name]-[hash]',
assetNames: 'assets/[ext]/[name]-[hash]'
});
Она обеспечивает:
chunkNamessplittingКонфигурация:
chunkNames: 'chunks/[name]-[hash]'
не будет иметь эффекта без:
splitting: true
Поскольку чанки просто не создаются.
Code Splitting работает только для:
format: 'esm'
Конфигурация:
format: 'cjs'
не позволит использовать разделение кода.
Ошибка:
chunkNames: 'chunks/[name]-[hash].js'
Результат:
chunk-A1B2.js.js
Расширение должно добавляться самим Esbuild.
assetNamesЕсли ресурс не обрабатывается как файл:
loader: {
'.png': 'file'
}
то настройка assetNames может не применяться.
Конфигурация:
assetNames: 'assets/[name]'
создает:
assets/logo.png
После обновления содержимого имя останется прежним.
Это ухудшает работу браузерного кэша.
Для production предпочтительно:
assetNames: 'assets/[name]-[hash]'
или
assetNames: 'assets/[ext]/[name]-[hash]'
chunkNames: '[name]-[hash]'
assetNames: '[name]-[hash]'
chunkNames: 'chunks/[name]-[hash]'
assetNames: 'assets/[ext]/[name]-[hash]'
entryNames: 'js/[name]-[hash]'
chunkNames: 'js/chunks/[name]-[hash]'
assetNames: 'assets/[ext]/[name]-[hash]'
Структура получается логичной, масштабируемой и удобной для сопровождения, а использование хешей обеспечивает корректную работу механизмов кэширования в production-окружении.