Конвейер сборки
Сборка сайта — это программируемый конвейер. Фазы идут в фиксированном порядке, а внутри них движок запускает именованные стадии. Стадии можно добавлять и обвязывать хуками; повторное имя вызывает ошибку. Ядро запускает этот конвейер через nuckty build.
Фазы
Конвейер состоит из фаз — крупных этапов, следующих один за другим:
clean → prepare → render → resolve → emit
| Фаза | Что происходит |
|---|---|
clean | Очистка выходного каталога |
prepare | Подготовка ресурсов: изображения, ассеты |
render | Карта сайта, Markdown → BEMJSON; сборка бандлов CSS и JS |
resolve | Зарезервировано для разрешения перекрёстных ссылок и якорей (пока заглушка) |
emit | HTML и файлы расширений; финализация выполняется после этой фазы |
Порядок фаз фиксирован — это каркас сборки. Набор стадий внутри фазы автор меняет: добавляет стадии и обвязывает хуками.
Стадии
Внутри фаз работают стадии — именованные функции (ctx) => void | Promise<void>. Каждая стадия получает данные из контекста сборки (ctx.{cwd, buildDir, outDir, store}) и записывает результат в его поля. Стадии ядра в порядке выполнения:
clean(clean) — очистка выходного каталога.images(prepare) — копирует исходные изображения и готовые варианты, строит.build/image-mapping.json.assets(prepare) — копирует статические файлы (PDF, ZIP, MP4,robots.txt) из конфигурации и внешних репозиториев.sitemap(render) — разбираетsitemap.yml, обрабатывает Markdown в BEMJSON, строит карту адресов.css/js(render) — собирают бандлы по зависимостям, добавляют content-hash.resolve(resolve) — заглушка, зарезервирован.html(emit) — применяет шаблоны и превращает BEMJSON в HTML.
После фазы emit (включая стадии фазы emit расширений) сборка прогоняет финализирующий проход в таком порядке:
compression— сжимает выбранные непустые файлы артефакта (Brotli Q11, Gzip 9).htaccess— генерирует.htaccessвoutDir.manifest— записываетmanifest.jsonс хэшами и размерами.nginx— генерируетnginx.confвbuildDir.
Стадии фазы emit расширений завершаются до финализации, поэтому их файлы попадают в сжатие и manifest. Именованные хуки before/after действуют и для финализаторов; неизвестное имя хука вызывает отказ до очистки. Новые файлы следует создавать до compression, а не в хуке более позднего финализатора.
Хуки before/after
Вокруг любой стадии можно поставить хук:
env.pipeline.after('html', myStage);
env.pipeline.before('sitemap', addExtraFormat);
env.pipeline.registerStage('search', searchStage, { phase: 'emit' });
Это и есть главная точка расширения сборки. После HTML отдельная стадия строит поисковый индекс, создаёт ленту RSS или обрабатывает готовый артефакт. Имена стадий уникальны — повторная регистрация имени стадии — ошибка. Подробнее — в pipeline-расширении.
Контекст сборки
Стадии общаются через ctx — контекст сборки:
ctx.cwd— корень проекта пользователя.ctx.configDir— каталог сsitemap.ymlи файлами конфигурации.ctx.buildDir— общий рабочий каталог.build/; после сборки нескольких таргетов содержит промежуточные результаты последнего.nuckty serveсоздаёт собственныйnginx-serve.conf.ctx.outDir— итоговый артефакт (site/), который публикуют на сервер.ctx.store— общее хранилище между стадиями: карта сайта, изображения, хэши бандлов.
Стадии не вызывают друг друга напрямую. Они читают и пишут общее хранилище, а конвейер гарантирует порядок выполнения. Каждая стадия должна соблюдать общий контракт данных и учитывать результаты предыдущих стадий, от которых она зависит.
Код, а не декларативный конфиг
Конвейер — это код, а не YAML. Стадия и хук — типизированные функции. Отсюда преимущества:
- компилятор проверяет, что стадия соответствует контракту;
- редактор подсказывает поля
ctx; - расширение сборки пишут на обычном TypeScript, а не на отдельном языке конфигурации: его не надо учить заново, и возможностями такого языка расширение не ограничено.
Когда возможностей config-nuckty.ts мало и нужно что-то нетривиальное (своя стадия, особый порядок, условная сборка), это пишут кодом расширения, а не усложняют config-nuckty.ts. Подробнее — в разделе расширения.