- заведён каталог web/ — Vue 3, роутер пятой версии, сборка Vite; собранное вшивается через go:embed и раздаётся корневым маршрутом: разметка на неизвестном пути вне корней сервиса, отказ контракта внутри корня - перечень корней сервиса стал единой точкой и порождает регистрацию маршрутов, а не описывает её; журнал раздачи пишет исход и длину пути, но не сам путь - шаг front зовёт Node контейнером docker — Biome, юнит-тесты Vue и сборка входят в гейт, а в Dockerfile появилась ступень приложения
4.7 KiB
Node зовётся контейнером, а не ставится на машину разработчика
- Дата: 2026-08-15
- Источник: ../../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 записал последствием,
что «машина разработчика получает второе требуемое окружение сверх ffmpeg», и
подразумевал под ним Node. Окружением оказался docker. Сам выбор фреймворка и
наличие шага сборки это не пересматривает, поэтому статуса «заменено на» у той
записи нет: заменена не она, а толкование одного её последствия.
Последствия
+версия сборочного окружения живёт одним местом — ступеньюDockerfile, — и своего шага сверки ей не нужно.+собранное в наборе проверок и собранное в образе совпадает, потому что совпадает окружение сборки, а не потому что «обычно совпадает».−набор проверок перестаёт работать без docker, и отказ этот приходит кодом окружения. Тем же кодом приходит отказ реестра пакетов: сетезависимых шагов в наборе становится два вместо одного.−контейнер ходит под тем же пользователем, что и вызвавший, а кэш установщика уводится наружу — обе частности обязательны: без них собранное ляжет отroot, а зависимости будут тянуться заново каждый прогон.−вес и время самой ступени в образе неизвестны: финальный образ от неё не растёт (ступень в рабочий слой не копируется), а время сборки решением владельца от 2026-08-15 не замеряется вовсе.