Files
transcriber/docs/adr/ADR-2026-08-11-spa-on-vue.md
T
av 54ca4c0e50 docs: фреймворком приложения выбран Vue 3 с роутером 5 и сборкой Vite
- заведены записка разведки docs/research/spa-framework.md со сравнением Svelte,
  Vue и React на одном экране и решение ADR-2026-08-11-spa-on-vue
- docs/conventions/web-ui.md переписан под Vue: компоненты, маршруты, состояние,
  обращение к API и показ ошибок
- закрыт вопрос «Приложение» в docs/architecture.md, уточнена задача spa-skeleton
2026-08-11 14:51:55 +03:00

77 lines
5.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Приложение пишем на Vue, а Node входит в гейт и в образ
- **Дата:** 2026-08-11
- **Источник:** [../research/spa-framework.md](../research/spa-framework.md) —
записка разведки `spa-framework-choice`
## Решение
Приложение пишем на **Vue 3** с роутером пятой версии и собираем **Vite** в
статику, которую бинарник вшивает через `go:embed` и раздаёт сам. Маршруты
задаём своей таблицей через `createRouter`; сборочную надстройку роутера под
маршруты по файлам не включаем.
Вместе с этим в проект входит **шаг сборки статики**: Node и `npm` становятся
нужны на машине разработчика, отдельным шагом в `task gate` и слоем сборки в
`Dockerfile`.
Это два решения, а не одно, но принимаются они вместе: шаг сборки появляется при
любом из трёх кандидатов, и отдельно от выбора фреймворка его обсуждать не о чем.
## Почему Vue
Разведка мерила три кандидата на одном и том же экране и нашла единственное
различие, которое расходится в разы:
> Различает единственное — **размер того, что скачивает телефон**, и он
> расходится вчетверо.
Вшивание в бинарник, цена шага сборки в гейте и установка на телефон у всех трёх
оказались одинаковыми и потому ничего не решают.
По размеру Vue стоит посередине — 33 326 Б на четыре экрана против 17 314 у
Svelte и 72 402 у React. Выбран он не по этому числу, а по устойчивости
экосистемы, и оба отвергнутых кандидата отвергнуты с названной ценой:
> **Svelte** — легче Vue вдвое, но своего роутера не имеет, а тот, что есть,
> держит один человек. Владелец выбрал экосистему, которая переживёт проект, а не
> минимальный размер: 33 КБ на телефоне не отличаются от 17 КБ на глаз, а
> брошенная зависимость отличается.
>
> **React** — вчетверо тяжелее Svelte и вдвое тяжелее Vue, а взамен даёт
> экосистему, которой приложению на четыре экрана не на что потратиться.
Роутер берём пятой версии, а не четвёртой, по тому же доводу: она стабильна с
29 января 2026 и несёт метку `latest`, то есть чинить будут её, а не
предшественницу. Её сборочная надстройка добавляет 34 пакета в установку, и это
принятая цена; на собранный файл она не влияет и необязательна.
## Почему это ADR
Запись проходит триггер **дорогим откатом**: переход на другой фреймворк
переписывает все экраны разом, а не один файл. Шаг сборки сюда же — он меняет
требования к машине разработчика и к образу, и снять его потом можно только
вместе с приложением.
Прежнего решения запись не пересматривает: htmx был снят решением о SPA от
2026-08-10, до заведения этого журнала, и парного статуса «заменено на» ставить
нечему.
## Последствия
- `+` разметка отделена от кода однофайловым компонентом, а роутер и хранилище
состояния идут из тех же рук, что и сам фреймворк: третьей библиотеки под них
заводить не нужно.
- `+` собранная статика — три файла и значок, поэтому `go:embed` берёт каталог
обычной строкой, а бинарник остаётся самодостаточным.
- `` **гейт перестаёт зависеть только от Go.** Красный шаг сборки статики
становится таким же поводом остановиться, как красный `go build`, а машина
разработчика получает второе требуемое окружение сверх `ffmpeg`.
- `` **в образ добавляется слой Node** ради шага, результат которого — три
файла; насколько дольше собирается образ и насколько тяжелеет, не замерялось.
- `` в проект приходит `node_modules` на 92 МБ и 84 пакета, за которыми надо
следить отдельно от зависимостей Go: `gitleaks` и `golangci-lint` про них
ничего не знают.
- `` приложение весит 33 КБ там, где на Svelte весило бы 17. Разница куплена
сознательно и обратно не отыгрывается.