Sergey Krylov a13b5145f7
Some checks failed
CI / ci (pull_request) Failing after 3m32s
CI / ci (push) Failing after 2m50s
docs(frontend): align tooling spec with implementation
2026-06-23 21:30:11 +03:00

6.6 KiB
Raw Permalink Blame History

Frontend Infrastructure Tooling — Implementation Plan

Architecture Decisions

ADR references

  • ADR-005: Biome вместо ESLint + Prettier
  • ADR-006: TanStack Router вместо react-router-dom
  • ADR-007: OpenAPI codegen как единый источник типов

Non-ADR decisions

  • ky как единый HTTP-клиент — выбор библиотеки, не меняющий архитектуры
  • MSW browser mode — расширение существующей инфраструктуры тестов
  • Zod для env validation — утилитарное улучшение

Phases

Выполнять последовательно для минимизации конфликтов.

Phase 1 — ky Migration

Низкий риск, обратно совместим

  1. Доработать kyClient.ts:
    • Добавить нормализацию конверта (normalizeEnvelope) в afterResponse hook
    • Экспортировать kyApi и configureKyAuth
  2. Поочерёдно перевести entity API на kyApi:
    • session, stock, bond, search, portfolio, broker-*
  3. Удалить shared/api/client.ts
  4. Заменить configureAuthconfigureKyAuth в точке входа
  5. Прогнать тесты — поведение не должно измениться

Phase 2 — Biome

Средний риск — изменения в коде при авто-миграции

  1. Установить @biomejs/biome
  2. npx @biomejs/biome migrate eslint --write
  3. Создать biome.json, донастроить:
    • Отключить несовместимые правила
    • Настроить files.ignore, linter.rules
  4. Проверить FSD-правила: @conarti/feature-sliced не портируются в Biome → оставить минимальный .eslintrc.cjs только для FSD
  5. Удалить eslint, prettier, .eslintrc.cjs (если FSD не нужен)
  6. Обновить package.json: lint скрипт → biome check
  7. Обновить CI в .gitea/workflows/ci.yml
  8. Обновить pre-commit hook (lint-staged → biome)
  9. Прогнать biome check --write, закоммитить
  10. Прогнать тесты

Phase 3 — Unify API Types

Низкий риск

Фактический подход: ре-экспорты в index.ts вместо types.ts. В процессе реализации выяснилось, что direct-импорты из types.ts ведут к многословным components['schemas']['XxxDto'] в 60+ файлах. Принято решение перенести friendly-name ре-экспорты из responses.ts в index.ts. Таким образом responses.ts удалён, а единая точка входа — @/shared/api.

  1. Перенести friendly-name type-алиасы из responses.ts в shared/api/index.ts
  2. Удалить shared/api/responses.ts
  3. Переключить все импорты с @/shared/api/responses на @/shared/api
  4. Перенести normalizeEnvelope (ky-версию) в shared/api/kyClient.ts
  5. Прогнать npm run build

Phase 4 — MSW Browser

Низкий риск, handlers готовы

  1. Создать apps/frontend/mocks/browser.ts (setupWorker)
  2. Прокинуть в public/mockServiceWorker.js через npx msw init public/
  3. Создать shared/config/env.ts с чтением VITE_API_MOCK
  4. Подключить MSW browser в main.tsx по условию
  5. Проверить npm run dev VITE_API_MOCK=true без бэкенда

Phase 5 — Env Validation

Низкий риск

  1. Расширить shared/config/env.ts — Zod-схема для всех VITE_*
  2. Вызвать валидацию в main.tsx до рендера

Phase 6 — TanStack Router

Крупный, высокий риск

Фактический подход: code-first вместо file-based. В процессе реализации выяснилось, что @tanstack/router-plugin не генерирует routeTree.gen.ts корректно на данной версии Vite/плагина. Принято решение использовать code-first подход — все маршруты определяются вручную в routeTree.tsx.

  1. Установить зависимости:
    • @tanstack/react-router
    • @tanstack/router-devtools (devDependency)
  2. Создать src/app/routing/routeTree.tsx — code-first дерево маршрутов:
    • Все маршруты определены в одном файле через createRootRoute, createRoute, createRouter
    • beforeLoad для guard'ов (requireAuth)
    • Loaders для предзагрузки отложены
  3. Создать src/app/routing/router.ts:
    • createRouter() с Route Tree из routeTree.tsx
  4. Заменить <BrowserRouter> + <Routes><RouterProvider> в App.tsx
  5. Заменить все импорты react-router-dom по всему проекту:
    • LinkLink из @tanstack/react-router
    • useNavigateuseNavigate({ to: '...' }) (объектный синтаксис)
    • useParamsuseParams
    • useSearchParamsuseSearchParamsCompat (временная обёртка, т.к. TanStack Router не экспортирует useSearchParams)
    • useLocationuseLocation
  6. Заменить MemoryRouter в тестах на createMemoryHistory + RouterProvider
  7. Обновить test-utils.tsx — рендер-обёртка на TanStack Router
  8. Настроить router-devtools в dev-режиме
  9. Прогнать тесты, проверить сборку

Dependencies

Phase 1 (ky)       → независим
Phase 2 (Biome)    → независим
Phase 3 (Types)    → после Phase 1 (ky меняет нормализацию)
Phase 4 (MSW)      → после Phase 5 (env нужен для VITE_API_MOCK)
Phase 5 (Env)      → независим
Phase 6 (Router)   → после Phase 3 (типы API стабильны)

Rollback Strategy

  • Каждый phase — отдельный коммит, можно revert по одному
  • Biome: .eslintrc.cjs сохраняется как .eslintrc.cjs.bak до верификации
  • Router: старый AppRoutes.tsx и react-router-dom не удаляются до полного прохождения тестов
  • Каждый phase должен оставлять npm run build и npm run test зелёными