Files
slm-design/docs/ru/reference/modules.md

165 lines
6.5 KiB
Markdown
Raw Normal View History

---
title: Модули
---
# Модули
Раздел описывает модули 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
```
Подробное описание каждого сегмента — в разделе [Сегменты](/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/`
Подъём — обычный рефакторинг в рамках задачи, а не отдельная активность.