Ассеты: CSS и JS
Движок собирает CSS и JS в бандлы по зависимостям блоков. Имя каждого бандла включает content-hash, поэтому файлы могут храниться в кэше длительное время. Манифест хранит размеры и хэши — его использует команда публикации.
Файлы из внешних репозиториев
Стадия assets копирует файлы PDF, ZIP и INI из объявленных внешних репозиториев в корень артефакта, сохраняя имя файла. Если найдено несколько файлов с одинаковым именем, сборка завершается ошибкой. Чтобы явно выбрать источник, задайте в config/site.json поле assetSources: укажите имя файла в артефакте и точный путь к источнику относительно корня проекта-потребителя:
{
"assetSources": {
"manual.pdf": "external/docs/manual.pdf"
}
}
По этому пути должен находиться кандидат с указанным именем. Если файл отсутствует или путь не совпадает с найденным источником, сборка завершится ошибкой. Для уникальных имён настройка не нужна. Для MP4 действуют те же правила коллизий и assetSources, но в выходное имя входит хэш, рассчитанный поточным чтением файла.
Бандлы по зависимостям
Бандл собирает стили и скрипты блоков из своей декларации; автоматически по содержимому страницы он не формируется. Если блок входит в зависимости, его block.css и block.js попадают в бандл. Блоки вне декларации не включаются.
Имя бандла берётся из site.json → bundles. Например, при "bundles": ["docs-layout"] движок читает docs-layout.bemdecl.js и собирает по этой декларации бандл docs-layout.
Стадии собирают все бандлы из site.json. Стандартный root подключает все переданные CSS и JS на каждой странице. Чтобы выбирать бандлы для отдельных страниц, задайте это в собственном обработчике документа или переопределённом шаблоне root.
CSS
Lightning CSS встраивает @import, расставляет префиксы, обрабатывает вложенные правила и минифицирует CSS. После этого собственный код стадии nuckty переписывает url() по .build/image-mapping.json и встраивает подходящие SVG.
Результат — файл <hash>.css в каталоге css/:
site/css/a1b2c3d4.css
Хэш в имени — content-hash: первые 16 шестнадцатеричных символов MD5 от содержимого файла (тот же алгоритм, что и в манифесте). Имя зависит от содержимого, поэтому файл можно хранить в кэше длительное время: при изменении меняется и хэш. В примерах на этой странице хэши сокращены для наглядности.
JS
esbuild собирает JS в формате IIFE, ориентируется на ES2018 и минифицирует код. Результат — файл <hash>.js в каталоге js/:
site/js/e5f6a7b8.js
Имя бандла JS также зависит от content-hash.
Переписывание ссылок на изображения
В CSS изображения подключают через url(...). При сборке движок переписывает эти ссылки по image-mapping.json: заменяет логический путь путём к файлу с хэшем в имени. Тот же image-mapping.json использует и мост Markdown, поэтому имена в CSS и в HTML всегда согласованы.
/* исходник */
.icon { background: url(images/icon.png); }
/* результат */
.icon{background:url(/_i9f8e7d6a1b2c3d4)}
manifest.json
Манифест хранит размеры и хэши файлов артефакта, кроме самого manifest.json. Сканирование выполняется после записи .htaccess. Его использует расширение публикации, чтобы сравнить манифест с файлами на сервере: загружается только то, что изменилось.
{
"css/a1b2c3d4.css": { "size": 12450, "hash": "a1b2c3d4e5f6a7b8" },
"js/e5f6a7b8.js": { "size": 8920, "hash": "e5f6a7b8c1d2e3f4" },
"html/how_bemjson.html": { "size": 3200, "hash": "..." }
}
Хэш — первые 16 шестнадцатеричных символов MD5 от всего содержимого файла, в том числе крупных бинарных файлов ZIP и PDF. Ключи отсортированы, поэтому манифест детерминирован.
Неизменяемый кэш
Конфигурация задаёт файлам с хешем в имени длительный срок хранения (10 лет) и Cache-Control: public, immutable. HTML отдаётся с no-cache: его можно хранить, но перед повторным использованием требуется проверка актуальности. Подробнее — конфигурация хостинга.