docs: добавить правила монорепозиториев
- добавлен раздел о применении SLM в монорепозиториях - обновлена навигация документации и обзор архитектуры - обновлены сгенерированные артефакты документации
This commit is contained in:
@@ -8,6 +8,7 @@ const sidebar = [
|
|||||||
{ text: 'Слои', link: '/architecture/layers' },
|
{ text: 'Слои', link: '/architecture/layers' },
|
||||||
{ text: 'Модули', link: '/architecture/modules' },
|
{ text: 'Модули', link: '/architecture/modules' },
|
||||||
{ text: 'Сегменты', link: '/architecture/segments' },
|
{ text: 'Сегменты', link: '/architecture/segments' },
|
||||||
|
{ text: 'Монорепозитории', link: '/architecture/monorepo' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -8,8 +8,9 @@ Scoped Layered Module Design — модульная архитектура фр
|
|||||||
- [Слои](docs/architecture/layers.md) — уровни организации `src/`, направление зависимостей и зона ответственности каждого слоя.
|
- [Слои](docs/architecture/layers.md) — уровни организации `src/`, направление зависимостей и зона ответственности каждого слоя.
|
||||||
- [Модули](docs/architecture/modules.md) — границы ответственности, публичный API, типы модулей и отличие модуля от компонента.
|
- [Модули](docs/architecture/modules.md) — границы ответственности, публичный API, типы модулей и отличие модуля от компонента.
|
||||||
- [Сегменты](docs/architecture/segments.md) — внутренние папки модуля (`ui/`, `parts/`, `hooks/`, `types/` и другие) и правила размещения файлов.
|
- [Сегменты](docs/architecture/segments.md) — внутренние папки модуля (`ui/`, `parts/`, `hooks/`, `types/` и другие) и правила размещения файлов.
|
||||||
|
- [Монорепозитории](docs/architecture/monorepo.md) — применение SLM в `apps/` и `packages/`, правила выноса общих слоёв и ограничения для business.
|
||||||
|
|
||||||
Рекомендуемый порядок чтения: обзор → слои → модули → сегменты.
|
Рекомендуемый порядок чтения: обзор → слои → модули → сегменты → монорепозитории.
|
||||||
|
|
||||||
## Преимущества
|
## Преимущества
|
||||||
|
|
||||||
@@ -41,6 +42,10 @@ Cross-domain зависимости в бизнес-слое реализуют
|
|||||||
|
|
||||||
При росте проекта слои не теряют структуру — модули группируются по естественным признакам: бизнес-домены по субдоменам, страницы по разделам, UI-компоненты по уровню абстракции (примитивы и композиции).
|
При росте проекта слои не теряют структуру — модули группируются по естественным признакам: бизнес-домены по субдоменам, страницы по разделам, UI-компоненты по уровню абстракции (примитивы и композиции).
|
||||||
|
|
||||||
|
### Адаптация к монорепозиториям
|
||||||
|
|
||||||
|
SLM применяется внутри каждого приложения, а `packages/*` используются только для общего кода из слоёв `ui`, `infra` и `shared`. Бизнес-домены остаются внутри приложений, чтобы не размывать продуктовые границы.
|
||||||
|
|
||||||
## Происхождение
|
## Происхождение
|
||||||
|
|
||||||
SLM Design вырос на основе:
|
SLM Design вырос на основе:
|
||||||
|
|||||||
@@ -13,8 +13,9 @@ Scoped Layered Module Design — модульная архитектура фр
|
|||||||
- [Слои](/architecture/layers) — уровни организации `src/`, направление зависимостей и зона ответственности каждого слоя.
|
- [Слои](/architecture/layers) — уровни организации `src/`, направление зависимостей и зона ответственности каждого слоя.
|
||||||
- [Модули](/architecture/modules) — границы ответственности, публичный API, типы модулей и отличие модуля от компонента.
|
- [Модули](/architecture/modules) — границы ответственности, публичный API, типы модулей и отличие модуля от компонента.
|
||||||
- [Сегменты](/architecture/segments) — внутренние папки модуля (`ui/`, `parts/`, `hooks/`, `types/` и другие) и правила размещения файлов.
|
- [Сегменты](/architecture/segments) — внутренние папки модуля (`ui/`, `parts/`, `hooks/`, `types/` и другие) и правила размещения файлов.
|
||||||
|
- [Монорепозитории](/architecture/monorepo) — применение SLM в `apps/` и `packages/`, правила выноса общих слоёв и ограничения для business.
|
||||||
|
|
||||||
Рекомендуемый порядок чтения: обзор → слои → модули → сегменты.
|
Рекомендуемый порядок чтения: обзор → слои → модули → сегменты → монорепозитории.
|
||||||
|
|
||||||
## Преимущества
|
## Преимущества
|
||||||
|
|
||||||
@@ -46,6 +47,10 @@ Cross-domain зависимости в бизнес-слое реализуют
|
|||||||
|
|
||||||
При росте проекта слои не теряют структуру — модули группируются по естественным признакам: бизнес-домены по субдоменам, страницы по разделам, UI-компоненты по уровню абстракции (примитивы и композиции).
|
При росте проекта слои не теряют структуру — модули группируются по естественным признакам: бизнес-домены по субдоменам, страницы по разделам, UI-компоненты по уровню абстракции (примитивы и композиции).
|
||||||
|
|
||||||
|
### Адаптация к монорепозиториям
|
||||||
|
|
||||||
|
SLM применяется внутри каждого приложения, а `packages/*` используются только для общего кода из слоёв `ui`, `infra` и `shared`. Бизнес-домены остаются внутри приложений, чтобы не размывать продуктовые границы.
|
||||||
|
|
||||||
## Происхождение
|
## Происхождение
|
||||||
|
|
||||||
SLM Design вырос на основе:
|
SLM Design вырос на основе:
|
||||||
|
|||||||
235
docs/architecture/monorepo.md
Normal file
235
docs/architecture/monorepo.md
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
---
|
||||||
|
title: Монорепозитории
|
||||||
|
description: "Правила применения SLM Design для frontend-проектов, находящихся в монорепозитории"
|
||||||
|
---
|
||||||
|
|
||||||
|
# Монорепозитории
|
||||||
|
|
||||||
|
Раздел описывает, как применять SLM Design, когда фронтенд-проекты находятся в одном монорепозитории. В нём показано, что остаётся внутри приложений, что можно выносить в `packages/` и какие ограничения действуют для общих пакетов.
|
||||||
|
|
||||||
|
## Определение
|
||||||
|
|
||||||
|
**Монорепозиторий — внешний уровень организации нескольких фронтенд-приложений и общих пакетов. SLM применяется внутри каждого приложения, а frontend-пакеты, относящиеся к SLM, содержат переиспользуемый код, вынесенный из слоёв `ui`, `infra` и `shared`.**
|
||||||
|
|
||||||
|
## Базовая структура
|
||||||
|
|
||||||
|
Каждое приложение внутри `apps/` сохраняет собственную SLM-структуру в `src/`.
|
||||||
|
|
||||||
|
```text
|
||||||
|
repo/
|
||||||
|
├── apps/
|
||||||
|
│ ├── web/
|
||||||
|
│ │ └── src/
|
||||||
|
│ │ ├── app/
|
||||||
|
│ │ ├── layouts/
|
||||||
|
│ │ ├── screens/
|
||||||
|
│ │ ├── widgets/
|
||||||
|
│ │ ├── business/
|
||||||
|
│ │ ├── infra/
|
||||||
|
│ │ ├── ui/
|
||||||
|
│ │ └── shared/
|
||||||
|
│ └── admin/
|
||||||
|
│ └── src/
|
||||||
|
│ └── ...
|
||||||
|
└── packages/
|
||||||
|
├── ui/
|
||||||
|
│ ├── button/ # самостоятельный пакет UI-модуля
|
||||||
|
│ ├── input/ # самостоятельный пакет UI-модуля
|
||||||
|
│ └── modal/ # самостоятельный пакет UI-модуля
|
||||||
|
├── infra/
|
||||||
|
│ ├── theme/ # самостоятельный пакет infra-модуля
|
||||||
|
│ ├── backend-api/ # самостоятельный пакет infra-модуля
|
||||||
|
│ └── logger/ # самостоятельный пакет infra-модуля
|
||||||
|
└── shared/ # единый shared-пакет
|
||||||
|
├── package.json
|
||||||
|
└── src/
|
||||||
|
├── lib/ # переиспользуемые утилиты
|
||||||
|
├── helpers/ # переиспользуемые helpers
|
||||||
|
└── index.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
`apps/{app}/src` — граница SLM-приложения. `packages/*` находятся выше SLM и не добавляют новые архитектурные слои.
|
||||||
|
|
||||||
|
## Группировка frontend-пакетов
|
||||||
|
|
||||||
|
Frontend-пакеты, вынесенные из SLM-приложений, рекомендуется группировать по источнику кода: `ui`, `infra`, `shared`.
|
||||||
|
|
||||||
|
```text
|
||||||
|
packages/ui/* # пакеты UI-модулей
|
||||||
|
packages/infra/* # пакеты infra-модулей
|
||||||
|
packages/shared # единый shared-пакет
|
||||||
|
```
|
||||||
|
|
||||||
|
Эта группировка повторяет названия SLM-слоёв для навигации, но сама не является слоистой архитектурой внутри `packages/`. Монорепозиторий может содержать другие пакеты: tooling, конфиги, SDK, схемы, e2e и другие технические пакеты вне SLM.
|
||||||
|
|
||||||
|
## Пакет и модуль
|
||||||
|
|
||||||
|
Пакет не равен SLM-модулю: модуль — архитектурная единица внутри слоя приложения, package — единица монорепозитория для переиспользования, владения, сборки и публикации.
|
||||||
|
|
||||||
|
В `packages/ui/*` размещаются пакеты самостоятельных UI-модулей. В `packages/infra/*` размещаются пакеты самостоятельных инфраструктурных модулей. `packages/shared` устроен иначе: это единый пакет для переиспользуемых утилит, helpers и другого фундаментального кода без привязки к конкретному приложению.
|
||||||
|
|
||||||
|
```text
|
||||||
|
packages/ui/button/
|
||||||
|
packages/ui/modal/
|
||||||
|
packages/infra/theme/
|
||||||
|
packages/infra/backend-api/
|
||||||
|
packages/shared/
|
||||||
|
```
|
||||||
|
|
||||||
|
## Что остаётся в приложении
|
||||||
|
|
||||||
|
Слои `app`, `layouts`, `screens`, `widgets` и `business` остаются внутри конкретного приложения.
|
||||||
|
|
||||||
|
```text
|
||||||
|
apps/web/src/app/
|
||||||
|
apps/web/src/layouts/
|
||||||
|
apps/web/src/screens/
|
||||||
|
apps/web/src/widgets/
|
||||||
|
apps/web/src/business/
|
||||||
|
```
|
||||||
|
|
||||||
|
`app`, `layouts` и `screens` привязаны к роутингу, каркасу и страницам конкретного приложения. `widgets` не выносятся в пакеты, потому что это слой композиции интерфейса приложения.
|
||||||
|
|
||||||
|
`business` не выносится в `packages/*`. Домены остаются рядом со сценариями приложения, чтобы не превращать монорепозиторий в общий бизнес-слой.
|
||||||
|
|
||||||
|
## Что можно выносить
|
||||||
|
|
||||||
|
В пакеты выносится только код из `ui`, `infra` и `shared`, который потенциально будет использоваться в двух и более фронтенд-приложениях монорепозитория.
|
||||||
|
|
||||||
|
| Группа | Что выносить | Пример |
|
||||||
|
|--------|--------------|--------|
|
||||||
|
| `packages/ui/*` | Самостоятельные UI-модули без бизнес-логики | `packages/ui/button` |
|
||||||
|
| `packages/infra/*` | Самостоятельные технические сервисы | `packages/infra/backend-api` |
|
||||||
|
| `packages/shared` | Общие утилиты, helpers и фундаментальный код | `packages/shared` |
|
||||||
|
|
||||||
|
Пакет можно создавать сразу, если модуль имеет общую природу и ожидается его переиспользование между приложениями. App-specific код остаётся внутри приложения.
|
||||||
|
|
||||||
|
## UI-пакеты
|
||||||
|
|
||||||
|
В `packages/ui/*` размещаются переиспользуемые UI-модули.
|
||||||
|
|
||||||
|
```text
|
||||||
|
packages/ui/button/
|
||||||
|
├── package.json
|
||||||
|
└── src/
|
||||||
|
├── button.tsx
|
||||||
|
├── styles/
|
||||||
|
├── types/
|
||||||
|
└── index.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
UI-пакет не содержит бизнес-логику, обращения к API, сценарные хуки приложения и композицию страниц.
|
||||||
|
|
||||||
|
## Infra-пакеты
|
||||||
|
|
||||||
|
В `packages/infra/*` размещаются переиспользуемые инфраструктурные модули.
|
||||||
|
|
||||||
|
```text
|
||||||
|
packages/infra/backend-api/
|
||||||
|
├── package.json
|
||||||
|
└── src/
|
||||||
|
├── clients/
|
||||||
|
├── config/
|
||||||
|
├── types/
|
||||||
|
└── index.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
Привязанные к конкретному приложению сервисы остаются в `apps/{app}/src/infra`. Например, локализация со словарями конкретного продукта остаётся в приложении; общим пакетом может быть только переиспользуемый i18n-движок.
|
||||||
|
|
||||||
|
## Shared-пакет
|
||||||
|
|
||||||
|
`packages/shared` является единым пакетом.
|
||||||
|
|
||||||
|
```text
|
||||||
|
packages/shared/
|
||||||
|
├── package.json
|
||||||
|
└── src/
|
||||||
|
├── lib/
|
||||||
|
├── helpers/
|
||||||
|
└── index.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
В `packages/shared` сразу выносится общий фундаментальный код: чистые функции, helpers, утилиты, независимые константы и другой код без знания о продукте.
|
||||||
|
|
||||||
|
Проектные стили, типы приложения, продуктовые конфиги и ресурсы, завязанные на одно приложение, в общий `shared` не выносятся.
|
||||||
|
|
||||||
|
## Имена пакетов и импорты
|
||||||
|
|
||||||
|
Путь импорта задаётся `name` в `package.json`, а не расположением директории.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "@repo/theme"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```text
|
||||||
|
packages/infra/theme/package.json
|
||||||
|
```
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { ThemeProvider } from '@repo/theme'
|
||||||
|
```
|
||||||
|
|
||||||
|
Пакеты должны импортироваться только через публичный API. Deep imports внутрь пакета запрещены.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// Хорошо
|
||||||
|
import { Button } from '@repo/button'
|
||||||
|
|
||||||
|
// Плохо
|
||||||
|
import { Button } from '@repo/button/src/button'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Зависимости
|
||||||
|
|
||||||
|
На уровне монорепозитория приложения зависят от пакетов, а пакеты не зависят от приложений.
|
||||||
|
|
||||||
|
```text
|
||||||
|
apps → packages
|
||||||
|
packages -/→ apps
|
||||||
|
```
|
||||||
|
|
||||||
|
Внутри приложения продолжает действовать обычное направление зависимостей SLM.
|
||||||
|
|
||||||
|
```text
|
||||||
|
app → [ layouts | screens ] → widgets → business → infra → ui → shared
|
||||||
|
```
|
||||||
|
|
||||||
|
Пакеты не должны нарушать природу своей группы: `packages/ui/*` не импортирует `packages/infra/*`, `packages/shared` не импортирует другие группы, а `packages/infra/*` не знает о приложениях.
|
||||||
|
|
||||||
|
## Когда не выносить
|
||||||
|
|
||||||
|
Не выносите код в пакет, если он не может быть использован в двух и более фронтенд-приложениях, зависит от роутинга или страниц, содержит бизнес-логику, отражает продуктовую композицию конкретного интерфейса или не имеет стабильного публичного API.
|
||||||
|
|
||||||
|
Фактическое использование в одном приложении не запрещает пакет, если модуль имеет общую природу и потенциально нужен нескольким приложениям.
|
||||||
|
|
||||||
|
```text
|
||||||
|
# Плохо
|
||||||
|
apps/web/src/screens/home/parts/promo-section/
|
||||||
|
packages/ui/promo-section/
|
||||||
|
```
|
||||||
|
|
||||||
|
Если блок нужен только одной странице или отражает продуктовую композицию конкретного приложения, он остаётся локальным `parts/`-модулем.
|
||||||
|
|
||||||
|
## Конфигурационные пакеты
|
||||||
|
|
||||||
|
Конфигурационные пакеты не относятся к SLM-архитектуре.
|
||||||
|
|
||||||
|
Если в монорепозитории есть общие настройки TypeScript, ESLint, сборки или форматирования, они относятся к tooling-инфраструктуре репозитория. Такие пакеты могут находиться в `packages/`, но их структура зависит от выбранного инструментария и не участвует в правилах слоёв внутри `src/`.
|
||||||
|
|
||||||
|
## Правила
|
||||||
|
|
||||||
|
- SLM применяется внутри каждого `apps/{app}/src`.
|
||||||
|
- Frontend-пакеты, вынесенные из SLM-приложений, группируются в `packages/ui`, `packages/infra`, `packages/shared`.
|
||||||
|
- Группы `packages/ui`, `packages/infra`, `packages/shared` не являются SLM-слоями.
|
||||||
|
- В `packages/ui/*` размещаются пакеты самостоятельных UI-модулей.
|
||||||
|
- В `packages/infra/*` размещаются пакеты самостоятельных инфраструктурных модулей.
|
||||||
|
- `packages/shared` является единым пакетом для переиспользуемых утилит и helpers.
|
||||||
|
- Модуль можно размещать в пакете, если он потенциально будет использоваться в двух и более фронтенд-приложениях.
|
||||||
|
- `business`, `app`, `layouts`, `screens`, `widgets` не выносятся в пакеты.
|
||||||
|
- Проектные стили, типы приложения и продуктовые конфиги не выносятся в `packages/shared`.
|
||||||
|
- Пакеты не импортируют приложения.
|
||||||
|
- Межпакетные импорты идут только через публичный API.
|
||||||
|
- Deep imports внутрь пакетов запрещены.
|
||||||
|
- Локальная колокация важнее преждевременного выноса в `packages/*`.
|
||||||
@@ -12,6 +12,7 @@ title: Документация
|
|||||||
- Если проектируете структуру `src/` — откройте [Слои](/architecture/layers).
|
- Если проектируете структуру `src/` — откройте [Слои](/architecture/layers).
|
||||||
- Если создаёте новый домен или блок интерфейса — используйте [Модули](/architecture/modules).
|
- Если создаёте новый домен или блок интерфейса — используйте [Модули](/architecture/modules).
|
||||||
- Если выбираете папку внутри модуля — смотрите [Сегменты](/architecture/segments).
|
- Если выбираете папку внутри модуля — смотрите [Сегменты](/architecture/segments).
|
||||||
|
- Если адаптируете SLM к монорепозиторию — откройте [Монорепозитории](/architecture/monorepo).
|
||||||
|
|
||||||
## Разделы
|
## Разделы
|
||||||
|
|
||||||
@@ -21,6 +22,7 @@ title: Документация
|
|||||||
| [Слои](/architecture/layers) | Нужно определить, где должен жить код и какие зависимости допустимы. |
|
| [Слои](/architecture/layers) | Нужно определить, где должен жить код и какие зависимости допустимы. |
|
||||||
| [Модули](/architecture/modules) | Нужно оформить границы модуля, публичный API или фабрику. |
|
| [Модули](/architecture/modules) | Нужно оформить границы модуля, публичный API или фабрику. |
|
||||||
| [Сегменты](/architecture/segments) | Нужно выбрать внутреннюю папку для компонента, хука, стиля, типа или конфига. |
|
| [Сегменты](/architecture/segments) | Нужно выбрать внутреннюю папку для компонента, хука, стиля, типа или конфига. |
|
||||||
|
| [Монорепозитории](/architecture/monorepo) | Нужно понять, что можно выносить в `packages/*` и какие слои остаются внутри приложения. |
|
||||||
|
|
||||||
## Для ассистентов
|
## Для ассистентов
|
||||||
|
|
||||||
|
|||||||
@@ -13,8 +13,9 @@ Scoped Layered Module Design — модульная архитектура фр
|
|||||||
- [Слои](#слои) — уровни организации `src/`, направление зависимостей и зона ответственности каждого слоя.
|
- [Слои](#слои) — уровни организации `src/`, направление зависимостей и зона ответственности каждого слоя.
|
||||||
- [Модули](#модули) — границы ответственности, публичный API, типы модулей и отличие модуля от компонента.
|
- [Модули](#модули) — границы ответственности, публичный API, типы модулей и отличие модуля от компонента.
|
||||||
- [Сегменты](#сегменты) — внутренние папки модуля (`ui/`, `parts/`, `hooks/`, `types/` и другие) и правила размещения файлов.
|
- [Сегменты](#сегменты) — внутренние папки модуля (`ui/`, `parts/`, `hooks/`, `types/` и другие) и правила размещения файлов.
|
||||||
|
- [Монорепозитории](#монорепозитории) — применение SLM в `apps/` и `packages/`, правила выноса общих слоёв и ограничения для business.
|
||||||
|
|
||||||
Рекомендуемый порядок чтения: обзор → слои → модули → сегменты.
|
Рекомендуемый порядок чтения: обзор → слои → модули → сегменты → монорепозитории.
|
||||||
|
|
||||||
## Преимущества
|
## Преимущества
|
||||||
|
|
||||||
@@ -46,6 +47,10 @@ Cross-domain зависимости в бизнес-слое реализуют
|
|||||||
|
|
||||||
При росте проекта слои не теряют структуру — модули группируются по естественным признакам: бизнес-домены по субдоменам, страницы по разделам, UI-компоненты по уровню абстракции (примитивы и композиции).
|
При росте проекта слои не теряют структуру — модули группируются по естественным признакам: бизнес-домены по субдоменам, страницы по разделам, UI-компоненты по уровню абстракции (примитивы и композиции).
|
||||||
|
|
||||||
|
### Адаптация к монорепозиториям
|
||||||
|
|
||||||
|
SLM применяется внутри каждого приложения, а `packages/*` используются только для общего кода из слоёв `ui`, `infra` и `shared`. Бизнес-домены остаются внутри приложений, чтобы не размывать продуктовые границы.
|
||||||
|
|
||||||
## Происхождение
|
## Происхождение
|
||||||
|
|
||||||
SLM Design вырос на основе:
|
SLM Design вырос на основе:
|
||||||
@@ -821,4 +826,236 @@ lib/
|
|||||||
config/
|
config/
|
||||||
├── routes.ts
|
├── routes.ts
|
||||||
└── constants.ts
|
└── constants.ts
|
||||||
```
|
```
|
||||||
|
|
||||||
|
<!-- /docs/architecture/monorepo -->
|
||||||
|
## Монорепозитории
|
||||||
|
|
||||||
|
Раздел описывает, как применять SLM Design, когда фронтенд-проекты находятся в одном монорепозитории. В нём показано, что остаётся внутри приложений, что можно выносить в `packages/` и какие ограничения действуют для общих пакетов.
|
||||||
|
|
||||||
|
### Определение
|
||||||
|
|
||||||
|
**Монорепозиторий — внешний уровень организации нескольких фронтенд-приложений и общих пакетов. SLM применяется внутри каждого приложения, а frontend-пакеты, относящиеся к SLM, содержат переиспользуемый код, вынесенный из слоёв `ui`, `infra` и `shared`.**
|
||||||
|
|
||||||
|
### Базовая структура
|
||||||
|
|
||||||
|
Каждое приложение внутри `apps/` сохраняет собственную SLM-структуру в `src/`.
|
||||||
|
|
||||||
|
```text
|
||||||
|
repo/
|
||||||
|
├── apps/
|
||||||
|
│ ├── web/
|
||||||
|
│ │ └── src/
|
||||||
|
│ │ ├── app/
|
||||||
|
│ │ ├── layouts/
|
||||||
|
│ │ ├── screens/
|
||||||
|
│ │ ├── widgets/
|
||||||
|
│ │ ├── business/
|
||||||
|
│ │ ├── infra/
|
||||||
|
│ │ ├── ui/
|
||||||
|
│ │ └── shared/
|
||||||
|
│ └── admin/
|
||||||
|
│ └── src/
|
||||||
|
│ └── ...
|
||||||
|
└── packages/
|
||||||
|
├── ui/
|
||||||
|
│ ├── button/ # самостоятельный пакет UI-модуля
|
||||||
|
│ ├── input/ # самостоятельный пакет UI-модуля
|
||||||
|
│ └── modal/ # самостоятельный пакет UI-модуля
|
||||||
|
├── infra/
|
||||||
|
│ ├── theme/ # самостоятельный пакет infra-модуля
|
||||||
|
│ ├── backend-api/ # самостоятельный пакет infra-модуля
|
||||||
|
│ └── logger/ # самостоятельный пакет infra-модуля
|
||||||
|
└── shared/ # единый shared-пакет
|
||||||
|
├── package.json
|
||||||
|
└── src/
|
||||||
|
├── lib/ # переиспользуемые утилиты
|
||||||
|
├── helpers/ # переиспользуемые helpers
|
||||||
|
└── index.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
`apps/{app}/src` — граница SLM-приложения. `packages/*` находятся выше SLM и не добавляют новые архитектурные слои.
|
||||||
|
|
||||||
|
### Группировка frontend-пакетов
|
||||||
|
|
||||||
|
Frontend-пакеты, вынесенные из SLM-приложений, рекомендуется группировать по источнику кода: `ui`, `infra`, `shared`.
|
||||||
|
|
||||||
|
```text
|
||||||
|
packages/ui/* # пакеты UI-модулей
|
||||||
|
packages/infra/* # пакеты infra-модулей
|
||||||
|
packages/shared # единый shared-пакет
|
||||||
|
```
|
||||||
|
|
||||||
|
Эта группировка повторяет названия SLM-слоёв для навигации, но сама не является слоистой архитектурой внутри `packages/`. Монорепозиторий может содержать другие пакеты: tooling, конфиги, SDK, схемы, e2e и другие технические пакеты вне SLM.
|
||||||
|
|
||||||
|
### Пакет и модуль
|
||||||
|
|
||||||
|
Пакет не равен SLM-модулю: модуль — архитектурная единица внутри слоя приложения, package — единица монорепозитория для переиспользования, владения, сборки и публикации.
|
||||||
|
|
||||||
|
В `packages/ui/*` размещаются пакеты самостоятельных UI-модулей. В `packages/infra/*` размещаются пакеты самостоятельных инфраструктурных модулей. `packages/shared` устроен иначе: это единый пакет для переиспользуемых утилит, helpers и другого фундаментального кода без привязки к конкретному приложению.
|
||||||
|
|
||||||
|
```text
|
||||||
|
packages/ui/button/
|
||||||
|
packages/ui/modal/
|
||||||
|
packages/infra/theme/
|
||||||
|
packages/infra/backend-api/
|
||||||
|
packages/shared/
|
||||||
|
```
|
||||||
|
|
||||||
|
### Что остаётся в приложении
|
||||||
|
|
||||||
|
Слои `app`, `layouts`, `screens`, `widgets` и `business` остаются внутри конкретного приложения.
|
||||||
|
|
||||||
|
```text
|
||||||
|
apps/web/src/app/
|
||||||
|
apps/web/src/layouts/
|
||||||
|
apps/web/src/screens/
|
||||||
|
apps/web/src/widgets/
|
||||||
|
apps/web/src/business/
|
||||||
|
```
|
||||||
|
|
||||||
|
`app`, `layouts` и `screens` привязаны к роутингу, каркасу и страницам конкретного приложения. `widgets` не выносятся в пакеты, потому что это слой композиции интерфейса приложения.
|
||||||
|
|
||||||
|
`business` не выносится в `packages/*`. Домены остаются рядом со сценариями приложения, чтобы не превращать монорепозиторий в общий бизнес-слой.
|
||||||
|
|
||||||
|
### Что можно выносить
|
||||||
|
|
||||||
|
В пакеты выносится только код из `ui`, `infra` и `shared`, который потенциально будет использоваться в двух и более фронтенд-приложениях монорепозитория.
|
||||||
|
|
||||||
|
| Группа | Что выносить | Пример |
|
||||||
|
|--------|--------------|--------|
|
||||||
|
| `packages/ui/*` | Самостоятельные UI-модули без бизнес-логики | `packages/ui/button` |
|
||||||
|
| `packages/infra/*` | Самостоятельные технические сервисы | `packages/infra/backend-api` |
|
||||||
|
| `packages/shared` | Общие утилиты, helpers и фундаментальный код | `packages/shared` |
|
||||||
|
|
||||||
|
Пакет можно создавать сразу, если модуль имеет общую природу и ожидается его переиспользование между приложениями. App-specific код остаётся внутри приложения.
|
||||||
|
|
||||||
|
### UI-пакеты
|
||||||
|
|
||||||
|
В `packages/ui/*` размещаются переиспользуемые UI-модули.
|
||||||
|
|
||||||
|
```text
|
||||||
|
packages/ui/button/
|
||||||
|
├── package.json
|
||||||
|
└── src/
|
||||||
|
├── button.tsx
|
||||||
|
├── styles/
|
||||||
|
├── types/
|
||||||
|
└── index.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
UI-пакет не содержит бизнес-логику, обращения к API, сценарные хуки приложения и композицию страниц.
|
||||||
|
|
||||||
|
### Infra-пакеты
|
||||||
|
|
||||||
|
В `packages/infra/*` размещаются переиспользуемые инфраструктурные модули.
|
||||||
|
|
||||||
|
```text
|
||||||
|
packages/infra/backend-api/
|
||||||
|
├── package.json
|
||||||
|
└── src/
|
||||||
|
├── clients/
|
||||||
|
├── config/
|
||||||
|
├── types/
|
||||||
|
└── index.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
Привязанные к конкретному приложению сервисы остаются в `apps/{app}/src/infra`. Например, локализация со словарями конкретного продукта остаётся в приложении; общим пакетом может быть только переиспользуемый i18n-движок.
|
||||||
|
|
||||||
|
### Shared-пакет
|
||||||
|
|
||||||
|
`packages/shared` является единым пакетом.
|
||||||
|
|
||||||
|
```text
|
||||||
|
packages/shared/
|
||||||
|
├── package.json
|
||||||
|
└── src/
|
||||||
|
├── lib/
|
||||||
|
├── helpers/
|
||||||
|
└── index.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
В `packages/shared` сразу выносится общий фундаментальный код: чистые функции, helpers, утилиты, независимые константы и другой код без знания о продукте.
|
||||||
|
|
||||||
|
Проектные стили, типы приложения, продуктовые конфиги и ресурсы, завязанные на одно приложение, в общий `shared` не выносятся.
|
||||||
|
|
||||||
|
### Имена пакетов и импорты
|
||||||
|
|
||||||
|
Путь импорта задаётся `name` в `package.json`, а не расположением директории.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "@repo/theme"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```text
|
||||||
|
packages/infra/theme/package.json
|
||||||
|
```
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { ThemeProvider } from '@repo/theme'
|
||||||
|
```
|
||||||
|
|
||||||
|
Пакеты должны импортироваться только через публичный API. Deep imports внутрь пакета запрещены.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// Хорошо
|
||||||
|
import { Button } from '@repo/button'
|
||||||
|
|
||||||
|
// Плохо
|
||||||
|
import { Button } from '@repo/button/src/button'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Зависимости
|
||||||
|
|
||||||
|
На уровне монорепозитория приложения зависят от пакетов, а пакеты не зависят от приложений.
|
||||||
|
|
||||||
|
```text
|
||||||
|
apps → packages
|
||||||
|
packages -/→ apps
|
||||||
|
```
|
||||||
|
|
||||||
|
Внутри приложения продолжает действовать обычное направление зависимостей SLM.
|
||||||
|
|
||||||
|
```text
|
||||||
|
app → [ layouts | screens ] → widgets → business → infra → ui → shared
|
||||||
|
```
|
||||||
|
|
||||||
|
Пакеты не должны нарушать природу своей группы: `packages/ui/*` не импортирует `packages/infra/*`, `packages/shared` не импортирует другие группы, а `packages/infra/*` не знает о приложениях.
|
||||||
|
|
||||||
|
### Когда не выносить
|
||||||
|
|
||||||
|
Не выносите код в пакет, если он не может быть использован в двух и более фронтенд-приложениях, зависит от роутинга или страниц, содержит бизнес-логику, отражает продуктовую композицию конкретного интерфейса или не имеет стабильного публичного API.
|
||||||
|
|
||||||
|
Фактическое использование в одном приложении не запрещает пакет, если модуль имеет общую природу и потенциально нужен нескольким приложениям.
|
||||||
|
|
||||||
|
```text
|
||||||
|
# Плохо
|
||||||
|
apps/web/src/screens/home/parts/promo-section/
|
||||||
|
packages/ui/promo-section/
|
||||||
|
```
|
||||||
|
|
||||||
|
Если блок нужен только одной странице или отражает продуктовую композицию конкретного приложения, он остаётся локальным `parts/`-модулем.
|
||||||
|
|
||||||
|
### Конфигурационные пакеты
|
||||||
|
|
||||||
|
Конфигурационные пакеты не относятся к SLM-архитектуре.
|
||||||
|
|
||||||
|
Если в монорепозитории есть общие настройки TypeScript, ESLint, сборки или форматирования, они относятся к tooling-инфраструктуре репозитория. Такие пакеты могут находиться в `packages/`, но их структура зависит от выбранного инструментария и не участвует в правилах слоёв внутри `src/`.
|
||||||
|
|
||||||
|
### Правила
|
||||||
|
|
||||||
|
- SLM применяется внутри каждого `apps/{app}/src`.
|
||||||
|
- Frontend-пакеты, вынесенные из SLM-приложений, группируются в `packages/ui`, `packages/infra`, `packages/shared`.
|
||||||
|
- Группы `packages/ui`, `packages/infra`, `packages/shared` не являются SLM-слоями.
|
||||||
|
- В `packages/ui/*` размещаются пакеты самостоятельных UI-модулей.
|
||||||
|
- В `packages/infra/*` размещаются пакеты самостоятельных инфраструктурных модулей.
|
||||||
|
- `packages/shared` является единым пакетом для переиспользуемых утилит и helpers.
|
||||||
|
- Модуль можно размещать в пакете, если он потенциально будет использоваться в двух и более фронтенд-приложениях.
|
||||||
|
- `business`, `app`, `layouts`, `screens`, `widgets` не выносятся в пакеты.
|
||||||
|
- Проектные стили, типы приложения и продуктовые конфиги не выносятся в `packages/shared`.
|
||||||
|
- Пакеты не импортируют приложения.
|
||||||
|
- Межпакетные импорты идут только через публичный API.
|
||||||
|
- Deep imports внутрь пакетов запрещены.
|
||||||
|
- Локальная колокация важнее преждевременного выноса в `packages/*`.
|
||||||
Reference in New Issue
Block a user