2026-01-30 02:02:32 +03:00
< a name = "1-tech-stackmd" > < / a >
# Технологии и библиотеки
Базовый стек технологий и библиотек, на который опираются проекты и примеры в документации.
## Что используем обычно
- **TypeScript** — типизация всей логики и компонентов.
- **FSD (Feature-Sliced Design)** — структура проекта и границы модулей.
- **React + Next.js** — основной стек для UI и приложения.
- **Mantine UI** — базовые UI-компоненты.
- **SWR** — получение данных по GET (кеширование и revalidate).
- **Zustand** — глобальное состояние.
- **i18next (i18n)** — локализация всех пользовательских текстов.
- **Vitest** — тестирование.
2026-01-30 13:21:04 +03:00
- **clsx** — конкатенация CSS‑ кла с с о в.
2026-01-30 02:02:32 +03:00
- **PostCSS Modules** — изоляция стилей.
- **Mobile First** — подход к адаптивной верстке.
< a name = "2-architecturemd" > < / a >
# Архитектура
Архитектура построена на FSD (Feature‑ Sliced Design) и строгих границах модулей.
Цель — разделить ответственность, упростить сопровождение и контроль зависимостей.
## Принципы
- Разделять UI, бизнес-логику и инфраструктуру.
- Держать зависимости однонаправленными.
- Открывать наружу только публичный API модулей.
- Н е допускать циклических зависимостей.
## Слои
- **app** — инициализация приложения, роутинг, конфигурации, глобальные провайдеры.
- **screens** — экраны и их композиция.
- **layouts** — каркас и шаблоны страниц.
- **widgets** — крупные блоки интерфейса, собирающие несколько сценариев.
- **features** — отдельные пользовательские действия и сценарии.
- **entities** — бизнес-сущности и их модель.
- **shared** — переиспользуемая инфраструктура, утилиты и базовые UI‑ ко мпо не нты.
## Правила зависимостей
- Допустимые импорты идут сверху вниз: `app → screens → layouts → widgets → features → entities → shared` .
- Импорты между слоями — через публичный API.
- Внутри одного слоя — относительные импорты.
## Публичный API модулей
- Каждый модуль экспортирует наружу только то, что нужно другим слоям.
- Внешние импорты идут только через `index` ‑файл модуля.
- Внутренние файлы не импортируются напрямую извне.
## Границы ответственности
- Бизнес‑логика не размещается в UI‑ ко мпо не нта х .
- UI‑ ко мпо не нты должны быть максимально простыми и предсказуемыми.
- Связь между независимыми сценариями поднимается на уровень выше.
## Типовые ошибки
- Импорт из более высокого слоя в более низкий.
- Смешивание логики нескольких слоёв в одном модуле.
- Прямые импорты внутренних файлов, минуя публичный API.
< a name = "3-code-stylemd" > < / a >
# Стиль кода
Раздел описывает единые правила оформления кода: отступы, переносы, кавычки, порядок импортов и базовую читаемость.
## Отступы
- 2 пробела (не табы).
## Длина строк
- Ориентироваться на 100 символов, но превышение допустимо, если строка читается легко.
- Переносить выражение на новые строки, когда строка становится плохо читаемой.
- Н е переносить строку внутри строковых литералов без необходимости.
**Хорошо**
```ts
const config = createRequestConfig(
endpoint,
{
headers: {
'X-Request-Id': requestId,
'X-User-Id': userId,
},
params: {
page,
pageSize,
sort: 'createdAt',
},
},
timeoutMs,
);
```
**Плохо**
```ts
// Плохо: длинная строка с вложенными структурами плохо читается.
const config = createRequestConfig(endpoint, { headers: { 'X-Request-Id': requestId, 'X-User-Id': userId }, params: { page, pageSize, sort: 'createdAt' } }, timeoutMs);
```
## Кавычки
- В JavaScript/TypeScript использовать одинарные кавычки.
- В JSX/TSX для атрибутов использовать двойные кавычки.
- Шаблонные строки использовать только при интерполяции или многострочном тексте.
**Хорошо**
```ts
const label = 'Сохранить';
const title = `Привет, ${name}` ;
```
```tsx
< input type = "text" placeholder = "Введите имя" / >
```
**Плохо**
```ts
// Плохо: двойные кавычки в TS и конкатенация вместо шаблонной строки.
const label = "Сохранить";
const title = 'Привет, ' + name;
```
```tsx
// Плохо: одинарные кавычки в JSX-атрибутах.
< input type = 'text' placeholder = 'Введите имя' / >
```
## Точки с запятой и запятые
- Допускаются упущения точки с запятой, если код остаётся читаемым и однозначным.
- В многострочных массивах, объектах и параметрах функции запятая в конце допускается, но не обязательна.
## Импорты
- В именованных импортах использовать пробелы внутри фигурных скобок.
- Типы импортировать через `import type` .
- `default` импорт и экспорт избегать, использовать именованные.
- Избегать импорта всего модуля через `*` .
**Хорошо**
```ts
import { MyComponent } from 'MyComponent';
import type { User } from '../model/types';
```
**Плохо**
```ts
// Плохо: default импорт и отсутствие пробелов в именованном импорте.
import MyComponent from 'MyComponent';
import type {User} from '../model/types';
```
## Ранние возвраты (early return)
- Использовать ранние возвраты для упрощения чтения.
- Избегать `else` после `return` .
**Хорошо**
```ts
const getName = (user?: { name: string }) => {
if (!user) {
return 'Гость';
}
return user.name;
};
```
**Плохо**
```ts
// Плохо: лишний else после return усложняет чтение.
const getName = (user?: { name: string }) => {
if (user) {
return user.name;
} else {
return 'Гость';
}
};
```
## Форматирование объектов и массивов
- В многострочных объектах каждое свойство на новой строке.
- В многострочных массивах каждый элемент на новой строке.
- Объекты и массивы можно писать в одну строку, если длина строки не превышает 100 символов.
- В однострочных объектах и массивах использовать пробелы после запятых.
**Хорошо**
```ts
const roles = ['admin', 'editor', 'viewer'];
const options = { id: 1, name: 'User' };
const config = {
url: '/api/users',
method: 'GET',
params: { page: 1, pageSize: 20 },
};
```
**Плохо**
```ts
// Плохо: нет пробелов после запятых и объект слишком длинный для одной строки.
const roles = ['admin','editor','viewer'];
const options = { id: 1,name: 'User' };
const config = { url: '/api/users', method: 'GET', params: { page: 1, pageSize: 20 } };
```
< a name = "4-namingmd" > < / a >
# Именование
Именование должно быть предсказуемым, коротким и отражать смысл сущности.
## Базовые правила
| Что | Рекомендуется |
| ---------------- | ---------------------- |
| Папки | `kebab-case` |
| Файлы | `kebab-case` |
| Переменные | `camelCase` |
| Константы | `SCREAMING_SNAKE_CASE` |
| Классы | `PascalCase` |
| React-компоненты | `PascalCase` |
| Хуки | `useSomething` |
| CSS классы | `camelCase` |
## Архитектурный неймспейс
Соглашение о суффиксах, которые обозначают слой (уровень абстракции), роль или тип файла.
- Суффиксы используются для обозначения слоя, роли или типа файла.
- Суффиксы всегда пишутся в единственном числе.
- Формат имени: `name.<suffix>.ts` или `name.<suffix>.tsx` .
**UI и слои FSD**
- `.screen.tsx` — экран
- `.layout.tsx` — layout
- `.widget.tsx` — виджет
- `.feature.tsx` — UI фичи
- `.entity.tsx` — UI сущности
- `.ui.tsx` — UI‑ ко мпо не нт
**Логика и модель**
- `.store.ts` — стор
- `.service.ts` — сервис
**Типы и контракты**
- `.type.ts` — типы и интерфейсы
- `.interface.ts` — файл с интерфейсами (если нужен отдельный контракт)
- `.enum.ts` — enum
- `.dto.ts` — внешние DTO
- `.schema.ts` — схемы валидации
- `.constant.ts` — константы
- `.config.ts` — конфигурация
**Утилиты и хелперы**
- `.util.ts` — утилиты
- `.helper.ts` — вспомогательные функции
- `.lib.ts` — вспомогательные функции
**Тесты**
- `.test.ts` / `.test.tsx`
- `.mock.ts`
**Хорошо**
```text
src/
├── screens/
│ └── main/
│ ├── main.screen.tsx
│ └── index.ts
├── features/
│ └── auth-by-email/
│ ├── ui/
│ │ └── login-form.ui.tsx
│ ├── auth-by-email.feature.tsx
│ └── index.ts
└── shared/
└── ui/
└── icon/
├── icon.ui.tsx
└── icon.module.css
```
**Плохо**
```text
// Плохо: нет единых правил для слоёв и публичных файлов.
src/
├── screens/
│ └── Main/
│ └── Main.tsx
└── features/
└── authByEmail/
└── login-form.tsx
```
## Булевы значения
- Использовать префиксы `is` , `has` , `can` , `should` .
**Хорошо**
```ts
const isReady = true;
const hasAccess = false;
const canSubmit = true;
const shouldRedirect = false;
```
**Плохо**
```ts
// Плохо: неясное булево значение без префикса.
const ready = true;
const access = false;
const submit = true;
```
## События и обработчики
- Обработчики начинать с `handle` .
- События и колбэки начинать с `on` .
**Хорошо**
```ts
const handleSubmit = () => { ... };
const onSubmit = () => { ... };
```
**Плохо**
```ts
// Плохо: неочевидное назначение имени.
const submitClick = () => { ... };
```
## Коллекции
- Для массивов использовать имена во множественном числе.
- Для словарей/мап — использовать суффиксы `ById` , `Map` , `Dict` .
**Хорошо**
```ts
const users = [];
const usersById = {} as Record< string , User > ;
const userIds = ['u1', 'u2'];
const ordersMap = new Map< string , Order > ();
const featureFlagsDict = { beta: true, legacy: false } as Record< string , boolean > ;
```
**Плохо**
```ts
// Плохо: имя не отражает, что это коллекция.
const user = [];
// Плохо: словарь назван как массив.
const usersMap = [];
// Плохо: по имени непонятно, что это словарь.
const users = {} as Record< string , User > ;
```
< a name = "5-documentationmd" > < / a >
# Документирование
Документирование должно помогать понять назначение сущности, а не дублировать её типы или очевидные детали.
## Правила
- Документировать только назначение функций, компонентов, типов, интерфейсов и enum.
- Н е документировать параметры, возвращаемые значения, типы пропсов и очевидные детали.
- В интерфейсах, типах и enum описывать только смысл поля или значения.
- Описание должно быть кратким, информативным и завершаться точкой.
## Примеры
**Хорошо**
```ts
/**
* Список задач пользователя.
*/
export const TodoList = memo(() => { ... });
/**
* Интерфейс задачи.
*/
export interface TodoItem {
/** Уникальный идентификатор задачи. */
id: string;
/** Текст задачи. */
text: string;
/** Статус выполнения задачи. */
completed: boolean;
}
/**
* Перечисление фильтров задач.
*/
export enum TodoFilter {
/** В с е задачи. */
All = 'all',
/** Только активные задачи. */
Active = 'active',
/** Только выполненные задачи. */
Completed = 'completed',
}
```
**Плохо**
```ts
// Плохо: дублирование параметров и возвращаемых значений.
/**
* @param id - идентификатор задачи
* @returns объект задачи
*/
// Плохо: описание очевидных деталей.
/**
* id — идентификатор задачи
* text — текст задачи
* completed — статус выполнения
*/
```
< a name = "6-typingmd" > < / a >
# Типизация
Типизация обязательна для всех публичных интерфейсов, функций и компонентов.
Цель — предсказуемость, безопасность и автодополнение.
## Общие правила
- Указывать типы для параметров компонентов, возвращаемых значений и параметров функций.
- Предпочитать `type` для описания сущностей и `interface` для расширяемых контрактов.
- Избегать `any` и `unknown` без необходимости.
- Н е использовать `ts-ignore` , кроме крайних случаев с явным комментарием причины.
## Типы для компонентов
- Типизировать параметры и публичный интерфейс компонента.
- Дефолтные значения описывать явно в коде.
**Хорошо**
```tsx
/**
* Параметры кнопки.
*/
interface IOwnProps extends HTMLAttributes< HTMLDivElement > {
/** Текст кнопки. */
label: string;
/** Обработчик клика по кнопке. */
onClick: () => void;
}
/**
* Кнопка с пользовательскими стилями.
*/
export const Button:FC< IOwnProps > = ({ className, label, onClick, ...htmlAttr }) => {
return (
< div { . . . htmlAttr } className = {cl(styles.root, className ) } >
button
< / div >
)
}
```
**Плохо**
```tsx
// Плохо: параметры не типизированы.
export const Button = (props) => (
< button type = "button" onClick = {props.onClick} >
{props.label}
< / button >
);
```
## Функции
- Для публичных функций указывать возвращаемый тип.
- Н е полагаться на неявный вывод для важных API.
**Хорошо**
```ts
export const formatPrice = (value: number): string => {
return `${value} ₽` ;
};
```
**Плохо**
```ts
// Плохо: нет явного возвращаемого типа.
export const formatPrice = (value: number) => {
return `${value} ₽` ;
};
```
## Работа с any/unknown
- `any` использовать только для временных заглушек.
- `unknown` сужать через проверки перед использованием.
**Хорошо**
```ts
const parse = (value: unknown): string => {
if (typeof value === 'string') {
return value;
}
return '';
};
```
**Плохо**
```ts
// Плохо: any отключает проверку типов.
const parse = (value: any) => value;
```
< a name = "7-project-structuremd" > < / a >
# Структура проекта
Раздел описывает базовую структуру проекта и принципы организации модулей на уровне папок и файлов.
## Базовая структура проекта
**Хорошо**
```text
src/
├── app/ # Инициализация приложения, роутинг, провайдеры
│ ├── config/ # Конфигурации и константы уровня приложения
│ ├── providers/ # Провайдеры и обёртки приложения
│ ├── routing/ # Конфигурация маршрутов
│ └── index.ts # Публичный API слоя
├── screens/ # Экраны приложения
│ └── Profile/ # Экран профиля
│ └── ... # ui/model/index.ts
├── layouts/ # Общие шаблоны и каркасы страниц
│ └── MainLayout/ # Основной layout
│ └── ... # ui/index.ts
├── widgets/ # Крупные блоки интерфейса
│ └── Header/ # Виджет шапки
│ └── ... # ui/index.ts
├── features/ # Пользовательские сценарии
│ └── auth-by-email/ # Авторизация по email
│ └── ... # ui/model/api/index.ts
├── entities/ # Бизнес-сущности
│ └── user/ # Сущность пользователя
│ └── ... # ui/model/api/lib/index.ts
└── shared/ # Общие ресурсы проекта
├── ui/ # Базовые UI-компоненты
├── lib/ # Утилиты и хелперы
├── services/ # Общие сервисы и клиенты
├── config/ # Общие конфигурации
├── styles/ # Глобальные стили и токены
└── assets/ # Ресурсы
├── images/ # Изображения
├── icons/ # Иконки
├── fonts/ # Шрифты
└── video/ # Видео
```
**Плохо**
```text
// Плохо: слои смешаны, нет понятных границ и публичного API.
src/
├── components/
├── api/
├── styles/
└── user.ts
```
## Правила организации
- Каждый слой и модуль хранится в собственной папке.
- Внутренние реализации разделяются на `ui` , `model` , `lib` , `api` .
- Публичный API модуля объявляется в `index.ts` .
- Внутренние файлы не импортируются напрямую извне.
- Н е смешивать ответственность разных слоёв в одном модуле.
< a name = "8-componentsmd" > < / a >
2026-01-30 13:21:04 +03:00
# Компоненты
Раздел описывает правила создания UI‑ ко мпо не нто в. Эти правила обязательны для всех слоёв FSD: `app` , `screens` , `layouts` , `widgets` , `features` , `entities` , `shared` .
## Базовая структура компонента
Минимальный набор файлов: компонент, стили, типы и публичный экспорт.
```text
container/
├── styles/
│ └── container.module.scss
├── types/
│ └── container.interface.ts
├── container.ui.tsx
└── index.ts
```
## Пример базового компонента
`styles/container.module.scss`
```scss
.root {}
```
В CSS Modules использование имени класса ** .root** — это общепринятое соглашение (best practice)
`types/container.interface.ts`
```ts
import type { HTMLAttributes } from 'react'
/**
* Параметры контейнера.
*/
export interface ContainerProps extends HTMLAttributes< HTMLDivElement > {}
```
Интерфес параметров компонента всегда наследует свойства своего тега: div, button, итд..
`container.ui.tsx`
```tsx
import type { FC } from 'react'
import { cl } from 'clsx'
import type { ContainerProps } from './types/container.interface'
import styles from './styles/container.module.scss'
/**
* Контейнер с адаптивной максимальной шириной.
*
* Используется для:
* - ограничения ширины контента
* - центрирования содержимого
* - построения адаптивной сетки страницы
*/
export const Container: FC< ContainerProps > = ({ className, ...htmlAttr }) => {
return (
< div { . . . htmlAttr } className = {cl(styles.root, className ) } >
Container...
< / div >
)
}
```
- Компонент объявляется через `const` и экспортируется именованно.
- Пропсы деструктурируются в сигнатуре; если их больше двух — деструктуризацию переносим в тело компонента.
- Из пропсов отдельно извлекаются `className` и `...htmlAttr` , чтобы корректно объединять классы и прокидывать остальные атрибуты.
- `cl` — короткое имя функции для конкатенации CSS‑ кла с с о в.
- `FC<>` используется для декларации `children` .
`index.ts`
```ts
export { Container } from './container.ui'
```
## Вложенные (дочерние) компоненты
Если для реализации функционала нужны компоненты, которые используются только внутри текущего компонента, создавайте их как вложенные в папке `ui/` . Такие компоненты не экспортируются наружу и используются только локально.
Вложенные компоненты подчиняются тем же правилам по структуре, именованию и стилю (включая папку `styles/` для их стилей).
2026-01-30 02:02:32 +03:00
< a name = "9-stylesmd" > < / a >
< a name = "10-images-spritesmd" > < / a >
< a name = "11-videomd" > < / a >
< a name = "12-apimd" > < / a >
< a name = "13-storesmd" > < / a >
< a name = "14-hooksmd" > < / a >
< a name = "15-fontsmd" > < / a >
< a name = "16-localizationmd" > < / a >