- заведён каталог web/ — Vue 3, роутер пятой версии, сборка Vite; собранное вшивается через go:embed и раздаётся корневым маршрутом: разметка на неизвестном пути вне корней сервиса, отказ контракта внутри корня - перечень корней сервиса стал единой точкой и порождает регистрацию маршрутов, а не описывает её; журнал раздачи пишет исход и длину пути, но не сам путь - шаг front зовёт Node контейнером docker — Biome, юнит-тесты Vue и сборка входят в гейт, а в Dockerfile появилась ступень приложения
63 lines
4.7 KiB
Markdown
63 lines
4.7 KiB
Markdown
# Node зовётся контейнером, а не ставится на машину разработчика
|
||
|
||
- **Дата:** 2026-08-15
|
||
- **Источник:** [../../openspec/changes/archive/2026-08-15-spa-skeleton/design.md](../../openspec/changes/archive/2026-08-15-spa-skeleton/design.md),
|
||
раздел «Node не ставится на машину, а зовётся контейнером»
|
||
|
||
## Решение
|
||
|
||
Шаг сборки приложения гоняет установщик пакетов и сборщик **внутри контейнера**,
|
||
а не вызывает их из `PATH`:
|
||
|
||
> Требованием к машине разработчика становится docker, которым и так собирается
|
||
> образ, — второго устанавливаемого окружения сверх `ffmpeg` не появляется
|
||
> вовсе.
|
||
|
||
Образ сборочного окружения берётся из ступени `Dockerfile`, а не объявляется
|
||
вторым числом в `Taskfile.yml`.
|
||
|
||
## Почему
|
||
|
||
Довод в дизайне назван прямо:
|
||
|
||
> Так снимается расхождение, которое иначе завелось бы молча: версия Node на
|
||
> машине разработчика и версия в образе — два разных числа, и собранное ими
|
||
> приложение различается ровно тогда, когда различаются они.
|
||
|
||
Отвергнуты два очевидных подхода, и оба с названной ценой. **Поставить Node на
|
||
машину** — вводит второе устанавливаемое окружение и разъезжается с версией в
|
||
образе. **Дать выбор — контейнер или локальный Node** — это второй способ делать
|
||
одно и то же, и собранное ими различалось бы в зависимости от того, у кого что
|
||
стоит.
|
||
|
||
## Почему это ADR
|
||
|
||
Запись проходит триггер **намеренным отказом** от очевидного подхода: поставить
|
||
Node на машину — ровно то, что делают по умолчанию, и отказ от этого надо
|
||
объяснить один раз, а не на каждом вопросе «почему у нас нельзя просто
|
||
`npm run build`».
|
||
|
||
## Что это меняет в прежнем решении
|
||
|
||
[ADR-2026-08-11-spa-on-vue](ADR-2026-08-11-spa-on-vue.md) записал последствием,
|
||
что «машина разработчика получает второе требуемое окружение сверх `ffmpeg`», и
|
||
подразумевал под ним Node. Окружением оказался **docker**. Сам выбор фреймворка и
|
||
наличие шага сборки это не пересматривает, поэтому статуса «заменено на» у той
|
||
записи нет: заменена не она, а толкование одного её последствия.
|
||
|
||
## Последствия
|
||
|
||
- `+` версия сборочного окружения живёт **одним** местом — ступенью
|
||
`Dockerfile`, — и своего шага сверки ей не нужно.
|
||
- `+` собранное в наборе проверок и собранное в образе совпадает, потому что
|
||
совпадает окружение сборки, а не потому что «обычно совпадает».
|
||
- `−` **набор проверок перестаёт работать без docker**, и отказ этот приходит
|
||
кодом окружения. Тем же кодом приходит отказ реестра пакетов: сетезависимых
|
||
шагов в наборе становится два вместо одного.
|
||
- `−` контейнер ходит под тем же пользователем, что и вызвавший, а кэш
|
||
установщика уводится наружу — обе частности обязательны: без них собранное
|
||
ляжет от `root`, а зависимости будут тянуться заново каждый прогон.
|
||
- `−` **вес и время самой ступени в образе неизвестны**: финальный образ от неё
|
||
не растёт (ступень в рабочий слой не копируется), а время сборки решением
|
||
владельца от 2026-08-15 не замеряется вовсе.
|