2026-03-29 11:43:23 +03:00
<!-- /index -->
2026-03-28 21:15:15 +03:00
# NextJS Style Guide
Правила и стандарты разработки на NextJS и TypeScript: архитектура, типизация, стили, компоненты, API и инфраструктурные разделы.
## Для ассистентов
2026-03-29 11:43:23 +03:00
Полная документация в одном MD файле: https://gromlab.ru/docs/nextjs-style-guide/raw/branch/main/generated/ru/RULES.md
2026-03-28 21:15:15 +03:00
## Структура документации
### Workflow
2026-03-29 11:43:23 +03:00
**Что делать и в каком порядке** — пошаговые инструкции.
2026-03-28 21:15:15 +03:00
| Раздел | Отвечает на вопрос |
|--------|-------------------|
2026-03-29 11:43:23 +03:00
| Начало работы | Что нужно знать перед началом разработки? |
| Создание проекта | Как начать новый проект? |
| Генерация кода | Какие модули должны генерироваться из шаблонов? |
| Добавление страницы | Как добавить новую страницу в проект? |
| Добавление UI-модуля | Как создать компонент, фичу, виджет, сущность или layout? |
| Стилизация | Как стилизовать компоненты в проекте? |
| Получение данных | Как получать данные с сервера? |
| Управление состоянием | Как работать с состоянием? |
| Локализация | Как добавлять переводы и подключать локализацию? |
2026-03-28 21:15:15 +03:00
### Базовые правила
**Каким должен быть код** — стандарты, не привязанные к конкретной технологии.
| Раздел | Отвечает на вопрос |
|--------|-------------------|
| Технологии и библиотеки | Какой стек используем? |
| Архитектура | Как устроены слои FSD, зависимости, публичный API? |
| Стиль кода | Как оформлять код: отступы, кавычки, импорты, early return? |
| Именование | Как называть файлы, переменные, компоненты, хуки? |
| Документирование | Как писать JSDoc: что документировать, а что нет? |
| Типизация | Как типизировать: type vs interface, any/unknown, FC? |
### Прикладные разделы
2026-03-29 11:43:23 +03:00
**Как это настроить и использовать** — конфигурация, структура и примеры кода для конкретных областей.
2026-03-28 21:15:15 +03:00
| Раздел | Отвечает на вопрос |
|--------|-------------------|
2026-03-29 11:43:23 +03:00
| Настройка VS Code | Как настроить редактор для проекта? |
2026-03-28 21:15:15 +03:00
| Структура проекта | Как организованы папки и файлы по FSD? |
| Компоненты | Как устроен компонент: файлы, пропсы, clsx, FC? |
2026-03-29 11:43:23 +03:00
| Page-level компоненты | Как описывать layout, page, loading, error, not-found? |
| Шаблоны и генерация кода | Как работают шаблоны, синтаксис и инструменты генерации? |
2026-03-28 21:15:15 +03:00
| Стили | Как писать CSS: PostCSS Modules, вложенность, медиа, токены? |
| Изображения | _(не заполнен)_ |
| SVG-спрайты | _(не заполнен)_ |
| Видео | _(не заполнен)_ |
| API | _(не заполнен)_ |
| Stores | _(не заполнен)_ |
| Хуки | _(не заполнен)_ |
| Шрифты | _(не заполнен)_ |
| Локализация | _(не заполнен)_ |
2026-03-29 14:04:25 +03:00
<!-- /workflow -->
## Workflow
2026-03-28 21:15:15 +03:00
2026-03-29 14:04:25 +03:00
Порядок действий при разработке — от создания проекта до реализации фич.
2026-03-28 21:15:15 +03:00
2026-03-29 14:04:25 +03:00
### Создание проекта
2026-03-28 21:15:15 +03:00
2026-03-29 14:04:25 +03:00
Инициализация нового проекта из готового шаблона.
2026-03-28 21:15:15 +03:00
2026-03-29 14:04:25 +03:00
1. Создать проект из шаблона:
```bash
npx tiged git@gromlab .ru:templates/nextjs.git my-app
cd my-app
npm install
```
2. Проект готов к разработке — стек, структура FSD, конфигурация
редактора и шаблоны генерации уже настроены.
2026-03-28 21:15:15 +03:00
2026-03-29 14:04:25 +03:00
### Генерация кода
2026-03-28 21:15:15 +03:00
2026-03-29 14:04:25 +03:00
Создание модулей из шаблонов `.templates/` вместо ручного создания файлов.
2026-03-28 21:15:15 +03:00
2026-03-29 14:04:25 +03:00
1. Определить тип модуля и соответствующий шаблон:
2026-03-28 21:15:15 +03:00
2026-03-29 14:04:25 +03:00
| Модуль | Слой | Шаблон |
|------------|--------------|-------------|
| Компонент | `shared/ui/` | `component` |
| Фича | `features/` | `feature` |
| Виджет | `widgets/` | `widget` |
| Сущность | `entities/` | `entity` |
| Layout | `layouts/` | `layout` |
| Экран | `screens/` | `screen` |
| Стор | `model/` | `store` |
2026-03-29 11:43:23 +03:00
2026-03-29 14:04:25 +03:00
2. Сгенерировать модуль из шаблона.
3. Если подходящего шаблона нет — сначала создать шаблон, затем использовать.
2026-03-29 11:43:23 +03:00
2026-03-29 14:04:25 +03:00
Ручное создание файловой структуры модулей запрещено.
2026-03-29 11:43:23 +03:00
2026-03-29 14:04:25 +03:00
### Добавление страницы
2026-03-28 21:15:15 +03:00
2026-03-29 14:04:25 +03:00
Создание нового маршрута: экран + точка входа для роутинга.
2026-03-28 21:15:15 +03:00
2026-03-29 14:04:25 +03:00
1. Сгенерировать экран из шаблона `screen` в `src/screens/` .
2026-03-29 11:43:23 +03:00
2. Заполнить экран логикой и стилями.
2026-03-29 14:04:25 +03:00
3. Создать `page.tsx` в нужном маршруте `src/app/` .
2026-03-28 21:15:15 +03:00
2026-03-29 14:04:25 +03:00
`page.tsx` — тонкая обёртка: только `metadata` и рендер экрана.
Логика, стили и хуки размещаются в экране, не в `page.tsx` .
2026-03-28 21:15:15 +03:00
2026-03-29 14:04:25 +03:00
### Добавление UI-модуля
2026-03-28 21:15:15 +03:00
2026-03-29 14:04:25 +03:00
Создание компонента, фичи, виджета, сущности или layout.
2026-03-28 21:15:15 +03:00
2026-03-29 14:04:25 +03:00
1. Сгенерировать модуль из соответствующего шаблона в целевой слой.
2026-03-29 11:43:23 +03:00
2. Заполнить модуль логикой и стилями.
2026-03-29 14:04:25 +03:00
3. Дочерние компоненты — генерировать из шаблона `component` в папку `ui/`
внутри родителя.
2026-03-28 21:15:15 +03:00
2026-03-29 14:04:25 +03:00
Дочерние компоненты не экспортируются через `index.ts` родителя.
2026-03-29 11:43:23 +03:00
2026-03-29 14:04:25 +03:00
### Стилизация
2026-01-30 02:02:32 +03:00
2026-03-29 14:04:25 +03:00
Выбор инструмента стилизации по приоритету.
2026-03-29 11:43:23 +03:00
2026-03-29 14:04:25 +03:00
1. Использовать Mantine-компоненты и их пропсы.
2. Если Mantine не покрывает — использовать CSS-токены
(`--color-*` , `--space-*` , `--radius-*` ).
3. Если нужна кастомная стилизация — PostCSS Modules.
2026-03-29 11:43:23 +03:00
2026-03-29 14:04:25 +03:00
Инлайн-стили (`style` ), магические значения и глобальные стили
вне `app/styles/` запрещены.
2026-03-29 11:43:23 +03:00
2026-03-29 14:04:25 +03:00
### Получение данных
2026-03-29 11:43:23 +03:00
2026-03-29 14:04:25 +03:00
*Раздел в разработке* — SWR, генерация API-клиентов, сокеты.
2026-03-29 11:43:23 +03:00
2026-03-29 14:04:25 +03:00
### Управление состоянием
2026-03-29 11:43:23 +03:00
2026-03-29 14:04:25 +03:00
*Раздел в разработке* — когда создавать стор, что хранить локально и глобально.
2026-03-29 11:43:23 +03:00
2026-03-29 14:04:25 +03:00
### Локализация
2026-03-29 11:43:23 +03:00
2026-03-29 14:04:25 +03:00
*Раздел в разработке* — переводы и i18next.
2026-03-29 11:43:23 +03:00
<!-- /basics/tech - stack -->
## Технологии и библиотеки
2026-01-30 02:02:32 +03:00
2026-03-31 15:17:47 +03:00
Этот раздел описывает базовый стек технологий и библиотек, принятый в проекте.
2026-01-30 02:02:32 +03:00
2026-03-29 11:43:23 +03:00
### Что используем
2026-01-30 02:02:32 +03:00
2026-03-29 11:43:23 +03:00
#### Стек
2026-03-31 15:17:47 +03:00
- `React` / `TypeScript` — основной стек для UI и приложения.
- `Next.js` — для продуктовых сайтов.
2026-03-18 09:22:03 +03:00
2026-03-29 11:43:23 +03:00
#### Архитектура
2026-03-31 15:17:47 +03:00
- `FSD (Feature-Sliced Design)` — структура проекта и границы модулей. Используется кастомизированная версия — подробнее в разделе [Архитектура ](/basics/architecture ).
2026-03-18 09:22:03 +03:00
2026-03-29 11:43:23 +03:00
#### UI компоненты
2026-03-31 15:17:47 +03:00
- `Mantine UI` — базовые UI-компоненты.
2026-03-18 09:22:03 +03:00
2026-03-31 15:17:47 +03:00
#### Работа с данными (API)
- `@gromlab/api-codegen` — генерация API‑ клие нто в и типов.
- `SWR` — получение, кеширование, ревалидация, дедубликация.
- `SWR (useSWRSubscription)` — сокеты, реалтайм подписки.
2026-03-18 09:22:03 +03:00
2026-03-29 11:43:23 +03:00
#### Store
2026-03-31 15:17:47 +03:00
- `Zustand` — глобальное состояние.
2026-03-18 09:22:03 +03:00
2026-03-29 11:43:23 +03:00
#### Локализация
2026-03-31 15:17:47 +03:00
- `i18next (i18n)` — локализация всех пользовательских текстов.
2026-03-18 09:22:03 +03:00
2026-03-29 11:43:23 +03:00
#### Тестирование
2026-03-31 15:17:47 +03:00
- `Vitest` — тестирование.
2026-03-18 09:22:03 +03:00
2026-03-29 11:43:23 +03:00
#### Стили
2026-03-31 15:17:47 +03:00
- `PostCSS Modules` — изоляция стилей.
- `Mobile First` — подход к адаптивной верстке.
- `clsx` — конкатенация CSS‑ кла с с о в.
2026-03-18 09:22:03 +03:00
2026-03-29 11:43:23 +03:00
#### Генерация
2026-03-31 15:17:47 +03:00
- `@gromlab/create` — шаблонизатор для создания слоёв и других файлов из шаблонов.
<!-- /basics/naming -->
## Именование
Этот раздел описывает соглашения о б именовании в проекте. Единые правила делают код предсказуемым и упрощают навигацию по проекту.
### Базовые правила
| Что | Рекомендуется |
| ---------------- | ---------------------- |
| Папки | `kebab-case` |
| Файлы | `kebab-case` |
| Переменные | `camelCase` |
| Константы | `SCREAMING_SNAKE_CASE` |
| Классы | `PascalCase` |
| React-компоненты | `PascalCase` |
| Хуки | `useSomething` |
| CSS классы | `camelCase` |
2026-04-01 10:35:07 +03:00
| Ключи enum | `SCREAMING_SNAKE_CASE` |
2026-03-31 15:17:47 +03:00
### Именование файлов
Суффикс обозначает роль или тип файла. Пишется в единственном числе.
Формат: `name.<suffix>.ts` .
**Хуки**
- `use-name.hook.ts` — файл хука, функция именуется `useName`
**Логика**
- `.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` — тесты
- `.mock.ts` — моки
**Хорошо**
```text
features/
└── auth-by-email/
├── ui/
│ └── login-form.tsx
├── hooks/
│ └── use-auth.hook.ts
├── stores/
│ └── auth.store.ts
├── types/
│ └── auth.interface.ts
├── auth-by-email.feature.tsx
└── index.ts
```
**Плохо**
```text
features/
└── authByEmail/
├── LoginForm.tsx
├── useAuth.ts
├── authStore.ts
└── index.ts
```
### Булевы значения
- Использовать префиксы `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 > ;
```
2026-01-30 02:02:32 +03:00
2026-03-29 11:43:23 +03:00
<!-- /basics/architecture -->
## Архитектура
2026-01-30 02:02:32 +03:00
2026-03-31 15:17:47 +03:00
Этот раздел описывает архитектуру проекта: из каких слоёв состоит приложение,
как организован код внутри слоёв и какие правила управляют зависимостями.
### Что важно знать
2026-01-30 02:02:32 +03:00
2026-03-31 15:17:47 +03:00
Проект использует [FSD (Feature-Sliced Design) ](https://feature-sliced.design/docs/get-started/overview )
как базовую архитектурную методологию. Если вы не знакомы с FSD — начните с официальной документации.
2026-01-30 02:02:32 +03:00
2026-03-31 15:17:47 +03:00
Данная архитектура является **надстройкой над FSD** , а не заменой. В с е правила FSD действуют
по умолчанию — если правило явно не переопределено в этом документе, применяется стандарт FSD.
Единственное отклонение: вместо слайсов используются **компоненты** .
2026-01-30 02:02:32 +03:00
2026-03-31 15:17:47 +03:00
### Слои
2026-01-30 02:02:32 +03:00
2026-03-31 15:17:47 +03:00
| Слой | Назначение |
|------|-----------|
| `app` | Инициализация: провайдеры, стили, роутинг Next.js |
| `screens` | Сборка страницы из виджетов и фич |
| `layouts` | Каркасы и шаблоны страниц |
| `widgets` | Крупные блоки интерфейса |
| `features` | Пользовательские сценарии и действия |
| `entities` | Бизнес-сущности |
| `shared` | Утилиты, UI-кит, инфраструктура |
2026-01-30 02:02:32 +03:00
2026-03-31 15:17:47 +03:00
Слой `pages` не используется — конфликтует с Next.js. Вместо него: `screens` и `layouts` .
2026-03-23 21:48:54 +03:00
2026-03-31 15:17:47 +03:00
Зависимости идут строго сверху вниз: `app → screens → layouts → widgets → features → entities → shared` .
2026-03-23 21:48:54 +03:00
2026-03-31 15:17:47 +03:00
### Компоненты
2026-01-30 02:02:32 +03:00
2026-03-31 15:17:47 +03:00
Компонент — стандартная UI-единица, такая же как в любом React-проекте. Содержит корневой `.tsx` ,
публичный API (`index.ts` ) и сегменты.
2026-01-30 02:02:32 +03:00
2026-03-31 15:17:47 +03:00
Компоненты располагаются в:
- `shared/ui/` — переиспользуемые компоненты без бизнес-контекста
- `ui/` внутри master component'а — дочерние компоненты *(подробнее в разделе [Master component](#master-component))*
2026-01-30 02:02:32 +03:00
2026-03-31 15:17:47 +03:00
### Сегменты
2026-01-30 02:02:32 +03:00
2026-03-31 15:17:47 +03:00
Сегмент — папка внутри компонента, группирующая код по техническому назначению. Н а б о р не фиксирован.
2026-01-30 02:02:32 +03:00
2026-03-31 15:17:47 +03:00
| Сегмент | Назначение |
|---------|-----------|
| `styles/` | Стили |
| `types/` | Интерфейсы, типы, enums, DTO |
| `ui/` | Компоненты, провайдеры и любые другие элементы интерфейса |
| `stores/` | Сторы состояния |
| `hooks/` | React-хуки |
| `services/` | Внешние источники данных |
| `lib/` | Утилиты |
| `helpers/` | Вспомогательные функции |
| `config/` | Константы, конфигурация |
2026-01-30 02:02:32 +03:00
2026-03-31 15:17:47 +03:00
### Master component
2026-01-30 02:02:32 +03:00
2026-03-31 15:17:47 +03:00
Master component — это обычный компонент, на который наложен ряд дополнительных правил.
Эти правила определяют е г о место в архитектуре и границы зависимостей.
- Может располагаться только в слоях: `screens` , `layouts` , `widgets` , `features` , `entities`
- Импортирует master component'ы только из слоёв ниже по иерархии
- Корневой `.tsx` именуется с суффиксом слоя: `header.widget.tsx` , `auth.feature.tsx`
- Корневой `.tsx` необязателен — `index.ts` может экспортировать несколько сущностей напрямую
- Дочерние компоненты в `ui/` доступны снаружи только через `index.ts`
- Компоненты внутри одного `ui/` могут импортировать друг друга
2026-01-30 02:02:32 +03:00
2026-03-29 11:43:23 +03:00
<!-- /basics/code - style -->
## Стиль кода
2026-01-30 02:02:32 +03:00
Раздел описывает единые правила оформления кода: отступы, переносы, кавычки, порядок импортов и базовую читаемость.
2026-03-29 11:43:23 +03:00
### Отступы
2026-01-30 02:02:32 +03:00
- 2 пробела (не табы).
2026-03-29 11:43:23 +03:00
### Длина строк
2026-01-30 02:02:32 +03:00
- Ориентироваться на 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);
```
2026-03-29 11:43:23 +03:00
### Кавычки
2026-01-30 02:02:32 +03:00
- В 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 = 'Введите имя' / >
```
2026-03-29 11:43:23 +03:00
### Точки с запятой и запятые
2026-01-30 02:02:32 +03:00
- Допускаются упущения точки с запятой, если код остаётся читаемым и однозначным.
- В многострочных массивах, объектах и параметрах функции запятая в конце допускается, но не обязательна.
2026-03-29 11:43:23 +03:00
### Импорты
2026-01-30 02:02:32 +03:00
- В именованных импортах использовать пробелы внутри фигурных скобок.
- Типы импортировать через `import type` .
2026-03-23 21:48:54 +03:00
- `default` экспорт избегать, использовать именованные. `default` импорт допустим (например, стили CSS Modules, сторонние библиотеки).
2026-01-30 02:02:32 +03:00
- Избегать импорта всего модуля через `*` .
**Хорошо**
```ts
import { MyComponent } from 'MyComponent';
import type { User } from '../model/types';
2026-03-23 21:48:54 +03:00
import styles from './styles/button.module.css';
2026-01-30 02:02:32 +03:00
```
**Плохо**
```ts
2026-03-23 21:48:54 +03:00
// Плохо: отсутствие пробелов в именованном импорте.
2026-01-30 02:02:32 +03:00
import type {User} from '../model/types';
2026-03-23 21:48:54 +03:00
// Плохо: default экспорт.
export default MyComponent;
2026-01-30 02:02:32 +03:00
```
2026-03-29 11:43:23 +03:00
### Ранние возвраты (early return)
2026-01-30 02:02:32 +03:00
- Использовать ранние возвраты для упрощения чтения.
- Избегать `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 'Гость';
}
};
```
2026-03-29 11:43:23 +03:00
### Форматирование объектов и массивов
2026-01-30 02:02:32 +03:00
- В многострочных объектах каждое свойство на новой строке.
- В многострочных массивах каждый элемент на новой строке.
- Объекты и массивы можно писать в одну строку, если длина строки не превышает 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 } };
```
2026-03-29 11:43:23 +03:00
<!-- /basics/documentation -->
## Документирование
2026-01-30 02:02:32 +03:00
2026-04-01 10:35:07 +03:00
Этот раздел описывает правила документирования кода: когда и как писать
комментарии к компонентам, функциям, типам и интерфейсам.
2026-01-30 02:02:32 +03:00
2026-04-01 10:35:07 +03:00
### Общие правила
2026-01-30 02:02:32 +03:00
2026-04-01 10:35:07 +03:00
- Документировать публичные функции, компоненты, типы, интерфейсы и enum.
- Н е документировать очевидное — если название говорит само за себя, комментарий не нужен.
- Н е документировать параметры, возвращаемые значения и типы пропсов — они видны из сигнатуры.
- Описание через пользу и назначение, а не через внутреннюю реализацию.
- Описание завершается точкой.
2026-01-30 02:02:32 +03:00
2026-04-01 10:35:07 +03:00
### Функции
2026-01-30 02:02:32 +03:00
2026-04-01 10:35:07 +03:00
Для документирования функций используется шаблон. Описание механики опционально —
добавляется когда логика нетривиальна.
**Шаблон**
2026-01-30 02:02:32 +03:00
```ts
/**
2026-04-01 10:35:07 +03:00
* < Что делает функция в 1 строке > .
*
* < Опционально: описание сложной механики или важных нюансов > .
2026-01-30 02:02:32 +03:00
*/
2026-04-01 10:35:07 +03:00
```
2026-01-30 02:02:32 +03:00
2026-04-01 10:35:07 +03:00
**Хорошо**
```ts
2026-01-30 02:02:32 +03:00
/**
2026-04-01 10:35:07 +03:00
* Форматирует цену с символом валюты.
2026-01-30 02:02:32 +03:00
*/
2026-04-01 10:35:07 +03:00
export const formatPrice = (value: number): string => { ... }
2026-01-30 02:02:32 +03:00
/**
2026-04-01 10:35:07 +03:00
* Рекурсивно собирает дерево категорий из плоского списка.
*
* Группирует элементы по parentId, начиная с корневых (parentId = null).
* Категории без родителя попадают в корень дерева.
2026-01-30 02:02:32 +03:00
*/
2026-04-01 10:35:07 +03:00
export const buildCategoryTree = (categories: Category[]): CategoryTree[] => { ... }
2026-01-30 02:02:32 +03:00
```
**Плохо**
```ts
2026-04-01 10:35:07 +03:00
// Плохо: дублирует сигнатуру.
2026-01-30 02:02:32 +03:00
/**
2026-04-01 10:35:07 +03:00
* @param value - число
* @returns строка с ценой
2026-01-30 02:02:32 +03:00
*/
2026-04-01 10:35:07 +03:00
```
### Компоненты
2026-01-30 02:02:32 +03:00
2026-04-01 10:35:07 +03:00
Компонент описывает своё **назначение** и **сценарии применения** — это помогает понять, когда и где е г о использовать, без необходимости читать реализацию.
**Шаблон**
```ts
2026-01-30 02:02:32 +03:00
/**
2026-04-01 10:35:07 +03:00
* < Назначение компонента в 1 строке > .
*
* Используется для:
* - < сценарий 1 >
* - < сценарий 2 >
* - < сценарий 3 >
2026-01-30 02:02:32 +03:00
*/
```
2026-04-01 10:35:07 +03:00
**Хорошо**
```tsx
/**
* Контейнер с адаптивной максимальной шириной.
*
* Используется для:
* - обёртки контента страниц с ограничением ширины
* - центрирования блоков в лейауте
*/
export const Container: FC< ContainerProps > = (props) => { ... }
```
2026-01-30 02:02:32 +03:00
2026-04-01 10:35:07 +03:00
**Плохо**
```tsx
// Плохо: описывает реализацию, а не назначение.
/**
* Рендерит div с className и htmlAttr.
*/
2026-01-30 02:02:32 +03:00
2026-04-01 10:35:07 +03:00
// Плохо: нет описания вообще.
export const Container: FC< ContainerProps > = (props) => { ... }
```
2026-01-30 02:02:32 +03:00
2026-04-01 10:35:07 +03:00
### Типы, интерфейсы, enum
2026-01-30 02:02:32 +03:00
2026-04-01 10:35:07 +03:00
Документируются назначение сущности и каждое её поле.
2026-01-30 02:02:32 +03:00
**Хорошо**
2026-04-01 10:35:07 +03:00
```ts
2026-01-30 02:02:32 +03:00
/**
2026-04-01 10:35:07 +03:00
* Фильтры списка задач.
2026-01-30 02:02:32 +03:00
*/
2026-04-01 10:35:07 +03:00
export enum TodoFilter {
/** В с е задачи. */
ALL = 'all',
/** Только активные. */
ACTIVE = 'active',
/** Только завершённые. */
COMPLETED = 'completed',
2026-01-30 02:02:32 +03:00
}
/**
2026-04-01 10:35:07 +03:00
* Задача пользователя.
2026-01-30 02:02:32 +03:00
*/
2026-04-01 10:35:07 +03:00
export interface TodoItem {
/** Уникальный идентификатор задачи. */
id: string;
/** Текст задачи. */
text: string;
/** Статус выполнения. */
completed: boolean;
2026-01-30 02:02:32 +03:00
}
```
**Плохо**
2026-04-01 10:35:07 +03:00
```ts
// Плохо: описывает очевидное.
export interface TodoItem {
/** id — это id */
id: string;
}
2026-01-30 02:02:32 +03:00
```
2026-04-01 10:35:07 +03:00
<!-- /basics/typing -->
## Типизация
Этот раздел описывает правила типизации: как типизировать компоненты, функции и работу с `any` /`unknown` .
### Общие правила
- Указывать типы для параметров компонентов, возвращаемых значений и параметров функций.
- Предпочитать `type` для описания сущностей и `interface` для расширяемых контрактов.
- Избегать `any` и `unknown` без необходимости.
- Н е использовать `ts-ignore` , кроме крайних случаев с явным комментарием причины.
2026-03-29 11:43:23 +03:00
### Функции
2026-01-30 02:02:32 +03:00
- Для публичных функций указывать возвращаемый тип.
- Н е полагаться на неявный вывод для важных API.
**Хорошо**
```ts
export const formatPrice = (value: number): string => {
return `${value} ₽` ;
};
```
**Плохо**
```ts
// Плохо: нет явного возвращаемого типа.
export const formatPrice = (value: number) => {
return `${value} ₽` ;
};
```
2026-03-29 11:43:23 +03:00
### Работа с any/unknown
2026-01-30 02:02:32 +03:00
- `any` использовать только для временных заглушек.
- `unknown` сужать через проверки перед использованием.
**Хорошо**
```ts
const parse = (value: unknown): string => {
if (typeof value === 'string') {
return value;
}
return '';
};
```
**Плохо**
```ts
// Плохо: any отключает проверку типов.
const parse = (value: any) => value;
```
2026-04-01 10:35:07 +03:00
<!-- /applied/project - structure -->
## Структура проекта
2026-03-29 11:43:23 +03:00
2026-04-01 10:35:07 +03:00
Раздел описывает расположение файлов и папок в проекте Next.js (App Router).
2026-01-30 02:02:32 +03:00
2026-04-01 10:35:07 +03:00
### Корень репозитория
2026-01-30 02:02:32 +03:00
2026-03-29 11:43:23 +03:00
```text
2026-04-01 10:35:07 +03:00
project-root/
├── .templates/ # Шаблоны для генерации модулей
├── .vscode/ # Настройки и рекомендуемые расширения VS Code
├── public/ # Статика, доступная по прямому URL
├── src/ # Исходный код приложения
├── .env.example # Переменные окружения проекта (шаблон)
├── .env # Переменные окружения проекта (не коммитить)
├── .gitignore
├── AGENTS.md # Инструкции для AI-агентов
├── biome.json # Линтер и форматтер (вместо ESLint + Prettier)
├── next.config.ts # Конфигурация Next.js
├── package.json # Зависимости и скрипты
├── postcss.config.mjs # Конфигурация PostCSS
└── tsconfig.json # Конфигурация TypeScript
```
### Папка `public/`
Хранит статические файлы, которые отдаются по прямому URL без обработки сборщиком:
2026-01-30 02:02:32 +03:00
2026-04-01 10:35:07 +03:00
```text
public/
└── og-image.png
2026-03-29 11:43:23 +03:00
```
2026-04-01 10:35:07 +03:00
Компоненты, стили и другой исходный код здесь не размещаются.
2026-03-29 11:43:23 +03:00
2026-04-01 10:35:07 +03:00
### Папка `src/`
2026-03-29 11:43:23 +03:00
2026-04-01 10:35:07 +03:00
```text
src/
├── app/ # Роутинг Next.js, провайдеры, глобальные стили
├── screens/ # Собраные страницы (UI)
├── layouts/ # Шаблоны
├── widgets/ # Крупные самостоятельные блоки интерфейса
├── features/ # Пользовательские сценарии
├── entities/ # Бизнес-сущности
└── shared/ # Переиспользуемый код (UI, утилиты, типы и др.)
2026-03-29 11:43:23 +03:00
```
2026-04-01 10:35:07 +03:00
Принципы организации слоёв описаны в разделе [Архитектура ](../basics/architecture ).
2026-03-29 11:43:23 +03:00
2026-04-01 10:35:07 +03:00
#### Папка `app/`
2026-03-29 11:43:23 +03:00
2026-04-01 10:35:07 +03:00
Совмещает два слоя: инициализацию приложения по FSD (провайдеры, глобальные стили) и файловый роутинг Next.js (`layout.tsx` , `page.tsx` , route-сегменты).
2026-03-29 11:43:23 +03:00
2026-04-01 10:35:07 +03:00
```text
src/app/
├── providers/ # Провайдеры приложения
├── styles/ # Глобальные стили
├── layout.tsx # Корневой layout
└── page.tsx # Главная страница
```
2026-03-29 11:43:23 +03:00
2026-04-01 10:35:07 +03:00
### Папка `.templates/`
2026-03-29 11:43:23 +03:00
2026-04-01 10:35:07 +03:00
Содержит шаблоны для генерации кода. Каждый подкаталог — шаблон отдельного типа модуля:
2026-03-29 11:43:23 +03:00
2026-04-01 10:35:07 +03:00
```text
.templates/
├── component/ # Шаблон компонента
├── screen/ # Шаблон экрана
├── layout/ # Шаблон layout
├── widget/ # Шаблон виджета
├── feature/ # Шаблон фичи
├── entity/ # Шаблон сущности
└── store/ # Шаблон стора
```
2026-03-29 11:43:23 +03:00
2026-04-01 10:35:07 +03:00
Подробнее о генерации описано в разделе [Шаблоны и генерация кода ](./templates-generation ).
2026-03-29 11:43:23 +03:00
2026-04-01 10:35:07 +03:00
### Конфигурационные файлы
2026-03-23 21:48:54 +03:00
2026-04-01 10:35:07 +03:00
| Файл | Назначение |
|---|---|
| `next.config.ts` | Настройки Next.js: редиректы, переменные окружения, webpack |
| `tsconfig.json` | Настройки TypeScript: пути, строгость, таргет |
| `biome.json` | Правила линтера и форматтера Biome |
| `postcss.config.mjs` | Подключение PostCSS-плагинов (CSS Modules, custom media) |
| `package.json` | Зависимости, версии, npm-скрипты |
| `AGENTS.md` | Инструкции для AI-агентов, работающих в проекте |
2026-03-23 21:48:54 +03:00
2026-04-01 10:35:07 +03:00
### Переменные окружения
2026-03-23 21:48:54 +03:00
2026-04-01 10:35:07 +03:00
- `.env` — переменные окружения проекта, запрещено коммитить
- `.env.example` — шаблон, коммитится в репозиторий
2026-03-23 21:48:54 +03:00
2026-04-01 10:35:07 +03:00
Переменные с префиксом `NEXT_PUBLIC_` доступны в клиентском коде. Остальные доступны только на сервере.
2026-01-30 02:02:32 +03:00
2026-04-01 10:35:07 +03:00
<!-- /applied/components -->
## Компоненты
2026-01-30 02:02:32 +03:00
2026-04-01 10:35:07 +03:00
Правила написания React-компонентов: файловая структура модуля, типизация пропсов, документирование и реализация. Раздел охватывает компоненты всех слоёв — от `shared/ui` до `screens` .
2026-01-30 02:02:32 +03:00
2026-04-01 10:35:07 +03:00
Архитектурные слои и их назначение описаны в разделе [Архитектура ](/basics/architecture ).
2026-01-30 02:02:32 +03:00
2026-04-01 10:35:07 +03:00
### Правила организации
2026-01-30 13:21:04 +03:00
2026-04-01 10:35:07 +03:00
1. Один компонент — один файл.
2. Компонент не содержит бизнес-логики — логика и сайд-эффекты выносятся в хуки или сторы.
3. Дочерние компоненты размещаются в сегменте `ui/` и подчиняются тем же правилам структуры.
4. Публичный API модуля — только `index.ts` . Прямые импорты внутренних файлов запрещены.
2026-01-30 13:21:04 +03:00
2026-03-29 11:43:23 +03:00
### Базовая структура компонента
2026-01-30 13:21:04 +03:00
Минимальный набор файлов: компонент, стили, типы и публичный экспорт.
```text
container/
├── styles/
2026-03-29 13:06:51 +03:00
│ └── container.module.css
2026-01-30 13:21:04 +03:00
├── types/
│ └── container.interface.ts
2026-03-29 11:43:23 +03:00
├── container.tsx
2026-01-30 13:21:04 +03:00
└── index.ts
```
2026-04-01 10:35:07 +03:00
### Именования
2026-01-30 13:21:04 +03:00
2026-04-01 10:35:07 +03:00
- Имя корневого css класса всегда `.root`
- Интерфейс именуется `{ComponentName}Props` .
### Типизация
- Компонент типизируется через `FC<Props>` .
- Интерфейс пропсов наследует HTML-атрибуты своего корневого элемента.
- `children` отдельно не объявляется — приходит из `HTMLAttributes` .
### Реализация
- Пропсы деструктурируются в теле компонента, не в параметрах.
- Порядок: пользовательские → системные (`children` , `className` ) → `...htmlAttr` .
- `className` объединяется с корневым классом через `cl()` : `cl(styles.root, className)` .
- `...htmlAttr` прокидывается на корневой элемент.
### Пример
`container/types/container.interface.ts`
2026-01-30 13:21:04 +03:00
```ts
import type { HTMLAttributes } from 'react'
/**
2026-04-01 10:35:07 +03:00
* Параметры компонента Container.
2026-01-30 13:21:04 +03:00
*/
export interface ContainerProps extends HTMLAttributes< HTMLDivElement > {}
```
2026-04-01 10:35:07 +03:00
`container/styles/container.module.css`
```css
.root {
max-width: var(--content-width);
margin: 0 auto;
padding: 0 var(--spacing-4);
}
```
`container/container.tsx`
2026-01-30 13:21:04 +03:00
```tsx
import type { FC } from 'react'
2026-03-23 21:48:54 +03:00
import cl from 'clsx'
2026-01-30 13:21:04 +03:00
import type { ContainerProps } from './types/container.interface'
2026-03-29 13:06:51 +03:00
import styles from './styles/container.module.css'
2026-01-30 13:21:04 +03:00
/**
* Контейнер с адаптивной максимальной шириной.
*
* Используется для:
2026-04-01 10:35:07 +03:00
* - обёртки контента страниц с ограничением ширины
* - центрирования блоков в лейауте
2026-01-30 13:21:04 +03:00
*/
2026-04-01 10:35:07 +03:00
export const Container: FC< ContainerProps > = (props) => {
const { children, className, ...htmlAttr } = props
2026-01-30 13:21:04 +03:00
return (
< div { . . . htmlAttr } className = {cl(styles.root, className ) } >
2026-04-01 10:35:07 +03:00
{children}
2026-01-30 13:21:04 +03:00
< / div >
)
}
```
2026-04-01 10:35:07 +03:00
`container/index.ts`
2026-01-30 13:21:04 +03:00
```ts
2026-03-29 11:43:23 +03:00
export { Container } from './container'
2026-01-30 13:21:04 +03:00
```
2026-03-29 11:43:23 +03:00
<!-- /applied/page - level -->
2026-03-29 18:55:12 +03:00
## Страницы (App Router)
2026-01-30 02:02:32 +03:00
2026-03-29 11:43:23 +03:00
Специальные файлы Next.js App Router, которые фреймворк использует по соглашению: `layout.tsx` , `page.tsx` , `loading.tsx` , `error.tsx` , `not-found.tsx` , `template.tsx` .
2026-03-18 09:22:03 +03:00
2026-03-29 11:43:23 +03:00
### Общие правила
2026-03-18 09:22:03 +03:00
2026-03-29 11:43:23 +03:00
- Экспорт через `export default function` — конвенция Next.js.
- Типизация через `PropsWithChildren` или явный интерфейс.
- Каждая страница (`page.tsx` ) должна содержать `metadata` с `title` и `description` .
- Минимум логики — page-level компоненты делегируют работу экранам, виджетам и фичам.
- Стили в page-level компонентах не используются — стилизация внутри вызываемых компонентов.
2026-03-28 21:15:15 +03:00
2026-03-29 11:43:23 +03:00
### layout.tsx
2026-03-28 21:15:15 +03:00
2026-03-29 11:43:23 +03:00
Корневой layout — точка подключения провайдеров, глобальных стилей и метаданных.
2026-03-18 09:22:03 +03:00
2026-03-29 11:43:23 +03:00
```tsx
import type { PropsWithChildren } from 'react'
import type { Metadata } from 'next'
2026-03-29 13:06:51 +03:00
import { Providers } from './providers'
import './styles/index.css'
2026-03-29 11:43:23 +03:00
export const metadata: Metadata = {
title: {
default: 'App',
template: '%s | App',
},
description: 'Описание приложения',
metadataBase: new URL('https://example.com'),
openGraph: {
type: 'website',
locale: 'ru_RU',
siteName: 'App',
images: [
{
url: '/og-image.png',
width: 1200,
height: 630,
alt: 'App',
},
],
},
twitter: {
card: 'summary_large_image',
},
}
2026-03-18 09:22:03 +03:00
2026-03-29 11:43:23 +03:00
export default function RootLayout({ children }: PropsWithChildren) {
return (
< html lang = "ru" suppressHydrationWarning >
< body >
2026-03-29 13:06:51 +03:00
< Providers >
2026-03-29 11:43:23 +03:00
{children}
2026-03-29 13:06:51 +03:00
< / Providers >
2026-03-29 11:43:23 +03:00
< / body >
< / html >
)
}
```
2026-03-18 09:22:03 +03:00
2026-03-29 11:43:23 +03:00
Вложенный layout — для секции с общей обёрткой (sidebar, header):
2026-03-18 09:22:03 +03:00
2026-03-29 11:43:23 +03:00
```tsx
import type { PropsWithChildren } from 'react'
import { DashboardLayout } from '@/shared/ui/dashboard -layout'
2026-03-18 09:22:03 +03:00
2026-03-29 11:43:23 +03:00
export default function Layout({ children }: PropsWithChildren) {
return (
< DashboardLayout >
{children}
< / DashboardLayout >
)
}
```
2026-03-18 09:22:03 +03:00
2026-03-29 11:43:23 +03:00
### page.tsx
2026-03-18 09:22:03 +03:00
2026-03-29 11:43:23 +03:00
Тонкий файл — только импорт и рендер экрана. Логика, стили и зависимости размещаются в экране, не в `page.tsx` .
2026-03-18 09:22:03 +03:00
2026-03-29 11:43:23 +03:00
```tsx
import type { Metadata } from 'next'
import { HomeScreen } from '@/screens/home '
export const metadata: Metadata = {
title: 'Главная',
description: 'Главная страница приложения',
}
export default function HomePage() {
return < HomeScreen / >
}
```
С параметрами маршрута:
```tsx
import type { Metadata } from 'next'
import { ProfileScreen } from '@/screens/profile '
export const metadata: Metadata = {
title: 'Профиль',
description: 'Страница профиля пользователя',
}
interface ProfilePageProps {
params: Promise< { id: string }>
}
export default async function ProfilePage({ params }: ProfilePageProps) {
const { id } = await params
return < ProfileScreen id = {id} / >
}
```
Каждая страница должна содержать `metadata` с `title` — он подставится в шаблон из корневого layout: `Профиль | App` .
### loading.tsx
2026-03-18 09:22:03 +03:00
2026-03-29 11:43:23 +03:00
Состояние загрузки. Показывается пока загружается контент страницы.
```tsx
export default function Loading() {
return < div > Загрузка...< / div >
}
2026-03-18 09:22:03 +03:00
```
2026-03-29 11:43:23 +03:00
### error.tsx
Обработка ошибок. Обязательно `'use client'` — error boundary работает только на клиенте. Разметку выносим в экран.
```tsx
'use client'
import type { FC } from 'react'
import { ErrorScreen } from '@/screens/error '
interface ErrorPageProps {
error: Error & { digest?: string }
reset: () => void
}
const ErrorPage: FC< ErrorPageProps > = ({ error, reset }) => {
return < ErrorScreen error = {error} reset = {reset} / >
}
export default ErrorPage
```
### not-found.tsx
Страница 404. Показывается когда маршрут не найден. Разметку выносим в экран.
```tsx
import type { Metadata } from 'next'
import { NotFoundScreen } from '@/screens/not -found'
export const metadata: Metadata = {
title: 'Страница не найдена',
description: 'Запрашиваемая страница не существует',
}
export default function NotFound() {
return < NotFoundScreen / >
}
```
### template.tsx
Аналог layout, но пересоздаётся при каждой навигации (не сохраняет состояние). Используется редко — для анимаций переходов между страницами.
```tsx
import type { PropsWithChildren } from 'react'
export default function Template({ children }: PropsWithChildren) {
return < div > {children}< / div >
}
```
<!-- /applied/templates - generation -->
<!-- @formatter:off -->
::: v-pre
## Шаблоны и генерация кода
Как работают шаблоны, как их создавать, синтаксис переменных и как генерировать код с помощью расширения VS Code и CLI.
### Структура шаблонов
В с е шаблоны лежат в `.templates/` в корне проекта. Каждая папка — отдельный шаблон.
2026-03-18 09:22:03 +03:00
```text
2026-03-29 11:43:23 +03:00
.templates/
2026-03-18 09:22:03 +03:00
├── component/ # шаблон компонента
2026-03-23 21:48:54 +03:00
│ └── {{name.kebabCase}}/
│ ├── styles/
│ │ └── {{name.kebabCase}}.module.css
│ ├── types/
│ │ └── {{name.kebabCase}}.interface.ts
2026-03-29 11:43:23 +03:00
│ ├── {{name.kebabCase}}.tsx
2026-03-23 21:48:54 +03:00
│ └── index.ts
2026-03-18 09:22:03 +03:00
└── store/ # шаблон Zustand стора
2026-03-23 21:48:54 +03:00
└── {{name.kebabCase}}/
├── {{name.kebabCase}}.store.ts
├── {{name.kebabCase}}.type.ts
└── index.ts
2026-03-18 09:22:03 +03:00
```
2026-03-29 11:43:23 +03:00
### Синтаксис шаблонов
2026-03-18 09:22:03 +03:00
2026-03-29 11:43:23 +03:00
Переменные работают в именах файлов/папок и внутри файлов. Базовая переменная — `name` .
2026-03-18 09:22:03 +03:00
```text
{{variable}}
```
2026-03-29 11:43:23 +03:00
Модификаторы меняют регистр и формат записи:
2026-03-18 09:22:03 +03:00
```text
2026-03-29 11:43:23 +03:00
{{name.pascalCase}} → MyButton
{{name.camelCase}} → myButton
{{name.kebabCase}} → my-button
{{name.snakeCase}} → my_button
{{name.screamingSnakeCase}} → MY_BUTTON
2026-03-18 09:22:03 +03:00
```
2026-03-29 11:43:23 +03:00
### Как создать новый шаблон
1. Создать папку в `.templates/` с именем шаблона (например `hook` ).
2. Внутри разместить файлы и папки, используя `{{name}}` и модификаторы в именах и содержимом.
3. Шаблон сразу доступен и в расширении VS Code, и в CLI.
Пример — создание шаблона для хука:
2026-03-18 09:22:03 +03:00
```text
2026-03-29 11:43:23 +03:00
.templates/
└── hook/
└── {{name.kebabCase}}/
├── {{name.kebabCase}}.hook.ts
└── index.ts
2026-03-18 09:22:03 +03:00
```
2026-03-29 11:43:23 +03:00
```ts
// .templates/hook/{{name.kebabCase}}.hook.ts
export const {{name.camelCase}} = () => {
2026-03-18 09:22:03 +03:00
}
```
2026-03-29 11:43:23 +03:00
```ts
// .templates/hook/index.ts
export { {{name.camelCase}} } from './{{name.kebabCase}}.hook'
```
2026-03-18 09:22:03 +03:00
2026-03-29 11:43:23 +03:00
### Примеры шаблонов
#### Шаблон компонента
2026-03-18 09:22:03 +03:00
```ts
// .templates/component/index.ts
2026-03-29 11:43:23 +03:00
export { {{name.pascalCase}} } from './{{name.kebabCase}}'
2026-03-23 21:48:54 +03:00
```
```ts
// .templates/component/types/{{name.kebabCase}}.interface.ts
import type { HTMLAttributes } from 'react'
/**
* Параметры {{name.pascalCase}}.
*/
export interface {{name.pascalCase}}Props extends HTMLAttributes< HTMLDivElement > {}
2026-03-18 09:22:03 +03:00
```
```tsx
2026-03-29 11:43:23 +03:00
// .templates/component/{{name.kebabCase}}.tsx
2026-03-23 21:48:54 +03:00
import type { FC } from 'react'
2026-03-18 09:22:03 +03:00
import cl from 'clsx'
2026-03-23 21:48:54 +03:00
import type { {{name.pascalCase}}Props } from './types/{{name.kebabCase}}.interface'
import styles from './styles/{{name.kebabCase}}.module.css'
2026-03-18 09:22:03 +03:00
2026-03-23 21:48:54 +03:00
/**
* {{name.pascalCase}}.
*/
2026-04-01 10:35:07 +03:00
export const {{name.pascalCase}}: FC< {{name.pascalCase}}Props> = (props) => {
const { children, className, ...htmlAttr } = props
2026-03-18 09:22:03 +03:00
return (
< div { . . . htmlAttr } className = {cl(styles.root, className ) } >
2026-04-01 10:35:07 +03:00
{children}
2026-03-18 09:22:03 +03:00
< / div >
)
}
```
```css
2026-03-23 21:48:54 +03:00
/* .templates/component/styles/{{name.kebabCase}}.module.css */
2026-03-18 09:22:03 +03:00
.root {
2026-03-23 21:48:54 +03:00
2026-03-18 09:22:03 +03:00
}
```
2026-03-29 11:43:23 +03:00
### Генерация через VS Code
2026-03-18 09:22:03 +03:00
2026-03-29 11:43:23 +03:00
[MyTemplateGenerator ](https://open-vsx.org/extension/MyTemplateGenerator/mytemplategenerator ) — расширение для генерации файлов и папок из шаблонов через интерфейс редактора.
2026-01-30 02:02:32 +03:00
2026-03-29 11:43:23 +03:00
1. ПКМ на целевой папке в проводнике VS Code.
2. **Generate from template** → выбрать шаблон.
3. Ввести имя (например `button` ) — расширение подставит е г о во все переменные `{{name}}` .
2026-03-23 21:48:54 +03:00
2026-03-29 11:43:23 +03:00
### Генерация через CLI
2026-03-23 21:48:54 +03:00
2026-03-29 11:43:23 +03:00
[@gromlab/create ](https://www.npmjs.com/package/@gromlab/create ) — CLI для генерации из тех же шаблонов. Используется через npx, глобальная установка не требуется.
2026-03-28 21:15:15 +03:00
2026-03-29 11:43:23 +03:00
```bash
npx @gromlab/create < шаблон > < имя > < путь >
```
2026-03-28 21:15:15 +03:00
2026-03-29 11:43:23 +03:00
| Команда | Что создаёт |
|---|---|
| `npx @gromlab/create component button src/shared/ui` | Компонент |
| `npx @gromlab/create feature auth src/features` | Фичу |
| `npx @gromlab/create widget header src/widgets` | Виджет |
| `npx @gromlab/create entity user src/entities` | Сущность |
| `npx @gromlab/create layout admin src/layouts` | Layout |
| `npx @gromlab/create store auth src/shared/model` | Стор |
:::
2026-03-28 21:15:15 +03:00
2026-03-29 11:43:23 +03:00
<!-- /applied/styles -->
## Стили
2026-03-28 21:15:15 +03:00
2026-03-29 11:43:23 +03:00
Раздел описывает правила написания CSS: PostCSS Modules, вложенность, медиа-запросы, переменные, форматирование.
2026-03-28 21:15:15 +03:00
2026-03-29 11:43:23 +03:00
### Общие правила
2026-03-23 21:48:54 +03:00
2026-03-28 21:15:15 +03:00
- Только **PostCSS** и **CSS Modules** для кастомной стилизации.
2026-03-23 21:48:54 +03:00
- Подход **Mobile First** — стили пишутся от мобильных к десктопу.
- Именование классов — `camelCase` (`.root` , `.buttonNext` , `.itemTitle` ).
- Модификаторы — отдельный класс с `_` , применяется через `&._modifier` .
**Хорошо**
```css
.submitButton {
padding: 8px 16px;
& ._disabled {
opacity: 0.5;
}
}
```
**Плохо**
```css
/* Плохо: kebab-case и вложенный элемент вместо отдельного класса. */
.submit-button {
padding: 8px 16px;
& __icon {
margin-right: 8px;
}
}
```
2026-03-29 11:43:23 +03:00
### Вложенность
2026-03-23 21:48:54 +03:00
- Вложенность селекторов запрещена.
- Исключения:
- Псевдоклассы: `&:hover` , `&:active` , `&:focus` , `&:disabled` и т.д.
- Псевдоэлементы: `&::before` , `&::after` .
- Медиа-запросы: `@media` .
- Модификаторы: `&._active` , `&._disabled` .
- Каждый вложенный блок отделяется пустой строкой от предыдущих свойств.
**Хорошо**
```css
.card {
padding: 16px;
background-color: var(--color-bg);
& :hover {
background-color: var(--color-bg-hover);
}
& ::after {
content: '';
display: block;
}
& ._highlighted {
border-color: var(--color-primary);
}
@media (--md) {
padding: 24px;
}
}
.cardTitle {
font-size: 16px;
@media (--md) {
font-size: 20px;
}
}
```
**Плохо**
```css
/* Плохо: вложенность селекторов, нет пустых строк между блоками. */
.card {
padding: 16px;
.cardTitle {
font-size: 16px;
}
& :hover {
background-color: var(--color-bg-hover);
}
}
```
2026-03-29 11:43:23 +03:00
### Медиа-запросы
2026-03-23 21:48:54 +03:00
- Только **Custom Media Queries** : `@media (--md) {}` .
- Запрещены произвольные breakpoints: `@media (min-width: 768px)` .
- `@media` пишется только **внутри** селектора.
- Запрещено писать `@media` на верхнем уровне с селекторами внутри.
**Хорошо**
```css
.sidebar {
display: none;
@media (--md) {
display: block;
}
}
.sidebarTitle {
font-size: 14px;
@media (--md) {
font-size: 18px;
}
}
```
**Плохо**
```css
/* Плохо: @media на верхнем уровне с селекторами внутри. */
@media (--md) {
.sidebar {
display: block;
}
.sidebarTitle {
font-size: 18px;
}
}
/* Плохо: произвольный breakpoint вместо custom media. */
.sidebar {
@media (min-width: 992px) {
display: block;
}
}
```
2026-03-29 11:43:23 +03:00
### CSS-переменные
2026-03-23 21:48:54 +03:00
- Цвета (`--color-*` ), отступы (`--space-*` ), скругления (`--radius-*` ) определяются в `app/styles/variables.css` через `:root` .
- Файл переменных подключается один раз в корневом layout/entry point — после этого переменные доступны глобально через каскад.
- Н е дублировать магические значения в компонентах.
**Хорошо**
```css
/* app/styles/variables.css */
:root {
--color-primary: #3b82f6 ;
--color-bg: #ffffff ;
--color-bg-hover: #f5f5f5 ;
--space-1: 4px;
--space-2: 8px;
--space-3: 12px;
--radius-1: 4px;
--radius-2: 8px;
}
```
```css
/* компонент */
.card {
padding: var(--space-3);
border-radius: var(--radius-2);
background-color: var(--color-bg);
}
```
**Плохо**
```css
/* Плохо: магические значения вместо переменных. */
.card {
padding: 12px;
border-radius: 8px;
background-color: #ffffff ;
}
```
2026-03-29 11:43:23 +03:00
### Custom Media
2026-03-23 21:48:54 +03:00
- Breakpoints определяются через Custom Media Queries в `app/styles/media.css` .
- Custom media подключаются глобально через конфиг PostCSS (плагин `postcss-custom-media` ) — не импортировать в файлы стилей.
```css
/* app/styles/media.css */
@custom -media --sm (min-width: 36em);
@custom -media --md (min-width: 62em);
@custom -media --lg (min-width: 82em);
```
2026-03-29 11:43:23 +03:00
### Импорт стилей
2026-03-23 21:48:54 +03:00
- Стили компонента импортируются только внутри своего компонента.
- Запрещено импортировать стили одного компонента в другой.
- Custom media не импортируются в файлы стилей — они подключаются глобально через конфиг PostCSS.
2026-03-29 11:43:23 +03:00
### Форматирование
2026-03-23 21:48:54 +03:00
- Пустая строка между селекторами верхнего уровня.
- Пустая строка перед каждым вложенным блоком (медиа, псевдокласс, модификатор).
**Хорошо**
```css
.userBar {
display: none;
color: var(--color-text);
@media (--md) {
display: flex;
}
}
.userBarButton {
background-color: var(--color-bg);
& :hover {
background-color: var(--color-bg-hover);
}
& ._active {
background-color: var(--color-primary);
}
}
```
**Плохо**
```css
/* Плохо: нет пустых строк между селекторами и вложенными блоками. */
.userBar {
display: none;
color: var(--color-text);
@media (--md) {
display: flex;
}
}
.userBarButton {
background-color: var(--color-bg);
& :hover {
background-color: var(--color-bg-hover);
}
& ._active {
background-color: var(--color-primary);
}
}
```
2026-03-29 11:43:23 +03:00
### Единицы измерения
2026-03-23 21:48:54 +03:00
- `px` — основная единица измерения.
- Остальные (`em` , `rem` , `%` , `vh` /`vw` ) — допускаются по необходимости дизайна.
2026-03-29 11:43:23 +03:00
### Порядок CSS-свойств
2026-03-23 21:48:54 +03:00
В стилях рекомендуется придерживаться логического порядка свойств:
1. Позиционирование (`position` , `top` , `left` , `z-index` ).
2. Блочная модель (`display` , `width` , `height` , `margin` , `padding` ).
3. Оформление (`background` , `border` , `box-shadow` , `border-radius` ).
4. Текст (`font` , `color` , `text-align` , `line-height` ).
5. Прочее (`transition` , `animation` , `opacity` , `cursor` ).
2026-03-29 11:43:23 +03:00
### Комментарии
2026-03-23 21:48:54 +03:00
- Желательно не писать комментарии в CSS.
- Исключение — нетривиальные хаки и обходные решения, к которым стоит оставить пояснение.
2026-01-30 02:02:32 +03:00
2026-03-29 11:43:23 +03:00
<!-- /applied/svg - sprites -->
2026-04-01 10:35:07 +03:00
## SVG-спрайты
<!-- /applied/vscode -->
## Настройка VS Code
Каждый проект содержит папку `.vscode/` с конфигурацией редактора. Это гарантирует, что все участники команды работают с одинаковыми настройками форматирования, линтинга и расширениями.
### Структура `.vscode/`
```text
.vscode/
├── extensions.json # Рекомендуемые расширения
└── settings.json # Настройки редактора для проекта
```
О б а файла коммитятся в репозиторий.
### Расширения
Файл `.vscode/extensions.json` определяет список расширений, которые VS Code предложит установить при открытии проекта.
```json
// .vscode/extensions.json
{
"recommendations": [
"biomejs.biome",
"MyTemplateGenerator.mytemplategenerator",
"csstools.postcss"
]
}
```
| Расширение | Назначение |
|---|---|
| [Biome ](https://marketplace.visualstudio.com/items?itemName=biomejs.biome ) | Линтинг и форматирование кода. Заменяет ESLint и Prettier |
| [MyTemplateGenerator ](https://open-vsx.org/extension/MyTemplateGenerator/mytemplategenerator ) | Генерация файлов и папок из шаблонов `.templates/` через контекстное меню |
| [PostCSS Language Support ](https://marketplace.visualstudio.com/items?itemName=csstools.postcss ) | Подсветка синтаксиса и автодополнение для PostCSS (`@custom-media` , `@nest` и др.) |
#### Зачем это нужно
- Новый участник команды получает все нужные расширения одним кликом.
- Нет разночтений: все используют одинаковый форматтер и линтер.
- Расширения привязаны к проекту, а не к конкретному разработчику.
### Настройки редактора
Файл `.vscode/settings.json` переопределяет пользовательские настройки VS Code на уровне проекта.
```json
// .vscode/settings.json
{
"editor.defaultFormatter": "biomejs.biome",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.biome": "explicit",
"source.organizeImports.biome": "explicit"
},
"files.associations": {
"*.css": "postcss"
}
}
```
#### Разбор настроек
| Настройка | Значение | Что делает |
|---|---|---|
| `editor.defaultFormatter` | `biomejs.biome` | Biome используется как единственный форматтер для всех файлов |
| `editor.formatOnSave` | `true` | Код автоматически форматируется при каждом сохранении |
| `codeActionsOnSave.source.fixAll.biome` | `explicit` | Biome автоматически применяет безопасные исправления при сохранении |
| `codeActionsOnSave.source.organizeImports.biome` | `explicit` | Импорты сортируются и группируются автоматически при сохранении |
| `files.associations` | `"*.css": "postcss"` | В с е CSS-файлы открываются с подсветкой PostCSS вместо стандартного CSS |
#### Зачем это нужно
- **Единый стиль кода** -- форматирование происходит автоматически, невозможно закоммитить неформатированный код.
- **Автофикс при сохранении** -- распространённые ошибки линтинга исправляются без ручного вмешательства.
- **Сортировка импортов** -- импорты всегда в одном порядке, без конфликтов при мерже.
- **PostCSS-подсветка** -- кастомные at-правила (`@custom-media` , `@define-mixin` ) подсвечиваются корректно, а не как ошибки.
### Что не должно быть в `.vscode/`
Н е коммитятся файлы, специфичные для конкретного разработчика:
- **Н е коммитить**: отладочные конфигурации с локальными путями, персональные сниппеты, настройки тем оформления.
- **Коммитить**: только `extensions.json` и `settings.json` с общими для команды настройками.