Модуль
Как создавать и организовывать SLM-модули в проекте.
Назначение
Модуль — основной строительный блок SLM-архитектуры. Это папка с публичным API (index.ts) и опциональными сегментами: компонентами, стилями, типами, хуками, сторами, сервисами и вложенными модулями.
Если UI-сущность остаётся одним .tsx файлом и использует ресурсы родительского модуля — это компонент, а не модуль. Связанные файлы в styles/ и types/ родителя не создают новую модульную границу.
Архитектурное определение: Модули SLM. Список сегментов: Сегменты SLM.
Когда нужен модуль
Создавайте модуль, если сущности нужны:
- публичный API;
- хуки, сторы, сервисы, мапперы или утилиты;
- вложенные части;
- переиспользование вне родительского модуля;
- самостоятельная ответственность на слое.
Если понадобилась папка вокруг компонента — это сигнал, что нужен модуль.
Где размещать
Модуль размещается на самом низком уровне использования.
- Нужен только одному модулю — размещается в
parts/родителя. - Нужен одной странице — размещается в
screens/{name}/parts/. - Нужен одному layout — размещается в
layouts/{name}/parts/. - Переиспользуется между страницами или layout — поднимается в
widgets/. - Представляет бизнес-домен — размещается в
business/. - Является UI-китом — размещается в
ui/.
app/ не содержит модулей. Это слой файлового роутинга и инициализации.
Структура
Минимальный UI-модуль:
user/
├── user.tsx
└── index.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/ не кладутся.
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 — единственная точка входа в модуль. Внешние импорты внутренних файлов запрещены.
// user/index.ts
export { User } from './user'
export type { UserProps } from './types/user.type'// Плохо: импорт в обход публичного API.
import { UserPosts } from 'screens/user/parts/user-posts/user-posts'
// Хорошо: импорт через публичный API родительского модуля.
import { User } from 'screens/user'Вложенный модуль имеет свой index.ts, но наружу родителя экспортируется только при необходимости.
Именование
Базовые правила описаны в разделе Именование.
- Папка модуля —
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-модуль
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.tsBusiness-модуль без корневого компонента
business/auth/
├── hooks/
│ └── use-auth.hook.ts
├── services/
│ └── auth.service.ts
├── stores/
│ └── auth.store.ts
├── types/
│ └── auth.type.ts
└── index.ts