165 lines
6.5 KiB
Markdown
165 lines
6.5 KiB
Markdown
|
|
---
|
|||
|
|
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/`
|
|||
|
|
|
|||
|
|
Подъём — обычный рефакторинг в рамках задачи, а не отдельная активность.
|