docs: переработать архитектуру и прикладные разделы компонента и модуля
- обновлена каноническая спецификация SLM Design из slm-design.gromlab.ru - файлы архитектуры перенесены из reference/ в basics/architecture/ - добавлена предупреждающая плашка о локальной копии архитектуры - infrastructure/ переименован в infra/ по канону спецификации - прикладной раздел «Компонент» переписан: определение заменено ссылкой на архитектуру, добавлен пример UserStatus с типами, стилями и JSDoc - прикладной раздел «Модуль» переписан: показаны три типа модулей (UI, бизнес, инфраструктурный), добавлен пример фабрики бизнес-модуля - добавлен запрет ручного создания компонентов: только через кодогенератор - обновлён раздел типизации: возвращаемый тип React-компонентов не указывается - обновлён шаблон компонента в templates-create: суффикс -props.type.ts - обновлены ссылки в page-level, project-structure, aliases - сгенерированы llms.txt, llms-full.txt, README и публичные копии
This commit is contained in:
@@ -19,9 +19,9 @@ const sidebar = [
|
|||||||
collapsed: true,
|
collapsed: true,
|
||||||
items: [
|
items: [
|
||||||
{ text: 'Обзор', link: '/docs/basics/architecture/' },
|
{ text: 'Обзор', link: '/docs/basics/architecture/' },
|
||||||
{ text: 'Слои', link: '/docs/basics/architecture/reference/layers' },
|
{ text: 'Слои', link: '/docs/basics/architecture/layers' },
|
||||||
{ text: 'Модули', link: '/docs/basics/architecture/reference/modules' },
|
{ text: 'Модули', link: '/docs/basics/architecture/modules' },
|
||||||
{ text: 'Сегменты', link: '/docs/basics/architecture/reference/segments' },
|
{ text: 'Сегменты', link: '/docs/basics/architecture/segments' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{ text: 'Стиль кода', link: '/docs/basics/code-style' },
|
{ text: 'Стиль кода', link: '/docs/basics/code-style' },
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ description: Что AI-агент обязан прочитать перед н
|
|||||||
### 1. Архитектура (КРИТИЧЕСКИ ВАЖНО)
|
### 1. Архитектура (КРИТИЧЕСКИ ВАЖНО)
|
||||||
|
|
||||||
* [Архитектура: Обзор](./basics/architecture/index.md)
|
* [Архитектура: Обзор](./basics/architecture/index.md)
|
||||||
* [Архитектура: Слои](./basics/architecture/reference/layers.md)
|
* [Архитектура: Слои](./basics/architecture/layers.md)
|
||||||
* [Архитектура: Модули](./basics/architecture/reference/modules.md)
|
* [Архитектура: Модули](./basics/architecture/modules.md)
|
||||||
* [Архитектура: Сегменты](./basics/architecture/reference/segments.md)
|
* [Архитектура: Сегменты](./basics/architecture/segments.md)
|
||||||
|
|
||||||
**Архитектура — это самое важное в проекте.**
|
**Архитектура — это самое важное в проекте.**
|
||||||
|
|
||||||
|
|||||||
@@ -12,9 +12,9 @@
|
|||||||
- [Технологии и библиотеки](./basics/tech-stack.md) — Какие библиотеки и инструменты используются в проекте.
|
- [Технологии и библиотеки](./basics/tech-stack.md) — Какие библиотеки и инструменты используются в проекте.
|
||||||
- [Именование](./basics/naming.md) — Как называть переменные, файлы и прочие сущности в коде.
|
- [Именование](./basics/naming.md) — Как называть переменные, файлы и прочие сущности в коде.
|
||||||
- [Архитектура: Обзор](./basics/architecture/index.md) — Архитектурный подход проекта: что такое SLM и как он устроен.
|
- [Архитектура: Обзор](./basics/architecture/index.md) — Архитектурный подход проекта: что такое SLM и как он устроен.
|
||||||
- [Архитектура: Слои](./basics/architecture/reference/layers.md) — Из каких слоёв состоит SLM-архитектура и как они связаны.
|
- [Архитектура: Слои](./basics/architecture/layers.md) — Из каких слоёв состоит SLM-архитектура и как они связаны.
|
||||||
- [Архитектура: Модули](./basics/architecture/reference/modules.md) — Что такое модуль в SLM-архитектуре и как он устроен.
|
- [Архитектура: Модули](./basics/architecture/modules.md) — Что такое модуль в SLM-архитектуре и как он устроен.
|
||||||
- [Архитектура: Сегменты](./basics/architecture/reference/segments.md) — Что такое сегмент модуля в SLM-архитектуре и какие они бывают.
|
- [Архитектура: Сегменты](./basics/architecture/segments.md) — Что такое сегмент модуля в SLM-архитектуре и какие они бывают.
|
||||||
- [Стиль кода](./basics/code-style.md) — Как оформляется код в проекте.
|
- [Стиль кода](./basics/code-style.md) — Как оформляется код в проекте.
|
||||||
- [Документирование](./basics/documentation.md) — Что и как документировать в коде.
|
- [Документирование](./basics/documentation.md) — Что и как документировать в коде.
|
||||||
- [Типизация](./basics/typing.md) — Как типизируется код в проекте.
|
- [Типизация](./basics/typing.md) — Как типизируется код в проекте.
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ keywords: [алиасы, aliases, paths, tsconfig, импорты, baseUrl, app,
|
|||||||
- **Каждый импорт между модулями — через алиас слоя.** Относительные пути (`../../`) запрещены за пределами своего модуля.
|
- **Каждый импорт между модулями — через алиас слоя.** Относительные пути (`../../`) запрещены за пределами своего модуля.
|
||||||
- **Внутри одного модуля** допустимы относительные импорты (`./model`, `./ui/button`) — это часть инкапсуляции модуля.
|
- **Внутри одного модуля** допустимы относительные импорты (`./model`, `./ui/button`) — это часть инкапсуляции модуля.
|
||||||
- **Префикс `@/` не используется.** Имя слоя — само по себе адрес.
|
- **Префикс `@/` не используется.** Имя слоя — само по себе адрес.
|
||||||
- **Направление импортов** определяется архитектурой, не алиасами. Алиас разрешает импорт технически, но не отменяет правила слоёв (→ [Слои](/docs/basics/architecture/reference/layers)).
|
- **Направление импортов** определяется архитектурой, не алиасами. Алиас разрешает импорт технически, но не отменяет правила слоёв (→ [Слои](/docs/basics/architecture/layers)).
|
||||||
|
|
||||||
**Хорошо**
|
**Хорошо**
|
||||||
|
|
||||||
|
|||||||
@@ -1,201 +1,165 @@
|
|||||||
---
|
---
|
||||||
title: Компонент
|
title: Компонент
|
||||||
description: Как создавать React-компоненты внутри SLM-модулей.
|
description: Как должен выглядеть сгенерированный React-компонент внутри SLM-модуля.
|
||||||
---
|
---
|
||||||
|
|
||||||
# Компонент
|
# Компонент
|
||||||
|
|
||||||
Как создавать React-компоненты внутри SLM-модулей.
|
Как должен выглядеть сгенерированный React-компонент внутри SLM-модуля.
|
||||||
|
|
||||||
## Назначение
|
## Назначение
|
||||||
|
|
||||||
Компонент — минимальная UI-единица проекта. Это один `.tsx` файл без собственной папки, сегментов и публичного API.
|
Архитектурное определение компонента описано в разделе [Модули → Компонент](/docs/basics/architecture/modules#компонент), а структура сегмента `ui/` — в разделе [Сегменты → ui/](/docs/basics/architecture/segments#сегмент-ui).
|
||||||
|
|
||||||
Компонент может использовать стили, типы, хуки и другие ресурсы родительского модуля. Наличие связанных файлов в `styles/` или `types/` не превращает компонент в модуль.
|
Эта страница не повторяет архитектурные ограничения. Она показывает, каким должен быть результат генерации компонента: структура папки, `.tsx`, типы, стили и локальный экспорт.
|
||||||
|
|
||||||
## Компонент или модуль
|
::: danger Компоненты не создаются вручную
|
||||||
|
Компоненты в проекте создаются только через кодогенератор: через [VS Code](/docs/applied/templates/templates-usage#через-vs-code) или [CLI](/docs/applied/templates/templates-usage#через-cli).
|
||||||
|
|
||||||
Классификация определяется границей владения:
|
Ручное создание компонента запрещено. Это грубое нарушение правил работы в проекте для разработчика и AI-ассистента.
|
||||||
|
|
||||||
- `component` — один `.tsx` файл внутри модуля;
|
Если в проекте нет шаблона `.templates/component`, сначала создайте шаблон по разделу [Создание шаблонов](/docs/applied/templates/templates-create), и только потом генерируйте компонент на его основе.
|
||||||
- `module` — папка с `index.ts`, сегментами и собственной публичной границей.
|
:::
|
||||||
|
|
||||||
|
## Создание
|
||||||
|
|
||||||
|
1. Проверьте, что в проекте есть шаблон `.templates/component`.
|
||||||
|
2. Если шаблона нет — создайте его по разделу [Создание шаблонов](/docs/applied/templates/templates-create).
|
||||||
|
3. Сгенерируйте компонент через [VS Code или CLI](/docs/applied/templates/templates-usage).
|
||||||
|
|
||||||
|
Структура и код ниже показывают ожидаемый результат генерации. Их нельзя использовать как инструкцию для ручного создания файлов.
|
||||||
|
|
||||||
|
## Структура
|
||||||
|
|
||||||
|
Компонент размещается в `ui/{component-name}/` родительского модуля.
|
||||||
|
|
||||||
|
Для каждого компонента обязательны `.tsx`, типы, стили и локальный `index.ts`.
|
||||||
|
|
||||||
```text
|
```text
|
||||||
user/
|
user-card/
|
||||||
├── ui/
|
|
||||||
│ └── user-avatar.tsx # компонент
|
|
||||||
├── styles/
|
|
||||||
│ └── user-avatar.module.css # ресурс родительского модуля
|
|
||||||
├── types/
|
|
||||||
│ └── user-avatar.type.ts # ресурс родительского модуля
|
|
||||||
└── user.tsx # корневой компонент модуля
|
|
||||||
```
|
|
||||||
|
|
||||||
`user-avatar.tsx` остаётся компонентом, потому что у него нет собственной папки, `index.ts` и сегментов.
|
|
||||||
|
|
||||||
## Где размещать
|
|
||||||
|
|
||||||
Компонент размещается внутри модуля:
|
|
||||||
|
|
||||||
- В корне модуля, если это главная UI-сущность модуля.
|
|
||||||
- В `ui/`, если это вспомогательный компонент модуля.
|
|
||||||
|
|
||||||
```text
|
|
||||||
user/
|
|
||||||
├── ui/
|
|
||||||
│ └── user-avatar.tsx
|
|
||||||
├── styles/
|
|
||||||
│ ├── user.module.css
|
|
||||||
│ └── user-avatar.module.css
|
|
||||||
├── types/
|
|
||||||
│ ├── user.type.ts
|
|
||||||
│ └── user-avatar.type.ts
|
|
||||||
├── user.tsx
|
|
||||||
└── index.ts
|
|
||||||
```
|
|
||||||
|
|
||||||
`user.tsx` — корневой компонент модуля. `ui/user-avatar.tsx` — вспомогательный компонент этого же модуля.
|
|
||||||
|
|
||||||
## Что запрещено
|
|
||||||
|
|
||||||
- Заворачивать компонент в папку: `ui/header/header.tsx`.
|
|
||||||
- Создавать для компонента отдельный `index.ts`.
|
|
||||||
- Создавать собственные сегменты внутри папки компонента: `ui/header/styles/`, `ui/header/types/`, `ui/header/hooks/` и т.п.
|
|
||||||
- Декларировать внутри `.tsx` сторы, сервисы, API-клиенты, мапперы или утилиты. Для этого есть сегменты родительского модуля.
|
|
||||||
- Размещать бизнес-правила прямо в компоненте. Компонент может использовать готовые зависимости модуля, но не определяет их.
|
|
||||||
- Размещать компонент в `parts/` напрямую. `parts/` содержит только модули.
|
|
||||||
|
|
||||||
**Плохо**
|
|
||||||
|
|
||||||
```text
|
|
||||||
user/
|
|
||||||
└── ui/
|
└── ui/
|
||||||
└── user-avatar/
|
└── user-status/
|
||||||
├── styles/
|
├── styles/
|
||||||
│ └── user-avatar.module.css
|
│ └── user-status.module.css
|
||||||
├── user-avatar.tsx
|
├── types/
|
||||||
|
│ └── user-status-props.type.ts
|
||||||
|
├── user-status.tsx
|
||||||
└── index.ts
|
└── index.ts
|
||||||
```
|
```
|
||||||
|
|
||||||
**Хорошо**
|
|
||||||
|
|
||||||
```text
|
|
||||||
user/
|
|
||||||
├── ui/
|
|
||||||
│ └── user-avatar.tsx
|
|
||||||
├── styles/
|
|
||||||
│ └── user-avatar.module.css
|
|
||||||
└── types/
|
|
||||||
└── user-avatar.type.ts
|
|
||||||
```
|
|
||||||
|
|
||||||
## Стили и типы
|
|
||||||
|
|
||||||
Компонент использует ресурсы родительского модуля.
|
|
||||||
|
|
||||||
`styles/` и `types/` рядом с корневым компонентом — это сегменты модуля, а не собственные папки `.tsx` файла.
|
|
||||||
|
|
||||||
- CSS Module компонента лежит в `styles/` родительского модуля и называется по компоненту: `user-avatar.module.css`.
|
|
||||||
- Если у компонента есть CSS Module, его корневой класс всегда называется `.root`.
|
|
||||||
- Типы компонента лежат в `types/` родительского модуля и называются по компоненту: `user-avatar.type.ts`.
|
|
||||||
- Локальный `type Props` внутри `.tsx` не используется. Типы пропсов всегда выносятся в `types/` родительского модуля.
|
|
||||||
- Экспорт типа из `types/` не делает его публичным API. Публичным он становится только при реэкспорте из `index.ts` модуля.
|
|
||||||
|
|
||||||
Причина `.root`: в DevTools проще находить корневой DOM-узел компонента и отличать его от внутренних элементов.
|
|
||||||
|
|
||||||
## Реализация
|
## Реализация
|
||||||
|
|
||||||
- Компоненты объявляются через `const`.
|
Пример ниже показывает файлы базового компонента.
|
||||||
- `React.FC` не используется.
|
|
||||||
- JSDoc-комментарий обязателен для компонента.
|
|
||||||
- Пропсы деструктурируются в теле компонента.
|
|
||||||
- `className` объединяется с `styles.root` через `cl()`.
|
|
||||||
- Побочные эффекты и состояние выносятся в хуки модуля, если перестают быть тривиальными.
|
|
||||||
- Компонент возвращает JSX и не содержит orchestration-код страницы или бизнес-домена.
|
|
||||||
|
|
||||||
`user/types/user-avatar.type.ts`
|
### Типы
|
||||||
|
|
||||||
|
Файл типов делится на три части:
|
||||||
|
|
||||||
|
- `UserStatusParams` — собственные параметры компонента. Здесь лежат только данные, которые нужны именно этому компоненту.
|
||||||
|
- `RootAttrs` — параметры корневой обёртки: `div`, `span`, `a`, `button` или другого HTML-элемента. Если компонент сам управляет `children`, они исключаются через `Omit`.
|
||||||
|
- `UserStatusProps` — итоговые пропсы компонента. Тип объединяет собственные параметры и параметры корневой обёртки.
|
||||||
|
|
||||||
|
Собственные параметры и их поля документируются по правилам раздела [Документирование → Типы, интерфейсы, enum](/docs/basics/documentation#типы-интерфейсы-enum).
|
||||||
|
|
||||||
|
`user-card/ui/user-status/types/user-status-props.type.ts`
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import type { ImageProps } from 'next/image'
|
import type { ComponentPropsWithoutRef } from 'react'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Параметры UserAvatar.
|
* Параметры UserStatus.
|
||||||
*/
|
*/
|
||||||
export type UserAvatarParams = {}
|
export type UserStatusParams = {
|
||||||
|
/** Текст статуса пользователя. */
|
||||||
|
label: string
|
||||||
|
/** Доступен ли пользователь сейчас. */
|
||||||
|
isOnline: boolean
|
||||||
|
}
|
||||||
|
|
||||||
/** Пропсы базового изображения. */
|
/** Атрибуты корневого элемента без children. */
|
||||||
type RootAttrs = ImageProps
|
type RootAttrs = Omit<ComponentPropsWithoutRef<'span'>, 'children'>
|
||||||
|
|
||||||
export type UserAvatarProps = RootAttrs & UserAvatarParams
|
export type UserStatusProps = RootAttrs & UserStatusParams
|
||||||
```
|
```
|
||||||
|
|
||||||
`user/ui/user-avatar.tsx`
|
### TSX
|
||||||
|
|
||||||
|
В `.tsx` лежит только сам компонент:
|
||||||
|
|
||||||
|
- Компонент объявляется через `const` и именованный экспорт.
|
||||||
|
- `React.FC` не используется.
|
||||||
|
- Параметры компонента типизируются через `Props`.
|
||||||
|
- Возвращаемый тип не указывается: TypeScript корректно выводит JSX-результат, а явный `ReactElement` сужает допустимые варианты возврата.
|
||||||
|
- JSDoc-комментарий обязателен и пишется по правилам раздела [Документирование → Компоненты](/docs/basics/documentation#компоненты).
|
||||||
|
- Пропсы деструктурируются в теле компонента, а не в сигнатуре.
|
||||||
|
- Из пропсов обязательно выделяются `className` и `...rootAttrs`.
|
||||||
|
- Функция конкатенации CSS-классов импортируется и именуется `cl`.
|
||||||
|
- Корневой CSS-класс всегда называется `.root`.
|
||||||
|
|
||||||
|
Комментарий описывает назначение и сценарии применения компонента, а не DOM-разметку или внутреннюю реализацию.
|
||||||
|
|
||||||
|
`className` — внешний CSS-класс, который родитель может передать компоненту. `rootAttrs` — остальные атрибуты корневой обёртки: `id`, `aria-*`, `data-*`, обработчики событий и другие HTML-атрибуты. Они прокидываются на корневой DOM-элемент компонента.
|
||||||
|
|
||||||
|
`.root` нужен, чтобы в DevTools быстро находить корневой DOM-узел компонента и одинаково подключать внешний `className` к реальному корню.
|
||||||
|
|
||||||
|
`user-card/ui/user-status/user-status.tsx`
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
import cl from 'clsx'
|
import cl from 'clsx'
|
||||||
import Image from 'next/image'
|
import type { UserStatusProps } from './types/user-status-props.type'
|
||||||
import type { UserAvatarProps } from '../types/user-avatar.type'
|
import styles from './styles/user-status.module.css'
|
||||||
import styles from '../styles/user-avatar.module.css'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Аватар пользователя.
|
* Статус пользователя в карточке профиля.
|
||||||
*
|
*
|
||||||
* Используется для:
|
* Используется для:
|
||||||
* - отображения пользователя в карточке
|
* - отображения текущей доступности пользователя
|
||||||
* - отображения пользователя в шапке профиля
|
* - визуального выделения онлайн- и офлайн-состояний
|
||||||
*/
|
*/
|
||||||
export const UserAvatar = (props: UserAvatarProps) => {
|
export const UserStatus = (props: UserStatusProps) => {
|
||||||
const { className, ...imageProps } = props
|
const { label, isOnline, className, ...rootAttrs } = props
|
||||||
|
|
||||||
return <Image {...imageProps} className={cl(styles.root, className)} />
|
return (
|
||||||
|
<span
|
||||||
|
{...rootAttrs}
|
||||||
|
className={cl(styles.root, isOnline && styles.online, className)}
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`user/styles/user-avatar.module.css`
|
### Стили
|
||||||
|
|
||||||
|
`user-card/ui/user-status/styles/user-status.module.css`
|
||||||
|
|
||||||
```css
|
```css
|
||||||
.root {
|
.root {
|
||||||
display: block;
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.root::before {
|
||||||
|
content: '';
|
||||||
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
|
background: currentColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
.online {
|
||||||
|
color: var(--color-success);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Когда нужен модуль
|
### Локальный экспорт
|
||||||
|
|
||||||
Решение о выделении модуля остаётся за разработчиком. Поднимать компонент в модуль стоит, если он становится самостоятельной областью:
|
`user-card/ui/user-status/index.ts`
|
||||||
|
|
||||||
- получает свои вложенные компоненты;
|
```ts
|
||||||
- получает свои хуки, стор или сервисы;
|
export { UserStatus } from './user-status'
|
||||||
- получает внутренние мапперы или утилиты;
|
export type { UserStatusProps } from './types/user-status-props.type'
|
||||||
- требует собственного публичного API;
|
|
||||||
- начинает переиспользоваться вне родительского модуля;
|
|
||||||
- становится отдельной зоной параллельной разработки.
|
|
||||||
|
|
||||||
Пример: страница — это screen-модуль, а самостоятельные секции страницы — вложенные модули в `parts/`.
|
|
||||||
|
|
||||||
```text
|
|
||||||
screens/home/
|
|
||||||
├── parts/
|
|
||||||
│ ├── hero-section/
|
|
||||||
│ │ ├── styles/
|
|
||||||
│ │ │ └── hero-section.module.css
|
|
||||||
│ │ ├── types/
|
|
||||||
│ │ │ └── hero-section.type.ts
|
|
||||||
│ │ ├── hero-section.tsx
|
|
||||||
│ │ └── index.ts
|
|
||||||
│ └── features-section/
|
|
||||||
│ ├── styles/
|
|
||||||
│ │ └── features-section.module.css
|
|
||||||
│ ├── types/
|
|
||||||
│ │ └── features-section.type.ts
|
|
||||||
│ ├── features-section.tsx
|
|
||||||
│ └── index.ts
|
|
||||||
├── styles/
|
|
||||||
│ └── home.module.css
|
|
||||||
├── types/
|
|
||||||
│ └── home.type.ts
|
|
||||||
├── home.screen.tsx
|
|
||||||
└── index.ts
|
|
||||||
```
|
```
|
||||||
|
|
||||||
`hero-section` и `features-section` — модули, потому что это самостоятельные части страницы со своей структурой и публичной точкой входа.
|
|
||||||
|
|||||||
@@ -1,162 +1,156 @@
|
|||||||
---
|
---
|
||||||
title: Модуль
|
title: Модуль
|
||||||
description: Как создавать и организовывать SLM-модули в проекте.
|
description: Как должен выглядеть сгенерированный SLM-модуль в проекте.
|
||||||
---
|
---
|
||||||
|
|
||||||
# Модуль
|
# Модуль
|
||||||
|
|
||||||
Как создавать и организовывать SLM-модули в проекте.
|
Как должен выглядеть сгенерированный SLM-модуль в проекте.
|
||||||
|
|
||||||
## Назначение
|
## Назначение
|
||||||
|
|
||||||
Модуль — основной строительный блок SLM-архитектуры. Это папка с публичным API (`index.ts`) и опциональными сегментами: компонентами, стилями, типами, хуками, сторами, сервисами и вложенными модулями.
|
Архитектурное определение модуля описано в разделе [Архитектура → Модули](/docs/basics/architecture/modules). Список сегментов описан в разделе [Архитектура → Сегменты](/docs/basics/architecture/segments).
|
||||||
|
|
||||||
Если UI-сущность остаётся одним `.tsx` файлом и использует ресурсы родительского модуля — это [компонент](/docs/applied/component), а не модуль. Связанные файлы в `styles/` и `types/` родителя не создают новую модульную границу.
|
Эта страница показывает прикладное оформление трёх типов модулей: UI, бизнес и инфраструктурный.
|
||||||
|
|
||||||
Архитектурное определение: [Модули SLM](/docs/basics/architecture/reference/modules). Список сегментов: [Сегменты SLM](/docs/basics/architecture/reference/segments).
|
## Создание
|
||||||
|
|
||||||
## Когда нужен модуль
|
1. Проверьте, что в проекте есть нужный шаблон в `.templates/`.
|
||||||
|
2. Если шаблона нет — создайте его по разделу [Создание шаблонов](/docs/applied/templates/templates-create).
|
||||||
|
3. Сгенерируйте модуль через [VS Code или CLI](/docs/applied/templates/templates-usage).
|
||||||
|
|
||||||
Создавайте модуль, если сущности нужны:
|
## Типы модулей
|
||||||
|
|
||||||
- публичный API;
|
Архитектура определяет три типа модулей ([Типы модулей](/docs/basics/architecture/modules#типы-модулей)):
|
||||||
- хуки, сторы, сервисы, мапперы или утилиты;
|
|
||||||
- вложенные части;
|
|
||||||
- переиспользование вне родительского модуля;
|
|
||||||
- самостоятельная ответственность на слое.
|
|
||||||
|
|
||||||
Если понадобилась папка вокруг компонента — это сигнал, что нужен модуль.
|
| Тип | Обязательный файл | Описание |
|
||||||
|
|---|---|---|
|
||||||
|
| UI-модуль | `{name}.tsx` | Модуль, выросший из компонента |
|
||||||
|
| Бизнес-модуль | `{name}.factory.ts` | Модуль вокруг публичного runtime API |
|
||||||
|
| Инфраструктурный модуль | нет | Модуль вокруг технического сервиса |
|
||||||
|
|
||||||
## Где размещать
|
## UI-модуль
|
||||||
|
|
||||||
Модуль размещается на самом низком уровне использования.
|
UI-модуль — это компонент, который перерос ограничения компонента: получил собственные хуки, вложенные модули в `parts/`, сценарную логику или публичный API. Внутренняя структура та же, что у компонента: корневой `.tsx`, типы, стили, `ui/`. Но без ограничений компонента.
|
||||||
|
|
||||||
- Нужен только одному модулю — размещается в `parts/` родителя.
|
Подробное оформление компонентов внутри `ui/` описано в разделе [Компонент](/docs/applied/component).
|
||||||
- Нужен одной странице — размещается в `screens/{name}/parts/`.
|
|
||||||
- Нужен одному layout — размещается в `layouts/{name}/parts/`.
|
|
||||||
- Переиспользуется между страницами или layout — поднимается в `widgets/`.
|
|
||||||
- Представляет бизнес-домен — размещается в `business/`.
|
|
||||||
- Является UI-китом — размещается в `ui/`.
|
|
||||||
|
|
||||||
`app/` не содержит модулей. Это слой файлового роутинга и инициализации.
|
## Бизнес-модуль
|
||||||
|
|
||||||
## Структура
|
Бизнес-модуль строится вокруг публичного runtime API. Ключевой файл — фабрика (`{name}.factory.ts`), которая возвращает всё, что нужно внешнему коду в runtime.
|
||||||
|
|
||||||
Минимальный UI-модуль:
|
Архитектурное описание фабрики: [Архитектура → Фабрика](/docs/basics/architecture/modules#фабрика).
|
||||||
|
|
||||||
|
### Структура
|
||||||
|
|
||||||
```text
|
```text
|
||||||
user/
|
business/customer/
|
||||||
├── user.tsx
|
├── customer.factory.ts
|
||||||
└── index.ts
|
├── index.ts
|
||||||
|
└── types/
|
||||||
|
├── customer.type.ts
|
||||||
|
├── customer-api.type.ts
|
||||||
|
├── customer-deps.type.ts
|
||||||
|
└── customer-factory.type.ts
|
||||||
```
|
```
|
||||||
|
|
||||||
Модуль расширяется сегментами только при реальной потребности:
|
### Типы
|
||||||
|
|
||||||
```text
|
`business/customer/types/customer-api.type.ts`
|
||||||
user/
|
|
||||||
├── ui/
|
|
||||||
│ └── user-avatar.tsx
|
|
||||||
├── parts/
|
|
||||||
│ └── user-posts/
|
|
||||||
│ ├── user-posts.tsx
|
|
||||||
│ └── index.ts
|
|
||||||
├── styles/
|
|
||||||
│ ├── user.module.css
|
|
||||||
│ └── user-avatar.module.css
|
|
||||||
├── types/
|
|
||||||
│ ├── user.type.ts
|
|
||||||
│ └── user-avatar.type.ts
|
|
||||||
├── user.tsx
|
|
||||||
└── index.ts
|
|
||||||
```
|
|
||||||
|
|
||||||
Корневой компонент опционален. Business- и infrastructure-модули могут состоять только из хуков, сервисов, типов и публичного API.
|
|
||||||
|
|
||||||
## `ui/` и `parts/`
|
|
||||||
|
|
||||||
`ui/` содержит только компоненты: отдельные `.tsx` файлы без собственных сегментов.
|
|
||||||
|
|
||||||
`parts/` содержит только модули: каждая запись внутри `parts/` — папка с собственным `index.ts`. Отдельные `.tsx`, стили, хуки или произвольные файлы в `parts/` не кладутся.
|
|
||||||
|
|
||||||
```text
|
|
||||||
user/
|
|
||||||
├── ui/
|
|
||||||
│ └── user-avatar.tsx # компонент
|
|
||||||
└── parts/
|
|
||||||
└── user-posts/ # модуль
|
|
||||||
├── styles/
|
|
||||||
│ └── user-posts.module.css
|
|
||||||
├── user-posts.tsx
|
|
||||||
└── index.ts
|
|
||||||
```
|
|
||||||
|
|
||||||
Если компоненту в `ui/` понадобились стили или типы, они добавляются в `styles/` и `types/` родительского модуля. Если компоненту нужны собственные хуки, вложенные части или публичная граница — он переносится в `parts/` как модуль.
|
|
||||||
|
|
||||||
## Публичный API
|
|
||||||
|
|
||||||
`index.ts` — единственная точка входа в модуль. Внешние импорты внутренних файлов запрещены.
|
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
// user/index.ts
|
export type CustomerApi = {
|
||||||
export { User } from './user'
|
useCustomer: () => Customer
|
||||||
export type { UserProps } from './types/user.type'
|
CustomerCard: (props: CustomerCardProps) => ReactNode
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`business/order/types/order-deps.type.ts`
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
// Плохо: импорт в обход публичного API.
|
export type OrderDeps = {
|
||||||
import { UserPosts } from 'screens/user/parts/user-posts/user-posts'
|
customer: Pick<CustomerApi, 'useCustomer'>
|
||||||
|
}
|
||||||
// Хорошо: импорт через публичный API родительского модуля.
|
|
||||||
import { User } from 'screens/user'
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Вложенный модуль имеет свой `index.ts`, но наружу родителя экспортируется только при необходимости.
|
`business/order/types/order-factory.type.ts`
|
||||||
|
|
||||||
## Именование
|
```ts
|
||||||
|
export type OrderFactory = (deps: OrderDeps) => OrderApi
|
||||||
Базовые правила описаны в разделе [Именование](/docs/basics/naming).
|
|
||||||
|
|
||||||
- Папка модуля — `kebab-case`: `user-posts/`.
|
|
||||||
- Файл корневого компонента повторяет имя папки: `user-posts/user-posts.tsx`.
|
|
||||||
- Корневые модули слоёв наследуют роль слоя в имени файла: `screens/profile/profile.screen.tsx`, `layouts/main/main.layout.tsx`.
|
|
||||||
- Корневой компонент именуется в `PascalCase`: `UserPosts`.
|
|
||||||
- Если имя без контекста слишком общее, добавляется префикс родителя или роль слоя: `ProfileUserPosts`, `ProfileScreen`, `MainLayout`.
|
|
||||||
|
|
||||||
## Примеры
|
|
||||||
|
|
||||||
### Screen-модуль
|
|
||||||
|
|
||||||
```text
|
|
||||||
screens/profile/
|
|
||||||
├── ui/
|
|
||||||
│ └── profile-heading.tsx
|
|
||||||
├── parts/
|
|
||||||
│ └── activity-feed/
|
|
||||||
│ ├── styles/
|
|
||||||
│ │ └── activity-feed.module.css
|
|
||||||
│ ├── activity-feed.tsx
|
|
||||||
│ └── index.ts
|
|
||||||
├── styles/
|
|
||||||
│ ├── profile.module.css
|
|
||||||
│ └── profile-heading.module.css
|
|
||||||
├── types/
|
|
||||||
│ ├── profile.type.ts
|
|
||||||
│ └── profile-heading.type.ts
|
|
||||||
├── profile.screen.tsx
|
|
||||||
└── index.ts
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Business-модуль без корневого компонента
|
### Фабрика без зависимостей
|
||||||
|
|
||||||
|
`business/customer/customer.factory.ts`
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import type { CustomerFactory } from './types/customer-factory.type'
|
||||||
|
|
||||||
|
export const customerFactory: CustomerFactory = () => {
|
||||||
|
return {
|
||||||
|
useCustomer,
|
||||||
|
CustomerCard,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Фабрика с зависимостями
|
||||||
|
|
||||||
|
`business/order/order.factory.ts`
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import type { OrderFactory } from './types/order-factory.type'
|
||||||
|
|
||||||
|
export const orderFactory: OrderFactory = (deps) => {
|
||||||
|
return {
|
||||||
|
useOrder,
|
||||||
|
OrderCard,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Композиция на уровне screen
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
// screens/home/home.screen.tsx
|
||||||
|
import { customerFactory } from '@/business/customer'
|
||||||
|
import { orderFactory } from '@/business/order'
|
||||||
|
|
||||||
|
const customer = customerFactory()
|
||||||
|
const order = orderFactory({ customer })
|
||||||
|
|
||||||
|
const { useOrder, OrderCard } = order
|
||||||
|
|
||||||
|
export const HomeScreen = () => {
|
||||||
|
const currentOrder = useOrder()
|
||||||
|
|
||||||
|
return <OrderCard order={currentOrder} />
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Инфраструктурный модуль
|
||||||
|
|
||||||
|
Инфраструктурный модуль строится вокруг технического сервиса или интеграции. Его структура определяется природой сервиса — фиксированного корневого файла нет.
|
||||||
|
|
||||||
|
Архитектурное описание: [Архитектура → Типы модулей → Инфраструктурный модуль](/docs/basics/architecture/modules#инфраструктурный-модуль).
|
||||||
|
|
||||||
|
Пример модуля темы:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
business/auth/
|
theme/
|
||||||
|
├── index.ts
|
||||||
|
├── config/
|
||||||
├── hooks/
|
├── hooks/
|
||||||
│ └── use-auth.hook.ts
|
├── styles/
|
||||||
├── services/
|
└── ui/
|
||||||
│ └── auth.service.ts
|
```
|
||||||
├── stores/
|
|
||||||
│ └── auth.store.ts
|
Пример модуля API-клиента:
|
||||||
|
|
||||||
|
```text
|
||||||
|
backend-api/
|
||||||
|
├── backend-api.client.ts
|
||||||
|
├── config/
|
||||||
├── types/
|
├── types/
|
||||||
│ └── auth.type.ts
|
|
||||||
└── index.ts
|
└── index.ts
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ description: Как работать со страницами и другими
|
|||||||
|
|
||||||
Файлы роутинга не реализуют интерфейс. Они описывают маршрут: читают параметры, получают данные первого рендера, подготавливают кеш или состояние и передают результат в screen.
|
Файлы роутинга не реализуют интерфейс. Они описывают маршрут: читают параметры, получают данные первого рендера, подготавливают кеш или состояние и передают результат в screen.
|
||||||
|
|
||||||
Границы слоя описаны в [Архитектура → Слои → App](/docs/basics/architecture/reference/layers#слой-app).
|
Границы слоя описаны в [Архитектура → Слои → App](/docs/basics/architecture/layers#слой-app).
|
||||||
|
|
||||||
## Граница ответственности
|
## Граница ответственности
|
||||||
|
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ src/
|
|||||||
Точка входа приложения и файловый роутинг Next.js (`layout.tsx`, `page.tsx`, route-сегменты).
|
Точка входа приложения и файловый роутинг Next.js (`layout.tsx`, `page.tsx`, route-сегменты).
|
||||||
`app/` подключает готовую инициализацию из нижних слоёв, но не реализует провайдеры, стили, UI-компоненты, хуки, сторы или сервисы.
|
`app/` подключает готовую инициализацию из нижних слоёв, но не реализует провайдеры, стили, UI-компоненты, хуки, сторы или сервисы.
|
||||||
|
|
||||||
Подробнее о границах слоя: [Архитектура → Слои → App](/docs/basics/architecture/reference/layers#слой-app).
|
Подробнее о границах слоя: [Архитектура → Слои → App](/docs/basics/architecture/layers#слой-app).
|
||||||
|
|
||||||
```text
|
```text
|
||||||
src/app/
|
src/app/
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ keywords: [шаблоны, templates, .templates, syntax, переменные,
|
|||||||
│ ├── styles/
|
│ ├── styles/
|
||||||
│ │ └── {{name.kebabCase}}.module.css
|
│ │ └── {{name.kebabCase}}.module.css
|
||||||
│ ├── types/
|
│ ├── types/
|
||||||
│ │ └── {{name.kebabCase}}.type.ts
|
│ │ └── {{name.kebabCase}}-props.type.ts
|
||||||
│ ├── {{name.kebabCase}}.tsx
|
│ ├── {{name.kebabCase}}.tsx
|
||||||
│ └── index.ts
|
│ └── index.ts
|
||||||
└── store/ # шаблон Zustand стора
|
└── store/ # шаблон Zustand стора
|
||||||
@@ -32,6 +32,12 @@ keywords: [шаблоны, templates, .templates, syntax, переменные,
|
|||||||
└── index.ts
|
└── index.ts
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Обязательный шаблон компонента
|
||||||
|
|
||||||
|
Перед созданием компонентов в проекте должен существовать шаблон `.templates/component`.
|
||||||
|
|
||||||
|
Если шаблона нет, компонент не создаётся вручную. Сначала создаётся шаблон компонента, затем компонент генерируется через [VS Code или CLI](/docs/applied/templates/templates-usage).
|
||||||
|
|
||||||
## Синтаксис шаблонов
|
## Синтаксис шаблонов
|
||||||
|
|
||||||
### Переменные
|
### Переменные
|
||||||
|
|||||||
@@ -8,6 +8,12 @@ keywords: [шаблоны, templates, generate, VS Code, CLI, gromlab/create, np
|
|||||||
|
|
||||||
Генерация файлов из шаблонов через VS Code плагин и CLI.
|
Генерация файлов из шаблонов через VS Code плагин и CLI.
|
||||||
|
|
||||||
|
::: danger Ручное создание запрещено
|
||||||
|
Файлы, для которых есть шаблоны в `.templates/`, создаются только генератором. Ручное создание компонента, модуля, стора или другого шаблонного блока запрещено.
|
||||||
|
|
||||||
|
Если нужного шаблона нет, сначала создайте шаблон в `.templates/`, затем сгенерируйте код на его основе.
|
||||||
|
:::
|
||||||
|
|
||||||
## Через VS Code
|
## Через VS Code
|
||||||
|
|
||||||
Template File Generator | gromlab ([Marketplace](https://marketplace.visualstudio.com/items?itemName=gromlab.vscode-templateFileGenerator), [Open VSX](https://open-vsx.org/extension/gromlab/vscode-templateFileGenerator)) — расширение для генерации файлов и папок из шаблонов через интерфейс редактора.
|
Template File Generator | gromlab ([Marketplace](https://marketplace.visualstudio.com/items?itemName=gromlab.vscode-templateFileGenerator), [Open VSX](https://open-vsx.org/extension/gromlab/vscode-templateFileGenerator)) — расширение для генерации файлов и папок из шаблонов через интерфейс редактора.
|
||||||
|
|||||||
@@ -1,11 +1,19 @@
|
|||||||
---
|
|
||||||
title: SLM Design
|
|
||||||
description: "Архитектурный подход проекта: что такое SLM и как он устроен."
|
|
||||||
---
|
|
||||||
|
|
||||||
# SLM Design
|
# SLM Design
|
||||||
|
Scoped Layered Module Design — модульная архитектура фронтенд-приложений. Код организован по слоям ответственности, а модуль содержит всё, что ему нужно: компоненты, хуки, сторы, типы, стили.
|
||||||
|
|
||||||
Архитектурный подход проекта: что такое SLM и как он устроен.
|
::: warning Локальная копия
|
||||||
|
Документация по архитектуре — локальная копия. Оригинал находится на сайте [slm-design.gromlab.ru](https://slm-design.gromlab.ru/).
|
||||||
|
:::
|
||||||
|
|
||||||
|
## Разделы спецификации
|
||||||
|
|
||||||
|
Спецификация SLM Design состоит из нескольких связанных разделов. Этот обзор даёт общий контекст, а детальные правила описаны дальше:
|
||||||
|
|
||||||
|
- [Слои](./layers.md) — уровни организации `src/`, направление зависимостей и зона ответственности каждого слоя.
|
||||||
|
- [Модули](./modules.md) — границы ответственности, публичный API, типы модулей и отличие модуля от компонента.
|
||||||
|
- [Сегменты](./segments.md) — внутренние папки модуля (`ui/`, `parts/`, `hooks/`, `types/` и другие) и правила размещения файлов.
|
||||||
|
|
||||||
|
Рекомендуемый порядок чтения: обзор → слои → модули → сегменты.
|
||||||
|
|
||||||
## Преимущества
|
## Преимущества
|
||||||
|
|
||||||
@@ -19,7 +27,7 @@ Cross-domain зависимости в бизнес-слое реализуют
|
|||||||
|
|
||||||
### Разделение ответственности без перегрузки слоёв
|
### Разделение ответственности без перегрузки слоёв
|
||||||
|
|
||||||
Сервисы приложения (`infrastructure/`), UI-кит (`ui/`) и общие ресурсы (`shared/`) — три разных слоя с разной природой. Ни один слой не превращается в свалку разнородного кода.
|
Сервисы приложения (`infra/`), UI-кит (`ui/`) и общие ресурсы (`shared/`) — три разных слоя с разной природой. Ни один слой не превращается в свалку разнородного кода.
|
||||||
|
|
||||||
### Горизонтальная инкапсуляция
|
### Горизонтальная инкапсуляция
|
||||||
|
|
||||||
@@ -73,7 +81,7 @@ src/
|
|||||||
│ ├── orders/
|
│ ├── orders/
|
||||||
│ └── chat/
|
│ └── chat/
|
||||||
│
|
│
|
||||||
├── infrastructure/
|
├── infra/
|
||||||
│ ├── theme/
|
│ ├── theme/
|
||||||
│ ├── i18n/
|
│ ├── i18n/
|
||||||
│ ├── backend-api/
|
│ ├── backend-api/
|
||||||
|
|||||||
@@ -1,11 +1,6 @@
|
|||||||
---
|
# Слои
|
||||||
title: Слои SLM
|
|
||||||
description: Из каких слоёв состоит SLM-архитектура и как они связаны.
|
|
||||||
---
|
|
||||||
|
|
||||||
# Слои SLM
|
Раздел описывает слои SLM: что такое слой, какие бывают, как между ними направлены зависимости и какие правила действуют на каждом.
|
||||||
|
|
||||||
Из каких слоёв состоит SLM-архитектура и как они связаны.
|
|
||||||
|
|
||||||
## Определение
|
## Определение
|
||||||
|
|
||||||
@@ -18,7 +13,7 @@ description: Из каких слоёв состоит SLM-архитектур
|
|||||||
| Группа | Слои | Описание |
|
| Группа | Слои | Описание |
|
||||||
|--------|------|----------|
|
|--------|------|----------|
|
||||||
| Композиция | `app`, `layouts`, `screens`, `widgets` | Собирают интерфейс из готовых блоков: маршруты, каркасы, страницы |
|
| Композиция | `app`, `layouts`, `screens`, `widgets` | Собирают интерфейс из готовых блоков: маршруты, каркасы, страницы |
|
||||||
| Ядро | `business`, `infrastructure`, `ui` | Реализация продукта: бизнес-домены, техсервисы, UI-кит |
|
| Ядро | `business`, `infra`, `ui` | Реализация продукта: бизнес-домены, техсервисы, UI-кит |
|
||||||
| Фундамент | `shared` | Общие ресурсы: утилиты, хелперы, стили, конфиги |
|
| Фундамент | `shared` | Общие ресурсы: утилиты, хелперы, стили, конфиги |
|
||||||
|
|
||||||
## Направление зависимостей
|
## Направление зависимостей
|
||||||
@@ -26,12 +21,12 @@ description: Из каких слоёв состоит SLM-архитектур
|
|||||||
Любой импорт между модулями — только через публичный API.
|
Любой импорт между модулями — только через публичный API.
|
||||||
|
|
||||||
```
|
```
|
||||||
app → [ layouts | screens ] → widgets → business → infrastructure → ui → shared
|
app → [ layouts | screens ] → widgets → business → infra → ui → shared
|
||||||
```
|
```
|
||||||
|
|
||||||
- `layouts` и `screens` — параллельные слои, не импортируют друг друга
|
- `layouts` и `screens` — параллельные слои, не импортируют друг друга
|
||||||
- Модули одного слоя в группе «Композиция» изолированы друг от друга
|
- Модули одного слоя в группе «Композиция» изолированы друг от друга
|
||||||
- Модули одного слоя `infrastructure` и `ui` могут импортировать друг друга через публичный API
|
- Модули одного слоя `infra` и `ui` могут импортировать друг друга через публичный API
|
||||||
- Модули `business` — cross-domain зависимости по коду через фабрику, `import type` напрямую
|
- Модули `business` — cross-domain зависимости по коду через фабрику, `import type` напрямую
|
||||||
- Импорт типов (`import type`) в «Ядре» разрешён в обоих направлениях
|
- Импорт типов (`import type`) в «Ядре» разрешён в обоих направлениях
|
||||||
|
|
||||||
@@ -129,7 +124,7 @@ src/widgets/
|
|||||||
|
|
||||||
Бизнес-домены приложения: auth, catalog, orders, checkout, chat. Каждый домен — отдельный модуль со своими типами, логикой, UI и сервисами.
|
Бизнес-домены приложения: auth, catalog, orders, checkout, chat. Каждый домен — отдельный модуль со своими типами, логикой, UI и сервисами.
|
||||||
|
|
||||||
Слой входит в группу «Ядро». Импортирует `infrastructure/`, `ui/`, `shared/`. Cross-domain зависимости по коду реализуются через фабрику. `import type` между доменами разрешён напрямую.
|
Слой входит в группу «Ядро». Импортирует `infra/`, `ui/`, `shared/`. Каждый бизнес-модуль создаёт публичный runtime API через фабрику в корне. Cross-domain зависимости: runtime — через аргументы фабрики, типы — напрямую через `import type`.
|
||||||
|
|
||||||
Business объединяет то, что в FSD разделено на `features` и `entities`: пользовательские сценарии и бизнес-сущности живут вместе, внутри одного домена. Внутри домена сегменты разделяют ответственность: `types/` — доменная модель, `hooks/` и `services/` — сценарии и логика, `mappers/` — трансформация данных, `parts/` — составные блоки.
|
Business объединяет то, что в FSD разделено на `features` и `entities`: пользовательские сценарии и бизнес-сущности живут вместе, внутри одного домена. Внутри домена сегменты разделяют ответственность: `types/` — доменная модель, `hooks/` и `services/` — сценарии и логика, `mappers/` — трансформация данных, `parts/` — составные блоки.
|
||||||
|
|
||||||
@@ -160,19 +155,20 @@ src/business/
|
|||||||
|
|
||||||
- Один модуль = один бизнес-домен
|
- Один модуль = один бизнес-домен
|
||||||
- Циклические зависимости между доменами запрещены
|
- Циклические зависимости между доменами запрещены
|
||||||
- Импорт кода между доменами — через фабрику. `import type` — напрямую
|
- Публичный runtime API — через фабрику в корне модуля (`{name}.factory.ts`). `index.ts` экспортирует только фабрику и type-only экспорты
|
||||||
|
- Импорт runtime-кода между доменами — через фабрику. `import type` — напрямую
|
||||||
- Доменные типы (`User`, `Product`) живут здесь, не в `shared/`
|
- Доменные типы (`User`, `Product`) живут здесь, не в `shared/`
|
||||||
|
|
||||||
## Слой Infrastructure
|
## Слой infra
|
||||||
|
|
||||||
Техсервисы приложения: theme, i18n, API-адаптеры, logger, realtime. Каждый сервис — отдельный модуль.
|
Техсервисы приложения: theme, i18n, API-адаптеры, logger, realtime. Каждый сервис — отдельный модуль.
|
||||||
|
|
||||||
Слой входит в группу «Ядро». Импортирует `infrastructure/`, `ui/`, `shared/`.
|
Слой входит в группу «Ядро». Импортирует `infra/`, `ui/`, `shared/`.
|
||||||
|
|
||||||
Отличие от `shared/`: infrastructure — инфраструктура приложения (сервисы, темы, адаптеры к API), `shared/` — общие ресурсы (утилиты, хелперы, стили, конфиги).
|
Отличие от `shared/`: infra — инфраструктура приложения (сервисы, темы, адаптеры к API), `shared/` — общие ресурсы (утилиты, хелперы, стили, конфиги).
|
||||||
|
|
||||||
```text
|
```text
|
||||||
src/infrastructure/
|
src/infra/
|
||||||
├── theme/
|
├── theme/
|
||||||
├── i18n/
|
├── i18n/
|
||||||
├── backend-api/
|
├── backend-api/
|
||||||
@@ -185,7 +181,7 @@ src/infrastructure/
|
|||||||
### Требования
|
### Требования
|
||||||
|
|
||||||
- Один модуль = один техсервис
|
- Один модуль = один техсервис
|
||||||
- Импортирует `infrastructure/`, `ui/`, `shared/`
|
- Импортирует `infra/`, `ui/`, `shared/`
|
||||||
|
|
||||||
## Слой UI
|
## Слой UI
|
||||||
|
|
||||||
@@ -236,7 +232,7 @@ src/ui/
|
|||||||
|
|
||||||
Слой входит в группу «Фундамент» — ни о ком не знает, никого не импортирует.
|
Слой входит в группу «Фундамент» — ни о ком не знает, никого не импортирует.
|
||||||
|
|
||||||
Отличие от `infrastructure/`: infrastructure — инфраструктура приложения (сервисы, темы, адаптеры к API), `shared/` — общие ресурсы (утилиты, хелперы, стили, конфиги).
|
Отличие от `infra/`: infra — инфраструктура приложения (сервисы, темы, адаптеры к API), `shared/` — общие ресурсы (утилиты, хелперы, стили, конфиги).
|
||||||
|
|
||||||
Отличие от `ui/`: UI-компоненты (button, carousel, modal) живут в слое `ui/`, а не здесь.
|
Отличие от `ui/`: UI-компоненты (button, carousel, modal) живут в слое `ui/`, а не здесь.
|
||||||
|
|
||||||
@@ -250,4 +246,4 @@ src/shared/
|
|||||||
|
|
||||||
### Требования
|
### Требования
|
||||||
|
|
||||||
- Не имеет runtime-состояния
|
- Не имеет runtime-состояния
|
||||||
284
docs/docs/basics/architecture/modules.md
Normal file
284
docs/docs/basics/architecture/modules.md
Normal file
@@ -0,0 +1,284 @@
|
|||||||
|
# Модули
|
||||||
|
|
||||||
|
Раздел описывает модуль как границу ответственности в SLM: что считается модулем, что такое компонент внутри модуля и как модуль взаимодействует с остальным кодом.
|
||||||
|
|
||||||
|
## Определение
|
||||||
|
|
||||||
|
**Модуль — минимальная архитектурная единица SLM. Он живёт на одном из слоёв, владеет конкретной областью ответственности и предоставляет наружу только публичный API.**
|
||||||
|
|
||||||
|
Модуль может содержать всё, что нужно этой области: компоненты, вложенные модули, хуки, сторы, сервисы, типы, стили, конфиги и утилиты. Набор сегментов не фиксирован — модуль включает только то, что реально нужно.
|
||||||
|
|
||||||
|
Модуль не обязан быть UI-блоком. Это может быть страница, виджет, бизнес-домен, инфраструктурный сервис или UI-kit сущность.
|
||||||
|
|
||||||
|
Главная граница модуля — не папка, а ответственность.
|
||||||
|
|
||||||
|
## Компонент
|
||||||
|
|
||||||
|
**Компонент — презентационная единица модуля, которая находится только в `ui/` своего родительского модуля и отвечает за отображение части интерфейса.**
|
||||||
|
|
||||||
|
Компонент не является архитектурной единицей: он не владеет сценарием, зависимостями, данными или внутренней структурой. Он работает только внутри границы родительского модуля.
|
||||||
|
|
||||||
|
> Компонент отображает. Модуль организует.
|
||||||
|
|
||||||
|
Компонент не может:
|
||||||
|
|
||||||
|
- Импортировать код проекта за пределами родительского модуля.
|
||||||
|
- Владеть архитектурными зависимостями.
|
||||||
|
- Содержать любые компоненты.
|
||||||
|
- Содержать любые модули.
|
||||||
|
- Делать внешние запросы.
|
||||||
|
- Самостоятельно получать данные.
|
||||||
|
- Выбирать источник данных.
|
||||||
|
- Композировать данные.
|
||||||
|
- Вызывать сценарные хуки.
|
||||||
|
- Оркестрировать сценарий.
|
||||||
|
- Композировать модули.
|
||||||
|
- Решать, как устроен процесс.
|
||||||
|
- Содержать бизнес-логику.
|
||||||
|
- Содержать сценарную логику.
|
||||||
|
|
||||||
|
Если компоненту требуется что-то из этого списка, он перестаёт быть компонентом и должен быть оформлен как модуль.
|
||||||
|
|
||||||
|
```text
|
||||||
|
auth/
|
||||||
|
├── ui/
|
||||||
|
│ └── logout-button/
|
||||||
|
│ ├── logout-button.tsx
|
||||||
|
│ ├── styles/
|
||||||
|
│ │ └── logout-button.module.css
|
||||||
|
│ ├── types/
|
||||||
|
│ │ └── logout-button-props.type.ts
|
||||||
|
│ └── index.ts
|
||||||
|
└── index.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
## Что считается модулем
|
||||||
|
|
||||||
|
Модулем считается папка, которая представляет самостоятельную область ответственности и имеет публичную границу.
|
||||||
|
|
||||||
|
Примеры модулей:
|
||||||
|
|
||||||
|
- `screens/home/` — модуль страницы.
|
||||||
|
- `widgets/page-heading/` — модуль виджета.
|
||||||
|
- `business/auth/` — модуль бизнес-домена.
|
||||||
|
- `infra/theme/` — модуль инфраструктурного сервиса.
|
||||||
|
- `ui/button/` — модуль UI-kit сущности.
|
||||||
|
- `screens/home/parts/hero-section/` — вложенный модуль страницы.
|
||||||
|
|
||||||
|
Не считаются модулями:
|
||||||
|
|
||||||
|
- `ui/`, `parts/`, `hooks/`, `types/`, `styles/`, `config/` — это сегменты.
|
||||||
|
- `screens/shop/`, `business/commerce/` — это группы, если в них нет `index.ts`.
|
||||||
|
- `screens/home/ui/user-card/` — это компонент, если он находится в `ui/` и соблюдает ограничения компонента.
|
||||||
|
|
||||||
|
## Типы модулей
|
||||||
|
|
||||||
|
Тип модуля определяет обязательный корневой файл и стартовую структуру.
|
||||||
|
|
||||||
|
### UI-модуль
|
||||||
|
|
||||||
|
Модуль строится вокруг основного UI-компонента и обязан иметь основной `.tsx` файл в корне:
|
||||||
|
|
||||||
|
```text
|
||||||
|
header/
|
||||||
|
├── header.tsx
|
||||||
|
└── index.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
`ui/` внутри такого модуля используется только для компонентов, которые помогают корневому `.tsx` файлу.
|
||||||
|
|
||||||
|
### Бизнес-модуль
|
||||||
|
|
||||||
|
Бизнес-модуль — модуль, который строится вокруг публичного runtime API.
|
||||||
|
|
||||||
|
Бизнес-модуль обязан иметь фабрику в корне:
|
||||||
|
|
||||||
|
```text
|
||||||
|
auth/
|
||||||
|
├── auth.factory.ts
|
||||||
|
├── index.ts
|
||||||
|
└── types/
|
||||||
|
```
|
||||||
|
|
||||||
|
Фабрика возвращает публичный runtime API модуля.
|
||||||
|
|
||||||
|
### Инфраструктурный модуль
|
||||||
|
|
||||||
|
Инфраструктурный модуль — модуль, который строится вокруг технического сервиса или интеграции.
|
||||||
|
|
||||||
|
Инфраструктурный модуль не обязан иметь фиксированный корневой файл. Его структура определяется природой сервиса.
|
||||||
|
|
||||||
|
```text
|
||||||
|
theme/
|
||||||
|
├── index.ts
|
||||||
|
├── config/
|
||||||
|
├── hooks/
|
||||||
|
├── styles/
|
||||||
|
└── ui/
|
||||||
|
```
|
||||||
|
|
||||||
|
```text
|
||||||
|
backend-api/
|
||||||
|
├── backend-api.client.ts
|
||||||
|
├── config/
|
||||||
|
├── types/
|
||||||
|
└── index.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
## Структура
|
||||||
|
|
||||||
|
Модуль состоит из сегментов. Ни один сегмент не обязателен — модуль включает только те части, которые нужны его ответственности.
|
||||||
|
|
||||||
|
```text
|
||||||
|
{module-name}/
|
||||||
|
├── {module-name}.factory.ts # фабрика (для business-модулей)
|
||||||
|
├── {module-name}.tsx # корневой файл модуля (опционален)
|
||||||
|
├── ui/ # компоненты модуля
|
||||||
|
├── parts/ # вложенные модули
|
||||||
|
├── hooks/ # хуки
|
||||||
|
├── stores/ # сторы состояния
|
||||||
|
├── services/ # внешние источники данных
|
||||||
|
├── mappers/ # трансформация данных между форматами
|
||||||
|
├── types/ # типы
|
||||||
|
├── styles/ # стили
|
||||||
|
├── lib/ # утилиты модуля
|
||||||
|
├── config/ # константы и конфигурация
|
||||||
|
└── index.ts # публичный API
|
||||||
|
```
|
||||||
|
|
||||||
|
Подробное описание сегментов — в разделе [Сегменты](./segments.md).
|
||||||
|
|
||||||
|
## Публичный API
|
||||||
|
|
||||||
|
Внешний код импортирует модуль только через публичный API.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// Хорошо
|
||||||
|
import { customerFactory } from '@/business/customer'
|
||||||
|
import type { Customer } from '@/business/customer'
|
||||||
|
```
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// Плохо
|
||||||
|
import { validateToken } from '@/business/auth/lib/tokens'
|
||||||
|
```
|
||||||
|
|
||||||
|
`index.ts` модуля не обязан экспортировать всё содержимое. Он экспортирует только то, что действительно нужно снаружи.
|
||||||
|
|
||||||
|
Внутренние сегменты модуля остаются деталями реализации.
|
||||||
|
|
||||||
|
Business-модуль экспортирует из `index.ts` только фабрику и type-only экспорты. Хуки, компоненты, сервисы, мапперы и утилиты напрямую из `index.ts` не экспортируются — они доступны через API, который возвращает фабрика.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// business/customer/index.ts
|
||||||
|
export { customerFactory } from './customer.factory'
|
||||||
|
|
||||||
|
export type { Customer } from './types/customer.type'
|
||||||
|
export type { CustomerApi } from './types/customer-api.type'
|
||||||
|
export type { CustomerDeps } from './types/customer-deps.type'
|
||||||
|
export type { CustomerFactory } from './types/customer-factory.type'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Фабрика
|
||||||
|
|
||||||
|
Business-модуль всегда экспортирует фабрику. Фабрика лежит в корне модуля (`{name}.factory.ts`), типизируется через `{Name}Factory` и возвращает публичный runtime API модуля.
|
||||||
|
|
||||||
|
Всё, что нужно внешнему коду в runtime, должно быть частью API, который возвращает фабрика.
|
||||||
|
|
||||||
|
Модуль без cross-domain зависимостей экспортирует фабрику без аргументов. Модуль с зависимостями — фабрику, принимающую зависимости доменными именами. Типы всегда экспортируются напрямую через `export type` — `import type` не является runtime-зависимостью.
|
||||||
|
|
||||||
|
Компоновка фабрик происходит на уровне модуля-потребителя: screen, layout, widget или любой другой модуль группы «Композиция».
|
||||||
|
|
||||||
|
### Структура business-модуля
|
||||||
|
|
||||||
|
```text
|
||||||
|
business/customer/
|
||||||
|
├── customer.factory.ts
|
||||||
|
├── index.ts
|
||||||
|
└── types/
|
||||||
|
├── customer.type.ts
|
||||||
|
├── customer-api.type.ts
|
||||||
|
├── customer-deps.type.ts
|
||||||
|
└── customer-factory.type.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
### Типы
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// business/customer/types/customer-api.type.ts
|
||||||
|
export type CustomerApi = {
|
||||||
|
useCustomer: () => Customer
|
||||||
|
CustomerCard: (props: CustomerCardProps) => ReactNode
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// business/order/types/order-deps.type.ts
|
||||||
|
export type OrderDeps = {
|
||||||
|
customer: Pick<CustomerApi, 'useCustomer'>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// business/order/types/order-factory.type.ts
|
||||||
|
export type OrderFactory = (deps: OrderDeps) => OrderApi
|
||||||
|
```
|
||||||
|
|
||||||
|
### Фабрика без зависимостей
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// business/customer/customer.factory.ts
|
||||||
|
import type { CustomerFactory } from './types/customer-factory.type'
|
||||||
|
|
||||||
|
export const customerFactory: CustomerFactory = () => {
|
||||||
|
return {
|
||||||
|
useCustomer,
|
||||||
|
CustomerCard,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Фабрика с зависимостями
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// business/order/order.factory.ts
|
||||||
|
import type { OrderFactory } from './types/order-factory.type'
|
||||||
|
|
||||||
|
export const orderFactory: OrderFactory = (deps) => {
|
||||||
|
return {
|
||||||
|
useOrder,
|
||||||
|
OrderCard,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Композиция на уровне screen
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
// screens/home/home.screen.tsx
|
||||||
|
import { customerFactory } from '@/business/customer'
|
||||||
|
import { orderFactory } from '@/business/order'
|
||||||
|
|
||||||
|
const customer = customerFactory()
|
||||||
|
const order = orderFactory({ customer })
|
||||||
|
|
||||||
|
const { useOrder, OrderCard } = order
|
||||||
|
|
||||||
|
export const HomeScreen = () => {
|
||||||
|
const currentOrder = useOrder()
|
||||||
|
|
||||||
|
return <OrderCard order={currentOrder} />
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Жизненный цикл
|
||||||
|
|
||||||
|
Модуль рождается на самом низком уровне использования и поднимается выше только при реальной потребности.
|
||||||
|
|
||||||
|
- Нужен на одной странице → `screens/{name}/parts/`
|
||||||
|
- Появился в 2+ местах → поднимается по природе:
|
||||||
|
- абстрактный UI → `ui/`
|
||||||
|
- блок с данными/логикой → `widgets/`
|
||||||
|
- представление бизнес-домена → `business/{area}/parts/`
|
||||||
|
|
||||||
|
Подъём — обычный рефакторинг в рамках задачи, а не отдельная активность.
|
||||||
@@ -1,165 +0,0 @@
|
|||||||
---
|
|
||||||
title: Модули SLM
|
|
||||||
description: Что такое модуль в SLM-архитектуре и как он устроен.
|
|
||||||
---
|
|
||||||
|
|
||||||
# Модули SLM
|
|
||||||
|
|
||||||
Что такое модуль в SLM-архитектуре и как он устроен.
|
|
||||||
|
|
||||||
## Определение
|
|
||||||
|
|
||||||
**Модуль — универсальный строительный блок архитектуры. Живёт на слое и содержит всё необходимое для своей работы: компоненты, хуки, сторы, сервисы, типы, стили. Набор содержимого не фиксирован — включаются только нужные части.**
|
|
||||||
|
|
||||||
## Модуль vs компонент
|
|
||||||
|
|
||||||
**Компонент** — один `.tsx` файл. Не имеет своих сегментов, использует сегменты родительского модуля. Живёт в корне или `ui/` сегменте модуля.
|
|
||||||
|
|
||||||
**Модуль** — папка, которая может содержать корневой компонент, сегменты (`hooks/`, `types/`, `styles/`, `ui/`, `parts/` и т.д.) и публичный API (`index.ts`).
|
|
||||||
|
|
||||||
```text
|
|
||||||
auth/
|
|
||||||
├── ui/
|
|
||||||
│ ├── auth-guard.tsx
|
|
||||||
│ └── logout-button.tsx
|
|
||||||
├── parts/
|
|
||||||
│ ├── login-form/
|
|
||||||
│ ├── registration-form/
|
|
||||||
│ └── restore-form/
|
|
||||||
├── hooks/
|
|
||||||
├── stores/
|
|
||||||
├── types/
|
|
||||||
├── auth.tsx # корневой компонент (опционален)
|
|
||||||
└── index.ts
|
|
||||||
```
|
|
||||||
|
|
||||||
## Структура
|
|
||||||
|
|
||||||
Модуль состоит из сегментов. Ни один сегмент не обязателен — модуль может состоять даже из одного `index.ts` с реэкспортом типов.
|
|
||||||
|
|
||||||
```text
|
|
||||||
{module-name}/
|
|
||||||
├── {module-name}.tsx # корневой компонент (опционален)
|
|
||||||
├── ui/ # компоненты модуля (только .tsx)
|
|
||||||
├── parts/ # вложенные модули (со своими сегментами)
|
|
||||||
├── hooks/ # хуки
|
|
||||||
├── stores/ # сторы состояния
|
|
||||||
├── services/ # внешние источники данных
|
|
||||||
├── mappers/ # трансформация данных между форматами
|
|
||||||
├── types/ # типы
|
|
||||||
├── styles/ # стили
|
|
||||||
├── lib/ # утилиты модуля
|
|
||||||
├── config/ # константы
|
|
||||||
└── index.ts # публичный API
|
|
||||||
```
|
|
||||||
|
|
||||||
Подробное описание каждого сегмента — в разделе [Сегменты](/docs/basics/architecture/reference/segments).
|
|
||||||
|
|
||||||
## Публичный API
|
|
||||||
|
|
||||||
Модуль экспортирует наружу только то, что нужно другим. Всё остальное — внутреннее.
|
|
||||||
|
|
||||||
```ts
|
|
||||||
// business/auth/index.ts
|
|
||||||
export type { User, Session } from './types/user.types'
|
|
||||||
export { useAuth } from './hooks/use-auth.hook'
|
|
||||||
export { AuthGuard } from './ui/auth-guard'
|
|
||||||
```
|
|
||||||
|
|
||||||
Импорт в обход `index.ts` запрещён:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
// Плохо
|
|
||||||
import { validateToken } from '@/business/auth/lib/tokens'
|
|
||||||
|
|
||||||
// Хорошо
|
|
||||||
import { useAuth } from '@/business/auth'
|
|
||||||
```
|
|
||||||
|
|
||||||
## Фабрика
|
|
||||||
|
|
||||||
Если модуль зависит от кода другого бизнес-домена — он экспортирует фабрику. Фабрика декларирует необходимые зависимости и возвращает API модуля. Точка использования (screen, widget, layout) предоставляет зависимости при вызове.
|
|
||||||
|
|
||||||
Модуль без cross-domain зависимостей экспортирует API напрямую. Типы всегда экспортируются напрямую — `import type` не является runtime-зависимостью.
|
|
||||||
|
|
||||||
### Модуль без зависимостей — прямой экспорт:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
// business/auth/index.ts
|
|
||||||
export { useAuth } from './hooks/use-auth'
|
|
||||||
export { useCurrentUser } from './hooks/use-current-user'
|
|
||||||
export type { User, Session } from './types'
|
|
||||||
```
|
|
||||||
|
|
||||||
### Модуль с зависимостями — фабрика:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
// business/chat/types/deps.ts
|
|
||||||
import type { User } from '@/business/auth'
|
|
||||||
|
|
||||||
export interface ChatDeps {
|
|
||||||
useCurrentUser: () => User | null
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
```ts
|
|
||||||
// business/chat/index.ts
|
|
||||||
import type { ChatDeps } from './types/deps'
|
|
||||||
|
|
||||||
export function chatFactory(deps: ChatDeps) {
|
|
||||||
return {
|
|
||||||
useMessages: (roomId: string) => {
|
|
||||||
const user = deps.useCurrentUser()
|
|
||||||
// ...
|
|
||||||
},
|
|
||||||
useSendMessage: (roomId: string) => {
|
|
||||||
const user = deps.useCurrentUser()
|
|
||||||
return (text: string) => { /* ... */ }
|
|
||||||
},
|
|
||||||
useChatRooms: () => {
|
|
||||||
const user = deps.useCurrentUser()
|
|
||||||
// ...
|
|
||||||
},
|
|
||||||
ChatBadge: ({ count }: { count: number }) => { /* ... */ },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export type { Message, ChatRoom } from './types'
|
|
||||||
export type { ChatDeps } from './types/deps'
|
|
||||||
```
|
|
||||||
|
|
||||||
### Использование на странице:
|
|
||||||
|
|
||||||
```tsx
|
|
||||||
// screens/support/support.tsx
|
|
||||||
import { useCurrentUser } from '@/business/auth'
|
|
||||||
import { chatFactory } from '@/business/chat'
|
|
||||||
|
|
||||||
const chat = chatFactory({ useCurrentUser })
|
|
||||||
|
|
||||||
export function SupportScreen() {
|
|
||||||
const { useMessages, useSendMessage, ChatBadge } = chat
|
|
||||||
const messages = useMessages('support')
|
|
||||||
const sendMessage = useSendMessage('support')
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<ChatBadge count={messages.length} />
|
|
||||||
{messages.map(m => <MessageBubble key={m.id} {...m} />)}
|
|
||||||
<MessageInput onSend={sendMessage} />
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Жизненный цикл
|
|
||||||
|
|
||||||
Модуль рождается на самом низком уровне использования и поднимается выше только при реальной потребности.
|
|
||||||
|
|
||||||
- Нужен на одной странице → `screens/{name}/parts/`
|
|
||||||
- Появился в 2+ местах → поднимается по природе:
|
|
||||||
- абстрактный UI → `ui/`
|
|
||||||
- блок с данными/логикой → `widgets/`
|
|
||||||
- представление бизнес-домена → `business/{area}/parts/`
|
|
||||||
|
|
||||||
Подъём — обычный рефакторинг в рамках задачи, а не отдельная активность.
|
|
||||||
@@ -1,11 +1,6 @@
|
|||||||
---
|
# Сегменты
|
||||||
title: Сегменты SLM
|
|
||||||
description: Что такое сегмент модуля в SLM-архитектуре и какие они бывают.
|
|
||||||
---
|
|
||||||
|
|
||||||
# Сегменты SLM
|
Раздел описывает сегменты SLM: что такое сегмент, какие бывают и что в каждом из них лежит.
|
||||||
|
|
||||||
Что такое сегмент модуля в SLM-архитектуре и какие они бывают.
|
|
||||||
|
|
||||||
## Определение
|
## Определение
|
||||||
|
|
||||||
@@ -15,7 +10,7 @@ description: Что такое сегмент модуля в SLM-архитек
|
|||||||
|
|
||||||
| Сегмент | Содержимое |
|
| Сегмент | Содержимое |
|
||||||
|---------|------------|
|
|---------|------------|
|
||||||
| `ui/` | Вспомогательные компоненты модуля — только `.tsx` файлы |
|
| `ui/` | Презентационные компоненты родительского модуля |
|
||||||
| `parts/` | Вложенные модули со своими сегментами |
|
| `parts/` | Вложенные модули со своими сегментами |
|
||||||
| `hooks/` | React-хуки |
|
| `hooks/` | React-хуки |
|
||||||
| `stores/` | Сторы состояния |
|
| `stores/` | Сторы состояния |
|
||||||
@@ -28,22 +23,44 @@ description: Что такое сегмент модуля в SLM-архитек
|
|||||||
|
|
||||||
## Сегмент ui/
|
## Сегмент ui/
|
||||||
|
|
||||||
Вспомогательные компоненты модуля. Содержит только `.tsx` файлы — без своих сегментов, стилей, типов, хуков и публичного API. Использует сегменты родительского модуля.
|
Презентационные компоненты родительского модуля. `ui/` содержит только компоненты, которые отвечают за отображение части интерфейса и не выходят за границы своего модуля.
|
||||||
|
|
||||||
Корневой компонент модуля в `ui/` не размещается. Он лежит в корне модуля: `{module-name}.tsx`.
|
Компонент в `ui/`:
|
||||||
|
|
||||||
|
- Находится в собственной папке.
|
||||||
|
- Может содержать только `{name}.tsx`, `index.ts`, `styles/`, `types/`.
|
||||||
|
- Не содержит любые компоненты.
|
||||||
|
- Не содержит любые модули.
|
||||||
|
- Не импортирует код проекта за пределами родительского модуля.
|
||||||
|
- Не делает внешние запросы.
|
||||||
|
- Не вызывает сценарные хуки.
|
||||||
|
- Не получает данные самостоятельно, не выбирает источник данных и не композирует данные.
|
||||||
|
- Не содержит бизнес-логику или сценарную логику.
|
||||||
|
|
||||||
|
Если UI-сущности нужно что-то за пределами этих ограничений, она должна быть оформлена как модуль. Полная граница описана в разделе [Компонент](./modules.md#компонент).
|
||||||
|
|
||||||
|
Корневой файл модуля в `ui/` не размещается. Он лежит в корне модуля: `{module-name}.tsx`.
|
||||||
|
|
||||||
```text
|
```text
|
||||||
user/
|
user/
|
||||||
├── ui/
|
├── ui/
|
||||||
│ ├── user-avatar.tsx
|
│ ├── user-avatar/
|
||||||
│ └── user-status.tsx
|
│ │ ├── user-avatar.tsx
|
||||||
|
│ │ ├── styles/
|
||||||
|
│ │ │ └── user-avatar.module.css
|
||||||
|
│ │ ├── types/
|
||||||
|
│ │ │ └── user-avatar-props.type.ts
|
||||||
|
│ │ └── index.ts
|
||||||
|
│ └── user-status/
|
||||||
|
│ ├── user-status.tsx
|
||||||
|
│ └── index.ts
|
||||||
├── types/
|
├── types/
|
||||||
├── hooks/
|
├── hooks/
|
||||||
├── user.tsx
|
├── user.tsx
|
||||||
└── index.ts
|
└── index.ts
|
||||||
```
|
```
|
||||||
|
|
||||||
Если компоненту нужны собственные сегменты — это уже не `ui/`, а `parts/`.
|
Если UI-сущности нужна внутренняя декомпозиция, сценарная логика, получение данных или собственные архитектурные зависимости — это уже не компонент в `ui/`, а модуль в `parts/`.
|
||||||
|
|
||||||
## Сегмент parts/
|
## Сегмент parts/
|
||||||
|
|
||||||
@@ -68,7 +85,7 @@ home/
|
|||||||
└── index.ts
|
└── index.ts
|
||||||
```
|
```
|
||||||
|
|
||||||
Отличие от `ui/`: элемент `parts/` — модульная папка со своими сегментами. Элемент `ui/` — вспомогательный компонент, один `.tsx` файл.
|
Отличие от `ui/`: элемент `parts/` — модульная папка со своими сегментами. Элемент `ui/` — компонент родительского модуля без собственной архитектурной ответственности.
|
||||||
|
|
||||||
Вложенность `parts/` инкапсулирует область разработки горизонтально: каждый разработчик работает в своём `parts/`-модуле, не затрагивая чужие. Это снижает конфликты при параллельной разработке.
|
Вложенность `parts/` инкапсулирует область разработки горизонтально: каждый разработчик работает в своём `parts/`-модуле, не затрагивая чужие. Это снижает конфликты при параллельной разработке.
|
||||||
|
|
||||||
@@ -156,4 +173,4 @@ lib/
|
|||||||
config/
|
config/
|
||||||
├── routes.ts
|
├── routes.ts
|
||||||
└── constants.ts
|
└── constants.ts
|
||||||
```
|
```
|
||||||
@@ -9,11 +9,16 @@ description: Как типизируется код в проекте.
|
|||||||
|
|
||||||
## Общие правила
|
## Общие правила
|
||||||
|
|
||||||
- Указывать типы для параметров компонентов, возвращаемых значений и параметров функций.
|
- Указывать типы для параметров компонентов и параметров функций.
|
||||||
- Предпочитать `type` для описания сущностей и `interface` для расширяемых контрактов.
|
- Предпочитать `type` для описания сущностей и `interface` для расширяемых контрактов.
|
||||||
- Избегать `any` и `unknown` без необходимости.
|
- Избегать `any` и `unknown` без необходимости.
|
||||||
- Не использовать `ts-ignore`, кроме крайних случаев с явным комментарием причины.
|
- Не использовать `ts-ignore`, кроме крайних случаев с явным комментарием причины.
|
||||||
|
|
||||||
|
## React-компоненты
|
||||||
|
|
||||||
|
- Пропсы компонента типизировать через отдельный `Props`.
|
||||||
|
- Возвращаемый тип компонента не указывать: TypeScript корректно выводит JSX-результат, а явный `ReactElement` сужает допустимые варианты возврата.
|
||||||
|
|
||||||
## Функции
|
## Функции
|
||||||
|
|
||||||
- Для публичных функций указывать возвращаемый тип.
|
- Для публичных функций указывать возвращаемый тип.
|
||||||
|
|||||||
Reference in New Issue
Block a user