codex/frontend-infrastructure-tooling #39
67
apps/docs/docs/adr/ADR-017-biome-linter-formatter.md
Normal file
67
apps/docs/docs/adr/ADR-017-biome-linter-formatter.md
Normal file
@ -0,0 +1,67 @@
|
||||
# ADR-017: Biome как единый инструмент линтинга и форматирования
|
||||
|
||||
**Дата:** 2026-06-23
|
||||
**Статус:** Принято
|
||||
**Автор:** AI Agent (codex/frontend-infrastructure-tooling)
|
||||
|
||||
## Контекст
|
||||
|
||||
Проект использует **ESLint v8** + **Prettier** для линтинга и форматирования. ESLint 8 устарел: ESLint 9 имеет полностью изменённый конфиг, миграция потребует переписывания `.eslintrc`. Оба инструмента написаны на JavaScript и работают медленно на больших кодовых базах.
|
||||
|
||||
Появились современные Rust-альтернативы, объединяющие линтинг и форматирование в одном CLI со значительным приростом производительности.
|
||||
|
||||
## Рассмотренные варианты
|
||||
|
||||
### Biome v2.5
|
||||
- Linter + Formatter в одном CLI
|
||||
- 500+ правил (ESLint + TypeScript ESLint + others)
|
||||
- 97% совместимость форматтера с Prettier
|
||||
- ~35x быстрее Prettier, ~35x быстрее ESLint
|
||||
- Поддержка: JS, TS, JSX, TSX, JSON, HTML, CSS, GraphQL
|
||||
- Стабильный LTS, продакшн у AWS, Google, Vercel
|
||||
- Встроенная миграция: `biome migrate eslint`
|
||||
|
||||
### Oxlint + Oxfmt (Oxc Project)
|
||||
- Linter отдельно (800+ правил, 50-100x быстрее ESLint)
|
||||
- Formatter отдельно (Oxfmt, beta, 3x быстрее Biome, 30x быстрее Prettier)
|
||||
- Type-aware linting через tsgo
|
||||
- Два отдельных инструмента с разными конфигами
|
||||
- Oxfmt в статусе beta
|
||||
|
||||
### Оставить ESLint + Prettier
|
||||
- Знакомый стек
|
||||
- Медленная производительность
|
||||
- Необходимость мигрировать на ESLint 9 в любом случае
|
||||
- Два набора конфигов
|
||||
|
||||
## Решение
|
||||
|
||||
Перейти на **Biome** как единый инструмент для линтинга и форматирования.
|
||||
|
||||
Причины:
|
||||
1. **Один инструмент вместо двух** — меньше конфигов, один CI-степ, одна команда
|
||||
2. **Production-ready** — стабильный LTS, используется крупными компаниями
|
||||
3. **Плавная миграция** — `biome migrate eslint` переносит правила автоматически
|
||||
4. **Производительность** — ~35x быстрее как линтинг, так и форматирование
|
||||
5. **Встроенный import sorting** — замена `eslint-plugin-import`
|
||||
|
||||
### Ограничения
|
||||
|
||||
FSD-правила из `@conarti/eslint-plugin-feature-sliced` не имеют аналога в Biome. Если не удаётся портировать через plugin system — сохраняется минимальный `.eslintrc.cjs` только для FSD layer boundaries.
|
||||
|
||||
## Последствия
|
||||
|
||||
### Положительные
|
||||
- Единый конфиг `biome.json` вместо `.eslintrc.cjs` + `.prettierrc`
|
||||
- Ускорение CI (lint + format за один проход)
|
||||
- Автоматический import sorting
|
||||
- Меньше зависимостей в `package.json`
|
||||
|
||||
### Риски
|
||||
- FSD-правила могут не портироваться — потребуется костыль с минимальным ESLint
|
||||
- Biome может не поддерживать какое-то редкое правило ESLint — потребуется адаптация
|
||||
- Команде нужно привыкнуть к новому CLI
|
||||
|
||||
## Связанные документы
|
||||
- `docs/research/frontend-infrastructure-tooling/biome-vs-oxlint.md`
|
||||
- `docs/features/frontend-infrastructure-tooling/plan.md` (Phase 2)
|
||||
72
apps/docs/docs/adr/ADR-018-tanstack-router.md
Normal file
72
apps/docs/docs/adr/ADR-018-tanstack-router.md
Normal file
@ -0,0 +1,72 @@
|
||||
# ADR-018: TanStack Router как основной роутер
|
||||
|
||||
**Дата:** 2026-06-23
|
||||
**Статус:** Принято
|
||||
**Автор:** AI Agent (codex/frontend-infrastructure-tooling)
|
||||
|
||||
## Контекст
|
||||
|
||||
Проект использует **react-router-dom v6** для клиентской маршрутизации. Текущая реализация:
|
||||
|
||||
- Все страницы импортируются статически в `AppRoutes.tsx`
|
||||
- Нет lazy loading (code splitting) — каждая навигация грузит весь бандл
|
||||
- Параметры роутов (`useParams`) и search params (`useSearchParams`) не типизированы
|
||||
- Нет встроенной валидации search params
|
||||
- Проект уже использует TanStack Query — потенциальная синергия с TanStack Router
|
||||
|
||||
Требуется:
|
||||
- Route-level code splitting для оптимизации бандла
|
||||
- Типобезопасность параметров и search params
|
||||
- Интеграция с существующим TanStack Query (prefetching через loaders)
|
||||
|
||||
## Рассмотренные варианты
|
||||
|
||||
### react-router-dom v6 + React.lazy
|
||||
- Минимальные изменения — обернуть каждый импорт в `React.lazy` + `<Suspense>`
|
||||
- Не решает проблему типизации
|
||||
- Нет prefetching / loaders
|
||||
- React.lazy boilerplate на каждый роут
|
||||
|
||||
### TanStack Router
|
||||
- Полная типобезопасность через генерацию RouteTree
|
||||
- Search params с Zod-схемами
|
||||
- Code splitting built-in — каждый роут ленивый по умолчанию
|
||||
- Loaders для prefetching + интеграция с TanStack Query
|
||||
- Pending/Error/NotFound boundaries на уровне роута
|
||||
- Размер: ~3-4KB gzip (меньше react-router-dom)
|
||||
- Требует переписывания всех роутов и навигации
|
||||
|
||||
## Решение
|
||||
|
||||
Мигрировать на **TanStack Router**.
|
||||
|
||||
Причины:
|
||||
1. **Типобезопасность** — RouteTree generation исключает опечатки в путях и невалидные search params
|
||||
2. **Code splitting без boilerplate** — built-in lazy, не нужен `React.lazy`
|
||||
3. **Синергия с TanStack Query** — уже используется в проекте; loaders дают prefetching данных до рендера компонента
|
||||
4. **Zod** — уже используется для валидации форм; Router использует Zod для search params
|
||||
5. **Search params** — типизированная валидация вместо строковых `useSearchParams`
|
||||
6. **Меньший размер** — 3-4KB vs 8KB react-router-dom
|
||||
|
||||
## Последствия
|
||||
|
||||
### Положительные
|
||||
- Каждая страница — отдельный chunk, грузится по требованию
|
||||
- Search params валидируются Zod-схемами (screener, broker-operations)
|
||||
- Loaders предзагружают данные, уменьшая время до первого контента
|
||||
- Guard'ы (ProtectedRoute) реализуются через `beforeLoad`, единый подход
|
||||
|
||||
### Риски
|
||||
- Переписывание всех роутов, компонентов навигации (`Link`, `useNavigate`) и тестов
|
||||
- `MemoryRouter` в тестах заменяется на `createMemoryRouter` из TanStack Router
|
||||
- Файловая структура роутов меняется — `src/app/routes/` с Route Tree generation
|
||||
- Learning curve для команды
|
||||
|
||||
### Миграция
|
||||
- Каждый роут переносится по одному
|
||||
- Старый `AppRoutes.tsx` сохраняется до полного прохождения тестов
|
||||
- `react-router-dom` удаляется только после верификации
|
||||
|
||||
## Связанные документы
|
||||
- `docs/research/frontend-infrastructure-tooling/react-router-vs-tanstack-router.md`
|
||||
- `docs/features/frontend-infrastructure-tooling/plan.md` (Phase 6)
|
||||
64
apps/docs/docs/adr/ADR-019-api-layer-unification.md
Normal file
64
apps/docs/docs/adr/ADR-019-api-layer-unification.md
Normal file
@ -0,0 +1,64 @@
|
||||
# ADR-019: Унификация API-слоя: ky + codegen как единый источник типов
|
||||
|
||||
**Дата:** 2026-06-23
|
||||
**Статус:** Принято
|
||||
**Автор:** AI Agent (codex/frontend-infrastructure-tooling)
|
||||
|
||||
## Контекст
|
||||
|
||||
В проекте сложилась ситуация расхождения между принятыми ADR и фактической реализацией:
|
||||
|
||||
- **ADR-005** решил использовать `openapi-typescript` + `openapi-fetch` для кодогенерации типов
|
||||
- **ADR-015** решил использовать `ky` как HTTP-клиент
|
||||
- Фактически: используется кастомный `client.ts` с нативным fetch, создан `kyClient.ts` (но не используется), рукописный `responses.ts` дублирует сгенерированный `types.ts`
|
||||
|
||||
Проблемы:
|
||||
- Дублирование типов — рукописные расходятся с codegen
|
||||
- Два HTTP-клиента (один мёртвый) — путаница
|
||||
- fetch-реализация без удобных интерцепторов (retry, timeout, hooks)
|
||||
|
||||
## Решение
|
||||
|
||||
### 1. ky как единый HTTP-клиент
|
||||
|
||||
- Активировать `kyClient.ts` с доработанными hooks (normalizeEnvelope в afterResponse)
|
||||
- Перевести все entity-API файлы с `request()` на `kyApi`
|
||||
- Удалить `shared/api/client.ts`
|
||||
- ADR-015 исполняется полностью
|
||||
|
||||
### 2. OpenAPI codegen как единый источник типов
|
||||
|
||||
- Удалить рукописный `shared/api/responses.ts`
|
||||
- Все entity-API файлы используют типы из сгенерированного `shared/api/types.ts`
|
||||
- Типы пишутся только через `npm run codegen`
|
||||
- ADR-005 приводится к фактическому исполнению (без `openapi-fetch`, с кастомным клиентом)
|
||||
|
||||
### 3. MSW Browser Mode (расширение существующей инфраструктуры)
|
||||
|
||||
- MSW уже используется в тестах (`shared/lib/test/server.ts`)
|
||||
- Добавить browser entry (`setupWorker`) для dev-режима
|
||||
- Включается переменной `VITE_API_MOCK=true`
|
||||
- Переиспользует существующие handlers
|
||||
|
||||
### 4. Валидация переменных окружения
|
||||
|
||||
- Zod-схема для `VITE_*` переменных
|
||||
- Валидация при старте приложения
|
||||
|
||||
## Последствия
|
||||
|
||||
### Положительные
|
||||
- Единый HTTP-клиент с интерцепторами (auth, retry, normalize)
|
||||
- Нет дублирования типов — все через codegen
|
||||
- Возможность разрабатывать UI без бэкенда (MSW browser)
|
||||
- Раннее обнаружение ошибок конфигурации (env validation)
|
||||
|
||||
### Риски
|
||||
- Миграция entity API требует регрессионного тестирования каждого модуля
|
||||
- MSW browser handlers могут отличаться от реального API — нужно синхронизировать
|
||||
- При изменении OpenAPI spec нужно запускать codegen вручную
|
||||
|
||||
## Связанные документы
|
||||
- ADR-005: OpenAPI codegen через openapi-typescript
|
||||
- ADR-015: Модернизация инфраструктуры фронтенда
|
||||
- `docs/features/frontend-infrastructure-tooling/plan.md` (Phase 1, 3, 4, 5)
|
||||
@ -18,5 +18,8 @@
|
||||
| [ADR-014](ADR-014-frontend-fsd-market-pages) | Accepted | FSD-миграция market pages и market widgets |
|
||||
| [ADR-015](ADR-015-frontend-libraries-modernization) | — | Модернизация инфраструктуры фронтенда |
|
||||
| [ADR-016](ADR-016-design-system) | Accepted | Дизайн-система — гибридный подход |
|
||||
| [ADR-017](ADR-017-biome-linter-formatter) | Accepted | Biome как единый инструмент линтинга и форматирования |
|
||||
| [ADR-018](ADR-018-tanstack-router) | Accepted | TanStack Router как основной роутер |
|
||||
| [ADR-019](ADR-019-api-layer-unification) | Accepted | Унификация API-слоя: ky + codegen как единый источник типов |
|
||||
|
||||
Все опубликованные ADR находятся в `apps/docs/docs/adr/` и отображаются в этом Docusaurus-разделе.
|
||||
|
||||
132
docs/features/frontend-infrastructure-tooling/plan.md
Normal file
132
docs/features/frontend-infrastructure-tooling/plan.md
Normal file
@ -0,0 +1,132 @@
|
||||
# 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. Заменить `configureAuth` → `configureKyAuth` в точке входа
|
||||
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
|
||||
*Низкий риск*
|
||||
|
||||
1. Убедиться, что все entity API импортируют из `types.ts` (codegen)
|
||||
2. Удалить `shared/api/responses.ts`
|
||||
3. Перенести normalizeEnvelope (ky-версию) в `shared/api/kyClient.ts`
|
||||
4. Прогнать `npm run build`
|
||||
|
||||
### Phase 4 — MSW Browser
|
||||
*Низкий риск, handlers готовы*
|
||||
|
||||
1. Создать `shared/lib/test/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
|
||||
*Крупный, высокий риск*
|
||||
|
||||
1. Установить зависимости:
|
||||
- `@tanstack/react-router`
|
||||
- `@tanstack/router-devtools` (devDependency)
|
||||
- `@tanstack/router-plugin` (vite plugin)
|
||||
2. Настроить Vite plugin в `vite.config.ts`
|
||||
3. Создать файловую структуру роутов:
|
||||
```
|
||||
src/app/routes/
|
||||
__root.tsx — AppLayout + ErrorBoundary
|
||||
index.tsx — HomePage
|
||||
stocks.$secid.tsx — StockPage
|
||||
bonds.$secid.tsx — BondPage
|
||||
screener.tsx — ScreenerPage + Zod search params
|
||||
login.tsx — LoginPage
|
||||
register.tsx — RegisterPage
|
||||
profile.tsx — ProfilePage (guard: beforeLoad)
|
||||
portfolios.tsx — PortfoliosListPage (guard)
|
||||
portfolios.$id.tsx — PortfolioDetailPage (guard)
|
||||
broker/
|
||||
index.tsx — BrokerAccountsPage (guard)
|
||||
$accountId/
|
||||
index.tsx — BrokerAccountOverviewPage (guard)
|
||||
shares.tsx — BrokerPositionsPage (guard)
|
||||
bonds.tsx — BrokerPositionsPage (guard)
|
||||
operations.tsx — BrokerOperationsPage + Zod search params (guard)
|
||||
events.tsx — BrokerEventsPage (guard)
|
||||
```
|
||||
4. Перенести каждый роут из `AppRoutes.tsx` — каждый файл создаёт lazy route
|
||||
5. Создать роутер в `app/routing/router.ts`:
|
||||
- `createRouter()` с Route Tree
|
||||
- `beforeLoad` для guard'ов
|
||||
- Loaders для предзагрузки (TanStack Query integration)
|
||||
6. Заменить `<BrowserRouter>` + `<Routes>` → `<RouterProvider>` в `App.tsx`
|
||||
7. Заменить все импорты `react-router-dom` по всему проекту:
|
||||
- `Link` → `Link` из `@tanstack/react-router`
|
||||
- `useNavigate` → `useNavigate`
|
||||
- `useParams` → `useParams`
|
||||
- `useSearchParams` → `useSearch` + `useNavigate`
|
||||
- `useLocation` → `useLocation`
|
||||
8. Заменить `MemoryRouter` в тестах на `createMemoryRouter` из TanStack Router
|
||||
9. Настроить router-devtools в dev-режиме
|
||||
10. Прогнать тесты
|
||||
|
||||
## 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` зелёными
|
||||
105
docs/features/frontend-infrastructure-tooling/tasks.md
Normal file
105
docs/features/frontend-infrastructure-tooling/tasks.md
Normal file
@ -0,0 +1,105 @@
|
||||
# Frontend Infrastructure Tooling — Tasks
|
||||
|
||||
## Phase 1: ky Migration
|
||||
|
||||
- [ ] Доработать `shared/api/kyClient.ts`: добавить normalizeEnvelope в afterResponse hook
|
||||
- [ ] Экспортировать `kyApi` (create экземпляр) и `configureKyAuth` из kyClient
|
||||
- [ ] Перевести `entities/session/api/sessionApi.ts` на kyApi
|
||||
- [ ] Перевести `entities/stock/api/stockApi.ts` на kyApi
|
||||
- [ ] Перевести `entities/bond/api/bondApi.ts` на kyApi
|
||||
- [ ] Перевести `entities/search/api/searchApi.ts` на kyApi
|
||||
- [ ] Перевести `entities/portfolio/api/portfolioApi.ts` на kyApi
|
||||
- [ ] Перевести `entities/broker-account/api/brokerAccountApi.ts` на kyApi
|
||||
- [ ] Перевести `entities/broker-position/api/brokerPositionApi.ts` на kyApi
|
||||
- [ ] Перевести `entities/broker-operation/api/brokerOperationApi.ts` на kyApi
|
||||
- [ ] Перевести `entities/broker-event/api/brokerEventApi.ts` на kyApi
|
||||
- [ ] Перевести `features/screener/api/screenerApi.ts` на kyApi
|
||||
- [ ] Удалить `shared/api/client.ts`
|
||||
- [ ] Заменить `configureAuth()` на `configureKyAuth()` в точке входа (AppProviders)
|
||||
- [ ] `npm run test` — все тесты проходят
|
||||
- [ ] `npm run build` — сборка проходит
|
||||
|
||||
## Phase 2: Biome Migration
|
||||
|
||||
- [ ] Research: проверить Biome plugin system на поддержку FSD/import-no-restricted-paths
|
||||
- [ ] Установить `@biomejs/biome` (devDependency)
|
||||
- [ ] Запустить `npx @biomejs/biome migrate eslint --write`
|
||||
- [ ] Создать `biome.json` с донастройкой под проект
|
||||
- [ ] Если FSD-правила не портируются — создать минимальный `.eslintrc.cjs` только для FSD
|
||||
- [ ] Удалить зависимости: eslint, prettier, @typescript-eslint/*, eslint-plugin-*
|
||||
- [ ] Удалить `.eslintrc.cjs` (если FSD не нужен)
|
||||
- [ ] Обновить `package.json`: `lint` → `biome check src/`
|
||||
- [ ] Обновить `.gitea/workflows/ci.yml`: заменить eslint на biome
|
||||
- [ ] Обновить pre-commit hook (lint-staged → biome)
|
||||
- [ ] Прогнать `biome check --write src/`
|
||||
- [ ] `npm run test` — все тесты проходят
|
||||
|
||||
## Phase 3: Unify API Types
|
||||
|
||||
- [ ] Проверить все импорты в entity API — должны быть из `types.ts` (codegen), не из `responses.ts`
|
||||
- [ ] Если кто-то импортирует из `responses.ts` — переключить на `types.ts`
|
||||
- [ ] Удалить `shared/api/responses.ts`
|
||||
- [ ] Перенести normalizeEnvelope (ky-версия) в `shared/api/kyClient.ts`
|
||||
- [ ] `npm run build` — сборка проходит
|
||||
|
||||
## Phase 4: MSW Browser
|
||||
|
||||
- [ ] Создать `shared/lib/test/browser.ts` (setupWorker из msw/browser)
|
||||
- [ ] Установить и прокинуть mockServiceWorker.js: `npx msw init public/`
|
||||
- [ ] Создать `shared/config/env.ts` с чтением и экспортом VITE_API_MOCK
|
||||
- [ ] В `main.tsx`: при `VITE_API_MOCK === 'true'` запускать `worker.start()`
|
||||
- [ ] Проверить: `VITE_API_MOCK=true npm run dev` без бэкенда — приложение работает
|
||||
- [ ] Проверить: `VITE_API_MOCK=false npm run dev` — запросы идут на бэкенд
|
||||
|
||||
## Phase 5: Env Validation
|
||||
|
||||
- [ ] Разработать Zod-схему в `shared/config/env.ts` для всех VITE_* переменных
|
||||
- [ ] Вызвать `validateEnv()` в `main.tsx` до `ReactDOM.createRoot`
|
||||
- [ ] Проверить: при отсутствии обязательной переменной — понятная ошибка
|
||||
|
||||
## Phase 6: TanStack Router
|
||||
|
||||
### Setup
|
||||
- [ ] Установить `@tanstack/react-router`, `@tanstack/router-devtools`, `@tanstack/router-plugin`
|
||||
- [ ] Настроить Vite plugin для генерации RouteTree в `vite.config.ts`
|
||||
|
||||
### Route files
|
||||
- [ ] Создать `src/app/routes/__root.tsx` — AppLayout + ErrorBoundary
|
||||
- [ ] Создать `src/app/routes/index.tsx` — HomePage
|
||||
- [ ] Создать `src/app/routes/stocks.$secid.tsx` — StockPage
|
||||
- [ ] Создать `src/app/routes/bonds.$secid.tsx` — BondPage
|
||||
- [ ] Создать `src/app/routes/screener.tsx` — ScreenerPage + Zod search params
|
||||
- [ ] Создать `src/app/routes/login.tsx` — LoginPage
|
||||
- [ ] Создать `src/app/routes/register.tsx` — RegisterPage
|
||||
- [ ] Создать `src/app/routes/profile.tsx` — ProfilePage (guard: beforeLoad)
|
||||
- [ ] Создать `src/app/routes/portfolios.tsx` — PortfoliosListPage (guard)
|
||||
- [ ] Создать `src/app/routes/portfolios.$id.tsx` — PortfolioDetailPage (guard)
|
||||
- [ ] Создать `src/app/routes/broker/index.tsx` — BrokerAccountsPage (guard)
|
||||
- [ ] Создать `src/app/routes/broker.$accountId/index.tsx` — BrokerAccountOverviewPage (guard)
|
||||
- [ ] Создать `src/app/routes/broker.$accountId/shares.tsx` — BrokerPositionsPage (guard)
|
||||
- [ ] Создать `src/app/routes/broker.$accountId/bonds.tsx` — BrokerPositionsPage (guard)
|
||||
- [ ] Создать `src/app/routes/broker.$accountId/operations.tsx` — BrokerOperationsPage (guard)
|
||||
- [ ] Создать `src/app/routes/broker.$accountId/events.tsx` — BrokerEventsPage (guard)
|
||||
|
||||
### Router integration
|
||||
- [ ] Создать `app/routing/router.ts`: `createRouter()` с Route Tree
|
||||
- [ ] Настроить `beforeLoad` для guard'ов
|
||||
- [ ] Настроить loaders для предзагрузки (TanStack Query)
|
||||
- [ ] Заменить `<BrowserRouter>` + `<Routes>` → `<RouterProvider>` в `App.tsx`
|
||||
|
||||
### Replace imports
|
||||
- [ ] Заменить `Link` → `@tanstack/react-router` Link по всему проекту
|
||||
- [ ] Заменить `useNavigate` → `@tanstack/react-router`
|
||||
- [ ] Заменить `useParams` → `@tanstack/react-router`
|
||||
- [ ] Заменить `useSearchParams` → `useSearch` + `useNavigate`
|
||||
- [ ] Заменить `useLocation` → `@tanstack/react-router`
|
||||
|
||||
### Tests
|
||||
- [ ] Заменить `MemoryRouter` в тестах на `createMemoryRouter` из TanStack Router
|
||||
- [ ] Обновить тестовые утилиты (`test-utils.tsx`)
|
||||
- [ ] `npm run test` — все тесты проходят
|
||||
- [ ] `npm run build` — сборка проходит
|
||||
|
||||
### Devtools
|
||||
- [ ] Настроить `@tanstack/router-devtools` в dev-режиме
|
||||
- [ ] Проверить навигацию по всем страницам вручную
|
||||
@ -0,0 +1,52 @@
|
||||
# Biome vs Oxlint: Comparison for Frontend Tooling
|
||||
|
||||
## Context
|
||||
|
||||
Проект использует **ESLint v8** + **Prettier** для линтинга и форматирования. ESLint 8 устарел (ESLint 9 имеет полностью изменённый конфиг). Рассматриваем замену на современную Rust-тулзу, совмещающую линтинг и форматирование.
|
||||
|
||||
## Candidates
|
||||
|
||||
### Biome (v2.5.0)
|
||||
|
||||
- **Linter + Formatter** в одном CLI (`biome check --write`)
|
||||
- 500+ правил (ESLint + TypeScript ESLint + другие источники)
|
||||
- Форматтер: **97% совместимость с Prettier**, ~35x быстрее
|
||||
- Поддержка: JS, TS, JSX, TSX, JSON, HTML, CSS, GraphQL
|
||||
- Единый конфиг `biome.json` вместо `.eslintrc` + `.prettierrc`
|
||||
- Встроенный import sorting (замена `eslint-plugin-import`)
|
||||
- Production usage: AWS, Google, Vercel, Microsoft, Discord, Cloudflare
|
||||
- Стабильный LTS-релиз, зрелое сообщество
|
||||
|
||||
### Oxlint + Oxfmt (Oxc Project)
|
||||
|
||||
- **Oxlint**: 50-100x быстрее ESLint, 800+ правил
|
||||
- **Oxfmt**: ~3x быстрее Biome formatter, 30x быстрее Prettier
|
||||
- Type-aware linting через `tsgo`
|
||||
- ESLint JS Plugin Support (alpha)
|
||||
- **Два отдельных инструмента** с разными конфигами
|
||||
- Oxfmt в статусе **beta**
|
||||
- Под капотом: самый быстрый parser (3x SWC), resolver, minifier (alpha)
|
||||
- Бэкд: VoidZero (авторы Vite, Rolldown, Rspack)
|
||||
|
||||
## Comparison
|
||||
|
||||
| Критерий | Biome | Oxlint + Oxfmt |
|
||||
|----------|-------|----------------|
|
||||
| Замена ESLint | ✅ 500+ правил | ✅ 800+ правил |
|
||||
| Замена Prettier | ✅ 97%, stable | ⚠️ Oxfmt beta |
|
||||
| Один CLI вместо двух | ✅ | ❌ два инструмента |
|
||||
| Production-ready | ✅ LTS | ⚠️ formatter beta |
|
||||
| Конфигурация | 1 файл | 2 файла |
|
||||
| Скорость линтинга | ~35x vs ESLint | ~50-100x vs ESLint |
|
||||
| Скорость форматирования | ~35x vs Prettier | ~3x vs Biome |
|
||||
| Сообщество | mature | growing |
|
||||
|
||||
## Verdict: Biome
|
||||
|
||||
**Рекомендуется Biome** по трём причинам:
|
||||
|
||||
1. **Одна тулза** вместо двух — меньше конфигов, меньше CI-степов, меньше точек отказа
|
||||
2. **Production-ready** — formatter стабилен, LTS-релизы, тысячи проектов в продакшене
|
||||
3. **Плавная миграция** — встроенная команда `biome migrate eslint --write` переносит правила автоматически; `biome format` совместим с Prettier на 97%, не требуется массовых изменений кода
|
||||
|
||||
Oxlint + Oxfmt перспективны (быстрее, больше правил), но Oxfmt ещё beta, и два инструмента усложняют конфигурацию. Если Oxfmt выйдет в stable — вопрос стоит пересмотреть.
|
||||
@ -0,0 +1,57 @@
|
||||
# react-router-dom vs TanStack Router
|
||||
|
||||
## Context
|
||||
|
||||
Проект использует **react-router-dom v6** для клиентской маршрутизации. Требуется route-level code splitting (lazy loading). Также стоит вопрос о типобезопасности роутов и интеграции с уже используемым TanStack Query.
|
||||
|
||||
## Candidates
|
||||
|
||||
### react-router-dom v6 (текущий)
|
||||
|
||||
- Стабильный стандарт де-факто
|
||||
- Декларативный API: `<Routes>`, `<Route>`, `<Link>`
|
||||
- lazy loading через `React.lazy()` + `<Suspense>` — добавляется вручную
|
||||
- Search params: `useSearchParams()` — без типизации, строками
|
||||
- Параметры: `useParams()` — без типизации
|
||||
- Нет встроенных loaders / prefetching
|
||||
- Нет генерации типов
|
||||
- Размер: ~8KB gzip
|
||||
- Нет нативной интеграции с TanStack Query
|
||||
|
||||
### TanStack Router
|
||||
|
||||
- **Генерация RouteTree**: полная типобезопасность путей, параметров, search params
|
||||
- **Search params с Zod**: декларативная валидация и парсинг (Zod уже используется в проекте)
|
||||
- **Route loaders**: prefetching данных ДО рендера компонента, кеширование
|
||||
- **Code splitting built-in**: каждый роут ленивый по умолчанию, без `React.lazy` boilerplate
|
||||
- **Pending/Error/NotFound boundaries** на уровне роута
|
||||
- **Интеграция с TanStack Query**: loaders могут вызывать `queryClient.fetchQuery()` напрямую
|
||||
- **File-based routing**: чище организация кода (опционально)
|
||||
- Файл роута = route + component + loader + error/loading states
|
||||
- Размер: ~3-4KB gzip
|
||||
- 1.2B+ total downloads, 20M+ weekly
|
||||
|
||||
## Comparison
|
||||
|
||||
| Критерий | react-router-dom v6 | TanStack Router |
|
||||
|----------|---------------------|-----------------|
|
||||
| Типизация путей | ❌ строки | ✅ генерация |
|
||||
| Типизация params | ❌ `useParams()` без типа | ✅ autocomplete |
|
||||
| Search params typing | ❌ `useSearchParams()` строки | ✅ Zod-схемы |
|
||||
| Lazy loading | ⚠️ React.lazy + Suspense | ✅ built-in |
|
||||
| Loaders / prefetch | ❌ нет | ✅ |
|
||||
| TanStack Query synergy | ❌ | ✅ native |
|
||||
| Bundle size | ~8KB gzip | ~3-4KB gzip |
|
||||
| Migration effort | — | средняя |
|
||||
| Learning curve | низкая | средняя |
|
||||
|
||||
## Verdict: TanStack Router
|
||||
|
||||
**Рекомендуется TanStack Router**:
|
||||
|
||||
1. **Типобезопасность** — генерация типов исключает класс багов (опечатки в путях, невалидные search params)
|
||||
2. **Code splitting без boilerplate** — каждый роут грузится лениво автоматически, не нужно `React.lazy`
|
||||
3. **Синергия с TanStack Query** — уже используется в проекте; loaders дают prefetching до рендера
|
||||
4. **Zod** — уже используется в проекте для валидации форм; Router использует Zod для search params
|
||||
|
||||
Минусы: требуется переписывание всех роутов, компонентов навигации (`Link`, `useNavigate`) и тестов (`MemoryRouter` → `createMemoryRouter`). Каждый переезд — отдельная задача с тестированием.
|
||||
Loading…
x
Reference in New Issue
Block a user