docs: переработать компоненты, структуру проекта и документирование
- переработан раздел «Компоненты»: добавлены правила организации, типизации, реализации - переработан раздел «Структура проекта»: упрощён, добавлены корень репозитория и конфиг-файлы - переработан раздел «Документирование»: добавлены шаблоны для функций, компонентов, типов - обновлён CONTRIBUTING.md: добавлены секции Workflow и Чеклист, правила разделены на Реализацию и Организацию - перенесены типы компонентов из «Типизации» в «Компоненты» - обновлён шаблон генерации: деструктуризация пропсов в теле, children вместо текста - добавлен SCREAMING_SNAKE_CASE для ключей enum в «Именование» - перемещён «Настройка VS Code» в конец сайдбара - обновлён порядок файлов в concat-md.js и перегенерирован RULES.md
This commit is contained in:
@@ -19,10 +19,8 @@ const ruSidebar = [
|
||||
{
|
||||
text: 'Прикладные разделы',
|
||||
items: [
|
||||
{ text: 'Настройка VS Code', link: '/applied/vscode' },
|
||||
{ text: 'Структура проекта', link: '/applied/project-structure' },
|
||||
{ text: 'UI и компоненты', link: '/applied/components' },
|
||||
{ text: 'Компоненты (new)', link: '/applied/components-new' },
|
||||
{ text: 'Компоненты', link: '/applied/components' },
|
||||
{ text: 'Страницы (App Router)', link: '/applied/page-level' },
|
||||
{ text: 'Шаблоны и генерация кода', link: '/applied/templates-generation' },
|
||||
{ text: 'Стили', link: '/applied/styles' },
|
||||
@@ -34,6 +32,7 @@ const ruSidebar = [
|
||||
{ text: 'Хуки', link: '/applied/hooks' },
|
||||
{ text: 'Шрифты', link: '/applied/fonts' },
|
||||
{ text: 'Локализация', link: '/applied/localization' },
|
||||
{ text: 'Настройка VS Code', link: '/applied/vscode' },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
docs/
|
||||
├── ru/ # Русская версия (основная)
|
||||
│ ├── index.md # Главная страница
|
||||
│ ├── workflow.md # Workflow (единый файл)
|
||||
│ ├── basics/ # Базовые правила
|
||||
│ │ ├── tech-stack.md
|
||||
│ │ ├── architecture.md
|
||||
@@ -63,16 +62,7 @@ concat-md.js # Скрипт генерации RULES.md
|
||||
2. Добавить пункт в сайдбар — `.vitepress/config.ts` (оба языка, если есть перевод).
|
||||
3. Добавить файл в массив `fileOrder` — `concat-md.js` (для генерации RULES.md).
|
||||
|
||||
## Три типа документации
|
||||
|
||||
### Workflow
|
||||
|
||||
**Отвечает на вопрос:** «Что делать и в каком порядке?»
|
||||
|
||||
Пошаговые инструкции. Описывает процесс, а не правила.
|
||||
Не содержит развёрнутых примеров кода — только минимальные команды и шаги.
|
||||
|
||||
Живёт в одном файле `workflow.md`.
|
||||
## Два типа документации
|
||||
|
||||
### Базовые правила
|
||||
|
||||
@@ -105,8 +95,8 @@ concat-md.js # Скрипт генерации RULES.md
|
||||
|
||||
## Что нужно знать
|
||||
|
||||
Контекст перед правилами: технологии, термины, принципы работы.
|
||||
Не правила — фундамент, без которого правила будут непонятны.
|
||||
Неочевидная информация, которую читатель должен знать перед чтением раздела.
|
||||
Если для раздела нет такой вводной — секция не создаётся.
|
||||
|
||||
## Структура
|
||||
|
||||
@@ -115,9 +105,25 @@ concat-md.js # Скрипт генерации RULES.md
|
||||
|
||||
## Правила
|
||||
|
||||
Конкретные требования к реализации в этой области.
|
||||
Формат — маркированный или нумерованный список.
|
||||
Конкретные требования, специфичные для области. Делятся на две подсекции:
|
||||
|
||||
### Реализация
|
||||
|
||||
Как написан код внутри файла: синтаксис, паттерны, API.
|
||||
Отвечает на вопрос: «Как писать код?»
|
||||
|
||||
Примеры: объявление через `const`, деструктуризация пропсов, формат вызова `cl()`, способ подключения стилей, структура хука.
|
||||
|
||||
### Организация
|
||||
|
||||
Как компонент/модуль встроен в проект: файловые границы, зоны ответственности, экспорт.
|
||||
Отвечает на вопрос: «Где что лежит и за что отвечает?»
|
||||
|
||||
Примеры: один компонент — один файл, вложенные компоненты в `ui/`, логика выносится в `model/`.
|
||||
|
||||
Формат обеих подсекций — маркированный список.
|
||||
Для неочевидных случаев — блоки «Хорошо / Плохо».
|
||||
Если в области нет правил одной из категорий — подсекция не создаётся.
|
||||
|
||||
## Именование
|
||||
|
||||
@@ -138,12 +144,29 @@ concat-md.js # Скрипт генерации RULES.md
|
||||
|
||||
Полноценные примеры кода.
|
||||
Каждый пример с путём к файлу и пояснениями.
|
||||
|
||||
## Workflow (процессы)
|
||||
|
||||
Пошаговая инструкция: как работать с этой областью на практике.
|
||||
Отвечает на вопрос: «Что делать и в каком порядке?»
|
||||
Нумерованный список шагов. Минимум кода — только команды и имена файлов.
|
||||
Не дублирует правила — описывает процесс, а не результат.
|
||||
Если для области нет специфичного процесса — секция не создаётся.
|
||||
|
||||
## Чеклист
|
||||
|
||||
Контрольный список для проверки перед завершением работы.
|
||||
Отвечает на вопрос: «Всё ли я сделал правильно?»
|
||||
Формат — маркированный список с чекбоксами (`- [ ]`).
|
||||
Каждый пункт — конкретная проверка, а не пересказ правила.
|
||||
Если для области нет специфичных проверок — секция не создаётся.
|
||||
```
|
||||
|
||||
### Порядок секций
|
||||
|
||||
Порядок фиксированный: контекст → структура → правила → специализации базовых правил → примеры.
|
||||
Логика: читатель сначала понимает «что это», потом «где это лежит», потом «как это делать», и в конце видит полный пример.
|
||||
Порядок фиксированный: контекст → структура → правила → специализации базовых правил → примеры → процесс → проверка.
|
||||
|
||||
Логика: читатель сначала понимает «что это», потом «где это лежит», потом «как это делать», видит полный пример, получает пошаговую инструкцию и в конце проверяет себя по чеклисту.
|
||||
|
||||
### Секции-расширения базовых правил
|
||||
|
||||
@@ -215,6 +238,6 @@ title: Название раздела
|
||||
|
||||
1. **Не дублировать.** Одна мысль живёт в одном месте. Остальные ссылаются.
|
||||
2. **Базовое vs прикладное.** Если правило применимо ко всему коду — оно базовое. Если только к одной области — прикладное.
|
||||
3. **Workflow vs правила.** Workflow описывает процесс (шаги). Правила описывают результат (каким должен быть код).
|
||||
3. **Workflow vs правила.** Workflow описывает процесс (шаги), правила описывают результат (каким должен быть код). Оба живут внутри прикладного раздела, но не смешиваются.
|
||||
4. **Пустые секции не создавать.** Если для раздела нет специфики по именованию — секции «Именование» в нём нет.
|
||||
5. **Примеры обязательны.** Прикладной раздел без примеров кода — незавершён.
|
||||
|
||||
@@ -15,7 +15,6 @@ const fileOrder = [
|
||||
"basics/documentation.md",
|
||||
"basics/typing.md",
|
||||
// applied
|
||||
"applied/vscode.md",
|
||||
"applied/project-structure.md",
|
||||
"applied/components.md",
|
||||
"applied/page-level.md",
|
||||
@@ -29,6 +28,7 @@ const fileOrder = [
|
||||
"applied/hooks.md",
|
||||
"applied/fonts.md",
|
||||
"applied/localization.md",
|
||||
"applied/vscode.md",
|
||||
];
|
||||
|
||||
// Удалить frontmatter из содержимого md-файла
|
||||
|
||||
@@ -1,10 +1,20 @@
|
||||
---
|
||||
title: UI и компоненты
|
||||
title: Компоненты
|
||||
---
|
||||
|
||||
# UI и компоненты
|
||||
# Компоненты
|
||||
|
||||
Раздел описывает правила создания UI‑компонентов. Эти правила обязательны для всех слоёв FSD: `app`, `screens`, `layouts`, `widgets`, `features`, `entities`, `shared`.
|
||||
Правила написания React-компонентов: файловая структура модуля, типизация пропсов, документирование и реализация. Раздел охватывает компоненты всех слоёв — от `shared/ui` до `screens`.
|
||||
|
||||
Архитектурные слои и их назначение описаны в разделе [Архитектура](/basics/architecture).
|
||||
|
||||
|
||||
## Правила организации
|
||||
|
||||
1. Один компонент — один файл.
|
||||
2. Компонент не содержит бизнес-логики — логика и сайд-эффекты выносятся в хуки или сторы.
|
||||
3. Дочерние компоненты размещаются в сегменте `ui/` и подчиняются тем же правилам структуры.
|
||||
4. Публичный API модуля — только `index.ts`. Прямые импорты внутренних файлов запрещены.
|
||||
|
||||
## Базовая структура компонента
|
||||
|
||||
@@ -20,26 +30,48 @@ container/
|
||||
└── index.ts
|
||||
```
|
||||
|
||||
## Пример базового компонента
|
||||
## Именования
|
||||
|
||||
`styles/container.module.css`
|
||||
```scss
|
||||
.root {}
|
||||
```
|
||||
В CSS Modules использование имени класса **.root** — это общепринятое соглашение (best practice)
|
||||
- Имя корневого css класса всегда `.root`
|
||||
- Интерфейс именуется `{ComponentName}Props`.
|
||||
|
||||
## Типизация
|
||||
|
||||
- Компонент типизируется через `FC<Props>`.
|
||||
- Интерфейс пропсов наследует HTML-атрибуты своего корневого элемента.
|
||||
- `children` отдельно не объявляется — приходит из `HTMLAttributes`.
|
||||
|
||||
## Реализация
|
||||
|
||||
- Пропсы деструктурируются в теле компонента, не в параметрах.
|
||||
- Порядок: пользовательские → системные (`children`, `className`) → `...htmlAttr`.
|
||||
- `className` объединяется с корневым классом через `cl()`: `cl(styles.root, className)`.
|
||||
- `...htmlAttr` прокидывается на корневой элемент.
|
||||
|
||||
## Пример
|
||||
|
||||
`container/types/container.interface.ts`
|
||||
|
||||
`types/container.interface.ts`
|
||||
```ts
|
||||
import type { HTMLAttributes } from 'react'
|
||||
|
||||
/**
|
||||
* Параметры контейнера.
|
||||
* Параметры компонента Container.
|
||||
*/
|
||||
export interface ContainerProps extends HTMLAttributes<HTMLDivElement> {}
|
||||
```
|
||||
Интерфес параметров компонента всегда наследует свойства своего тега: div, button, итд..
|
||||
|
||||
`container.tsx`
|
||||
`container/styles/container.module.css`
|
||||
|
||||
```css
|
||||
.root {
|
||||
max-width: var(--content-width);
|
||||
margin: 0 auto;
|
||||
padding: 0 var(--spacing-4);
|
||||
}
|
||||
```
|
||||
|
||||
`container/container.tsx`
|
||||
|
||||
```tsx
|
||||
import type { FC } from 'react'
|
||||
@@ -51,39 +83,23 @@ import styles from './styles/container.module.css'
|
||||
* Контейнер с адаптивной максимальной шириной.
|
||||
*
|
||||
* Используется для:
|
||||
* - ограничения ширины контента
|
||||
* - центрирования содержимого
|
||||
* - построения адаптивной сетки страницы
|
||||
* - обёртки контента страниц с ограничением ширины
|
||||
* - центрирования блоков в лейауте
|
||||
*/
|
||||
export const Container: FC<ContainerProps> = ({ className, ...htmlAttr }) => {
|
||||
export const Container: FC<ContainerProps> = (props) => {
|
||||
const { children, className, ...htmlAttr } = props
|
||||
|
||||
return (
|
||||
<div {...htmlAttr} className={cl(styles.root, className)}>
|
||||
Container...
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
- Компонент объявляется через `const` и экспортируется именованно.
|
||||
- Пропсы деструктурируются в сигнатуре; если их больше двух — деструктуризацию переносим в тело компонента.
|
||||
- Из пропсов отдельно извлекаются `className` и `...htmlAttr`, чтобы корректно объединять классы и прокидывать остальные атрибуты.
|
||||
- `cl` — короткое имя функции для конкатенации CSS‑классов.
|
||||
- `FC<>` используется для декларации `children`.
|
||||
|
||||
`index.ts`
|
||||
`container/index.ts`
|
||||
|
||||
```ts
|
||||
export { Container } from './container'
|
||||
```
|
||||
|
||||
## Шаблоны и генерация кода
|
||||
|
||||
Создание компонентов — **только через шаблоны**. Ручное создание файловой структуры компонента запрещено. Это обеспечивает единообразие каркаса, одинаковые папки и имена файлов, уменьшает ручные ошибки и ускоряет старт работы.
|
||||
|
||||
После генерации через **@gromlab/create** — проверить название компонента/файлов и заполнить описание назначения. Подробный порядок действий и перечень обязательных шаблонов — в разделе «Workflow».
|
||||
|
||||
## Вложенные (дочерние) компоненты
|
||||
|
||||
Если для реализации функционала нужны компоненты, которые используются только внутри текущего компонента, создавайте их как вложенные в папке `ui/`. Такие компоненты не экспортируются наружу и используются только локально.
|
||||
|
||||
Вложенные компоненты подчиняются тем же правилам по структуре, именованию и стилю (включая папку `styles/` для их стилей).
|
||||
|
||||
@@ -4,146 +4,96 @@ title: Структура проекта
|
||||
|
||||
# Структура проекта
|
||||
|
||||
Раздел описывает базовую структуру проекта Next.js (App Router) и принципы организации модулей на уровне папок и файлов.
|
||||
Раздел описывает расположение файлов и папок в проекте Next.js (App Router).
|
||||
|
||||
## Базовая структура проекта
|
||||
## Корень репозитория
|
||||
|
||||
```text
|
||||
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 без обработки сборщиком:
|
||||
|
||||
```text
|
||||
public/
|
||||
└── og-image.png
|
||||
```
|
||||
|
||||
Компоненты, стили и другой исходный код здесь не размещаются.
|
||||
|
||||
## Папка `src/`
|
||||
|
||||
```text
|
||||
src/
|
||||
├── app/ # Слой app: роутинг, провайдеры, глобальные стили
|
||||
│ ├── providers/ # Провайдеры и обёртки приложения
|
||||
│ ├── styles/ # Глобальные стили, CSS-переменные, custom media
|
||||
│ ├── layout.tsx # Корневой layout (провайдеры, стили, метаданные)
|
||||
│ ├── page.tsx # Главная страница → HomeScreen
|
||||
│ └── profile/
|
||||
│ ├── page.tsx # → ProfileScreen
|
||||
│ └── [id]/
|
||||
│ └── page.tsx # → ProfileDetailScreen
|
||||
├── screens/ # UI-компоненты страниц
|
||||
│ ├── home/
|
||||
│ │ ├── home.screen.tsx
|
||||
│ │ └── index.ts
|
||||
│ └── profile/
|
||||
│ ├── profile.screen.tsx
|
||||
│ └── index.ts
|
||||
├── layouts/ # Общие шаблоны и каркасы страниц
|
||||
│ └── main-layout/
|
||||
│ ├── main-layout.layout.tsx
|
||||
│ └── index.ts
|
||||
├── widgets/ # Крупные блоки интерфейса
|
||||
│ └── header/
|
||||
│ ├── header.widget.tsx
|
||||
│ └── index.ts
|
||||
├── app/ # Роутинг Next.js, провайдеры, глобальные стили
|
||||
├── screens/ # Собраные страницы (UI)
|
||||
├── layouts/ # Шаблоны
|
||||
├── widgets/ # Крупные самостоятельные блоки интерфейса
|
||||
├── features/ # Пользовательские сценарии
|
||||
│ └── auth-by-email/
|
||||
│ ├── ui/
|
||||
│ │ └── login-form.tsx
|
||||
│ ├── model/
|
||||
│ │ └── auth-by-email.store.ts
|
||||
│ ├── auth-by-email.feature.tsx
|
||||
│ └── index.ts
|
||||
├── entities/ # Бизнес-сущности
|
||||
│ └── user/
|
||||
│ ├── model/
|
||||
│ │ └── user.store.ts
|
||||
│ ├── user.entity.tsx
|
||||
│ └── index.ts
|
||||
└── shared/ # Общие ресурсы проекта
|
||||
├── ui/ # Повторно используемые UI-элементы
|
||||
│ └── icon/
|
||||
│ ├── styles/
|
||||
│ │ └── icon.module.css
|
||||
│ ├── types/
|
||||
│ │ └── icon.interface.ts
|
||||
│ ├── icon.tsx
|
||||
│ └── index.ts
|
||||
├── lib/ # Утилиты и хелперы
|
||||
├── services/ # Общие сервисы и клиенты
|
||||
├── config/ # Общие конфигурации и константы
|
||||
└── assets/ # Ресурсы
|
||||
├── images/
|
||||
├── icons/
|
||||
├── fonts/
|
||||
└── video/
|
||||
└── shared/ # Переиспользуемый код (UI, утилиты, типы и др.)
|
||||
```
|
||||
|
||||
## Слой `app/`
|
||||
Принципы организации слоёв описаны в разделе [Архитектура](../basics/architecture).
|
||||
|
||||
Папка `app/` совмещает две роли: инициализация приложения (провайдеры, глобальные стили) и файловый роутинг Next.js (route-сегменты, `layout.tsx`, `page.tsx`).
|
||||
### Папка `app/`
|
||||
|
||||
- `providers/` и `styles/` -- это инфраструктура приложения, они не являются частью роутинга.
|
||||
- Route-сегменты (вложенные папки с `page.tsx`) -- это роутинг Next.js. Они не содержат логики, только импортируют экраны из `screens/`.
|
||||
Совмещает два слоя: инициализацию приложения по FSD (провайдеры, глобальные стили) и файловый роутинг Next.js (`layout.tsx`, `page.tsx`, route-сегменты).
|
||||
|
||||
Компоненты, хуки, стили и утилиты не размещаются внутри route-сегментов -- всё это живёт в соответствующих слоях FSD.
|
||||
|
||||
## Правила организации
|
||||
|
||||
- В слоях FSD (`features`, `entities`, `widgets`, `screens` и т.д.) `ui/` используется только для дочерних элементов, которые относятся к модулю и не экспортируются отдельно. Главные компоненты, которые составляют сам слой, держат собственные `*.feature.tsx`, `*.widget.tsx` и т. п., а `ui/` служит для вспомогательных мелких компонентов.
|
||||
- В `shared/ui/` хранятся базовые UI-элементы/компоненты, которыми пользуются сразу несколько модулей; в этом случае они экспортируются наружу и не считаются «дочерними» для слоя.
|
||||
- Если модуль строится вокруг «главного» компонента (`*.feature.tsx`, `*.screen.tsx`, `*.widget.tsx`), помещайте его в корень модуля и экспортируйте через `index.ts`. Проверяйте, что `ui/` не используется просто как «контейнер» слоя.
|
||||
- Каждый слой и модуль хранится в собственной папке.
|
||||
- Внутренние реализации разделяются на `ui/`, `model/`, `styles/`, `helpers/`, `lib/`, `api/`.
|
||||
- Публичный API модуля объявляется в `index.ts`.
|
||||
- Внутренние файлы не импортируются напрямую извне.
|
||||
- Не смешивать ответственность разных слоёв в одном модуле.
|
||||
|
||||
## Пример организации структуры
|
||||
|
||||
**Плохо** -- плоская структура без архитектуры:
|
||||
```text
|
||||
src/
|
||||
├── components/
|
||||
│ ├── Header.tsx
|
||||
│ ├── LoginForm.tsx
|
||||
│ ├── UserCard.tsx
|
||||
│ └── Button.tsx
|
||||
├── hooks/
|
||||
│ ├── useAuth.ts
|
||||
│ └── useUser.ts
|
||||
├── api/
|
||||
│ ├── auth.ts
|
||||
│ └── user.ts
|
||||
├── styles/
|
||||
│ ├── header.module.css
|
||||
│ └── login.module.css
|
||||
├── types/
|
||||
│ └── user.ts
|
||||
└── utils/
|
||||
└── format.ts
|
||||
src/app/
|
||||
├── providers/ # Провайдеры приложения
|
||||
├── styles/ # Глобальные стили
|
||||
├── layout.tsx # Корневой layout
|
||||
└── page.tsx # Главная страница
|
||||
```
|
||||
|
||||
Нет слоёв, нет границ ответственности -- Header и Button лежат рядом, хотя это разные уровни абстракции. LoginForm знает про API напрямую. При росте проекта `components/` превращается в свалку.
|
||||
## Папка `.templates/`
|
||||
|
||||
Содержит шаблоны для генерации кода. Каждый подкаталог — шаблон отдельного типа модуля:
|
||||
|
||||
**Хорошо** -- та же функциональность в FSD:
|
||||
```text
|
||||
src/
|
||||
├── widgets/
|
||||
│ └── header/
|
||||
│ ├── header.widget.tsx
|
||||
│ └── index.ts
|
||||
├── features/
|
||||
│ └── auth-by-email/
|
||||
│ ├── ui/
|
||||
│ │ └── login-form.tsx
|
||||
│ ├── model/
|
||||
│ │ └── auth.store.ts
|
||||
│ ├── auth-by-email.feature.tsx
|
||||
│ └── index.ts
|
||||
├── entities/
|
||||
│ └── user/
|
||||
│ ├── ui/
|
||||
│ │ └── user-card.tsx
|
||||
│ ├── model/
|
||||
│ │ └── user.store.ts
|
||||
│ ├── user.entity.tsx
|
||||
│ └── index.ts
|
||||
└── shared/
|
||||
├── ui/
|
||||
│ └── button/
|
||||
│ ├── button.tsx
|
||||
│ └── index.ts
|
||||
└── lib/
|
||||
└── format.ts
|
||||
.templates/
|
||||
├── component/ # Шаблон компонента
|
||||
├── screen/ # Шаблон экрана
|
||||
├── layout/ # Шаблон layout
|
||||
├── widget/ # Шаблон виджета
|
||||
├── feature/ # Шаблон фичи
|
||||
├── entity/ # Шаблон сущности
|
||||
└── store/ # Шаблон стора
|
||||
```
|
||||
|
||||
Каждый элемент на своём слое, с публичным API и чёткими границами ответственности.
|
||||
Подробнее о генерации описано в разделе [Шаблоны и генерация кода](./templates-generation).
|
||||
|
||||
## Конфигурационные файлы
|
||||
|
||||
| Файл | Назначение |
|
||||
|---|---|
|
||||
| `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-агентов, работающих в проекте |
|
||||
|
||||
## Переменные окружения
|
||||
|
||||
- `.env` — переменные окружения проекта, запрещено коммитить
|
||||
- `.env.example` — шаблон, коммитится в репозиторий
|
||||
|
||||
Переменные с префиксом `NEXT_PUBLIC_` доступны в клиентском коде. Остальные доступны только на сервере.
|
||||
|
||||
@@ -105,10 +105,12 @@ import styles from './styles/{{name.kebabCase}}.module.css'
|
||||
/**
|
||||
* {{name.pascalCase}}.
|
||||
*/
|
||||
export const {{name.pascalCase}}: FC<{{name.pascalCase}}Props> = ({ className, ...htmlAttr }) => {
|
||||
export const {{name.pascalCase}}: FC<{{name.pascalCase}}Props> = (props) => {
|
||||
const { children, className, ...htmlAttr } = props
|
||||
|
||||
return (
|
||||
<div {...htmlAttr} className={cl(styles.root, className)}>
|
||||
{{name.kebabCase}}
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4,61 +4,131 @@ title: Документирование
|
||||
|
||||
# Документирование
|
||||
|
||||
Этот раздел описывает правила документирования кода: когда и как писать комментарии к функциям, компонентам, типам и интерфейсам.
|
||||
Этот раздел описывает правила документирования кода: когда и как писать
|
||||
комментарии к компонентам, функциям, типам и интерфейсам.
|
||||
|
||||
## Правила
|
||||
## Общие правила
|
||||
|
||||
- Документировать только назначение функций, компонентов, типов, интерфейсов и enum.
|
||||
- Не документировать параметры, возвращаемые значения, типы пропсов и очевидные детали.
|
||||
- В интерфейсах, типах и enum описывать только смысл поля или значения.
|
||||
- Описание должно быть кратким, информативным и завершаться точкой.
|
||||
- Документировать публичные функции, компоненты, типы, интерфейсы и enum.
|
||||
- Не документировать очевидное — если название говорит само за себя, комментарий не нужен.
|
||||
- Не документировать параметры, возвращаемые значения и типы пропсов — они видны из сигнатуры.
|
||||
- Описание через пользу и назначение, а не через внутреннюю реализацию.
|
||||
- Описание завершается точкой.
|
||||
|
||||
## Примеры
|
||||
## Функции
|
||||
|
||||
Для документирования функций используется шаблон. Описание механики опционально —
|
||||
добавляется когда логика нетривиальна.
|
||||
|
||||
**Шаблон**
|
||||
```ts
|
||||
/**
|
||||
* <Что делает функция в 1 строке>.
|
||||
*
|
||||
* <Опционально: описание сложной механики или важных нюансов>.
|
||||
*/
|
||||
```
|
||||
|
||||
**Хорошо**
|
||||
```ts
|
||||
/**
|
||||
* Список задач пользователя.
|
||||
* Форматирует цену с символом валюты.
|
||||
*/
|
||||
export const TodoList = memo(() => { ... });
|
||||
export const formatPrice = (value: number): string => { ... }
|
||||
|
||||
/**
|
||||
* Интерфейс задачи.
|
||||
* Рекурсивно собирает дерево категорий из плоского списка.
|
||||
*
|
||||
* Группирует элементы по parentId, начиная с корневых (parentId = null).
|
||||
* Категории без родителя попадают в корень дерева.
|
||||
*/
|
||||
export const buildCategoryTree = (categories: Category[]): CategoryTree[] => { ... }
|
||||
```
|
||||
|
||||
**Плохо**
|
||||
```ts
|
||||
// Плохо: дублирует сигнатуру.
|
||||
/**
|
||||
* @param value - число
|
||||
* @returns строка с ценой
|
||||
*/
|
||||
```
|
||||
|
||||
## Компоненты
|
||||
|
||||
Компонент описывает своё **назначение** и **сценарии применения** — это помогает понять, когда и где его использовать, без необходимости читать реализацию.
|
||||
|
||||
**Шаблон**
|
||||
```ts
|
||||
/**
|
||||
* <Назначение компонента в 1 строке>.
|
||||
*
|
||||
* Используется для:
|
||||
* - <сценарий 1>
|
||||
* - <сценарий 2>
|
||||
* - <сценарий 3>
|
||||
*/
|
||||
```
|
||||
|
||||
**Хорошо**
|
||||
```tsx
|
||||
/**
|
||||
* Контейнер с адаптивной максимальной шириной.
|
||||
*
|
||||
* Используется для:
|
||||
* - обёртки контента страниц с ограничением ширины
|
||||
* - центрирования блоков в лейауте
|
||||
*/
|
||||
export const Container: FC<ContainerProps> = (props) => { ... }
|
||||
```
|
||||
|
||||
**Плохо**
|
||||
```tsx
|
||||
// Плохо: описывает реализацию, а не назначение.
|
||||
/**
|
||||
* Рендерит div с className и htmlAttr.
|
||||
*/
|
||||
|
||||
// Плохо: нет описания вообще.
|
||||
export const Container: FC<ContainerProps> = (props) => { ... }
|
||||
```
|
||||
|
||||
## Типы, интерфейсы, enum
|
||||
|
||||
Документируются назначение сущности и каждое её поле.
|
||||
|
||||
**Хорошо**
|
||||
```ts
|
||||
/**
|
||||
* Фильтры списка задач.
|
||||
*/
|
||||
export enum TodoFilter {
|
||||
/** Все задачи. */
|
||||
ALL = 'all',
|
||||
/** Только активные. */
|
||||
ACTIVE = 'active',
|
||||
/** Только завершённые. */
|
||||
COMPLETED = 'completed',
|
||||
}
|
||||
|
||||
/**
|
||||
* Задача пользователя.
|
||||
*/
|
||||
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 — статус выполнения
|
||||
*/
|
||||
// Плохо: описывает очевидное.
|
||||
export interface TodoItem {
|
||||
/** id — это id */
|
||||
id: string;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -18,6 +18,7 @@ title: Именование
|
||||
| React-компоненты | `PascalCase` |
|
||||
| Хуки | `useSomething` |
|
||||
| CSS классы | `camelCase` |
|
||||
| Ключи enum | `SCREAMING_SNAKE_CASE` |
|
||||
|
||||
|
||||
## Именование файлов
|
||||
|
||||
@@ -13,45 +13,6 @@ title: Типизация
|
||||
- Избегать `any` и `unknown` без необходимости.
|
||||
- Не использовать `ts-ignore`, кроме крайних случаев с явным комментарием причины.
|
||||
|
||||
## Типы для компонентов
|
||||
|
||||
- Типизировать параметры и публичный интерфейс компонента.
|
||||
- Дефолтные значения описывать явно в коде.
|
||||
|
||||
**Хорошо**
|
||||
```tsx
|
||||
/**
|
||||
* Параметры кнопки.
|
||||
*/
|
||||
interface ButtonProps extends HTMLAttributes<HTMLDivElement> {
|
||||
/** Текст кнопки. */
|
||||
label: string;
|
||||
/** Обработчик клика по кнопке. */
|
||||
onClick: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Кнопка с пользовательскими стилями.
|
||||
*/
|
||||
export const Button: FC<ButtonProps> = ({ 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>
|
||||
);
|
||||
```
|
||||
|
||||
## Функции
|
||||
|
||||
- Для публичных функций указывать возвращаемый тип.
|
||||
|
||||
@@ -200,6 +200,7 @@
|
||||
| React-компоненты | `PascalCase` |
|
||||
| Хуки | `useSomething` |
|
||||
| CSS классы | `camelCase` |
|
||||
| Ключи enum | `SCREAMING_SNAKE_CASE` |
|
||||
|
||||
|
||||
### Именование файлов
|
||||
@@ -540,63 +541,133 @@ const config = { url: '/api/users', method: 'GET', params: { page: 1, pageSize:
|
||||
<!-- /basics/documentation -->
|
||||
## Документирование
|
||||
|
||||
Этот раздел описывает правила документирования кода: когда и как писать комментарии к функциям, компонентам, типам и интерфейсам.
|
||||
Этот раздел описывает правила документирования кода: когда и как писать
|
||||
комментарии к компонентам, функциям, типам и интерфейсам.
|
||||
|
||||
### Правила
|
||||
### Общие правила
|
||||
|
||||
- Документировать только назначение функций, компонентов, типов, интерфейсов и enum.
|
||||
- Не документировать параметры, возвращаемые значения, типы пропсов и очевидные детали.
|
||||
- В интерфейсах, типах и enum описывать только смысл поля или значения.
|
||||
- Описание должно быть кратким, информативным и завершаться точкой.
|
||||
- Документировать публичные функции, компоненты, типы, интерфейсы и enum.
|
||||
- Не документировать очевидное — если название говорит само за себя, комментарий не нужен.
|
||||
- Не документировать параметры, возвращаемые значения и типы пропсов — они видны из сигнатуры.
|
||||
- Описание через пользу и назначение, а не через внутреннюю реализацию.
|
||||
- Описание завершается точкой.
|
||||
|
||||
### Примеры
|
||||
### Функции
|
||||
|
||||
Для документирования функций используется шаблон. Описание механики опционально —
|
||||
добавляется когда логика нетривиальна.
|
||||
|
||||
**Шаблон**
|
||||
```ts
|
||||
/**
|
||||
* <Что делает функция в 1 строке>.
|
||||
*
|
||||
* <Опционально: описание сложной механики или важных нюансов>.
|
||||
*/
|
||||
```
|
||||
|
||||
**Хорошо**
|
||||
```ts
|
||||
/**
|
||||
* Список задач пользователя.
|
||||
* Форматирует цену с символом валюты.
|
||||
*/
|
||||
export const TodoList = memo(() => { ... });
|
||||
export const formatPrice = (value: number): string => { ... }
|
||||
|
||||
/**
|
||||
* Интерфейс задачи.
|
||||
* Рекурсивно собирает дерево категорий из плоского списка.
|
||||
*
|
||||
* Группирует элементы по parentId, начиная с корневых (parentId = null).
|
||||
* Категории без родителя попадают в корень дерева.
|
||||
*/
|
||||
export const buildCategoryTree = (categories: Category[]): CategoryTree[] => { ... }
|
||||
```
|
||||
|
||||
**Плохо**
|
||||
```ts
|
||||
// Плохо: дублирует сигнатуру.
|
||||
/**
|
||||
* @param value - число
|
||||
* @returns строка с ценой
|
||||
*/
|
||||
```
|
||||
|
||||
### Компоненты
|
||||
|
||||
Компонент описывает своё **назначение** и **сценарии применения** — это помогает понять, когда и где его использовать, без необходимости читать реализацию.
|
||||
|
||||
**Шаблон**
|
||||
```ts
|
||||
/**
|
||||
* <Назначение компонента в 1 строке>.
|
||||
*
|
||||
* Используется для:
|
||||
* - <сценарий 1>
|
||||
* - <сценарий 2>
|
||||
* - <сценарий 3>
|
||||
*/
|
||||
```
|
||||
|
||||
**Хорошо**
|
||||
```tsx
|
||||
/**
|
||||
* Контейнер с адаптивной максимальной шириной.
|
||||
*
|
||||
* Используется для:
|
||||
* - обёртки контента страниц с ограничением ширины
|
||||
* - центрирования блоков в лейауте
|
||||
*/
|
||||
export const Container: FC<ContainerProps> = (props) => { ... }
|
||||
```
|
||||
|
||||
**Плохо**
|
||||
```tsx
|
||||
// Плохо: описывает реализацию, а не назначение.
|
||||
/**
|
||||
* Рендерит div с className и htmlAttr.
|
||||
*/
|
||||
|
||||
// Плохо: нет описания вообще.
|
||||
export const Container: FC<ContainerProps> = (props) => { ... }
|
||||
```
|
||||
|
||||
### Типы, интерфейсы, enum
|
||||
|
||||
Документируются назначение сущности и каждое её поле.
|
||||
|
||||
**Хорошо**
|
||||
```ts
|
||||
/**
|
||||
* Фильтры списка задач.
|
||||
*/
|
||||
export enum TodoFilter {
|
||||
/** Все задачи. */
|
||||
ALL = 'all',
|
||||
/** Только активные. */
|
||||
ACTIVE = 'active',
|
||||
/** Только завершённые. */
|
||||
COMPLETED = 'completed',
|
||||
}
|
||||
|
||||
/**
|
||||
* Задача пользователя.
|
||||
*/
|
||||
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 — статус выполнения
|
||||
*/
|
||||
// Плохо: описывает очевидное.
|
||||
export interface TodoItem {
|
||||
/** id — это id */
|
||||
id: string;
|
||||
}
|
||||
```
|
||||
|
||||
<!-- /basics/typing -->
|
||||
@@ -611,45 +682,6 @@ export enum TodoFilter {
|
||||
- Избегать `any` и `unknown` без необходимости.
|
||||
- Не использовать `ts-ignore`, кроме крайних случаев с явным комментарием причины.
|
||||
|
||||
### Типы для компонентов
|
||||
|
||||
- Типизировать параметры и публичный интерфейс компонента.
|
||||
- Дефолтные значения описывать явно в коде.
|
||||
|
||||
**Хорошо**
|
||||
```tsx
|
||||
/**
|
||||
* Параметры кнопки.
|
||||
*/
|
||||
interface ButtonProps extends HTMLAttributes<HTMLDivElement> {
|
||||
/** Текст кнопки. */
|
||||
label: string;
|
||||
/** Обработчик клика по кнопке. */
|
||||
onClick: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Кнопка с пользовательскими стилями.
|
||||
*/
|
||||
export const Button: FC<ButtonProps> = ({ 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>
|
||||
);
|
||||
```
|
||||
|
||||
### Функции
|
||||
|
||||
- Для публичных функций указывать возвращаемый тип.
|
||||
@@ -692,242 +724,117 @@ const parse = (value: unknown): string => {
|
||||
const parse = (value: any) => value;
|
||||
```
|
||||
|
||||
<!-- /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` с общими для команды настройками.
|
||||
|
||||
<!-- /applied/project-structure -->
|
||||
## Структура проекта
|
||||
|
||||
Раздел описывает базовую структуру проекта Next.js (App Router) и принципы организации модулей на уровне папок и файлов.
|
||||
Раздел описывает расположение файлов и папок в проекте Next.js (App Router).
|
||||
|
||||
### Базовая структура проекта
|
||||
### Корень репозитория
|
||||
|
||||
```text
|
||||
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 без обработки сборщиком:
|
||||
|
||||
```text
|
||||
public/
|
||||
└── og-image.png
|
||||
```
|
||||
|
||||
Компоненты, стили и другой исходный код здесь не размещаются.
|
||||
|
||||
### Папка `src/`
|
||||
|
||||
```text
|
||||
src/
|
||||
├── app/ # Слой app: роутинг, провайдеры, глобальные стили
|
||||
│ ├── providers/ # Провайдеры и обёртки приложения
|
||||
│ ├── styles/ # Глобальные стили, CSS-переменные, custom media
|
||||
│ ├── layout.tsx # Корневой layout (провайдеры, стили, метаданные)
|
||||
│ ├── page.tsx # Главная страница → HomeScreen
|
||||
│ └── profile/
|
||||
│ ├── page.tsx # → ProfileScreen
|
||||
│ └── [id]/
|
||||
│ └── page.tsx # → ProfileDetailScreen
|
||||
├── screens/ # UI-компоненты страниц
|
||||
│ ├── home/
|
||||
│ │ ├── home.screen.tsx
|
||||
│ │ └── index.ts
|
||||
│ └── profile/
|
||||
│ ├── profile.screen.tsx
|
||||
│ └── index.ts
|
||||
├── layouts/ # Общие шаблоны и каркасы страниц
|
||||
│ └── main-layout/
|
||||
│ ├── main-layout.layout.tsx
|
||||
│ └── index.ts
|
||||
├── widgets/ # Крупные блоки интерфейса
|
||||
│ └── header/
|
||||
│ ├── header.widget.tsx
|
||||
│ └── index.ts
|
||||
├── app/ # Роутинг Next.js, провайдеры, глобальные стили
|
||||
├── screens/ # Собраные страницы (UI)
|
||||
├── layouts/ # Шаблоны
|
||||
├── widgets/ # Крупные самостоятельные блоки интерфейса
|
||||
├── features/ # Пользовательские сценарии
|
||||
│ └── auth-by-email/
|
||||
│ ├── ui/
|
||||
│ │ └── login-form.tsx
|
||||
│ ├── model/
|
||||
│ │ └── auth-by-email.store.ts
|
||||
│ ├── auth-by-email.feature.tsx
|
||||
│ └── index.ts
|
||||
├── entities/ # Бизнес-сущности
|
||||
│ └── user/
|
||||
│ ├── model/
|
||||
│ │ └── user.store.ts
|
||||
│ ├── user.entity.tsx
|
||||
│ └── index.ts
|
||||
└── shared/ # Общие ресурсы проекта
|
||||
├── ui/ # Повторно используемые UI-элементы
|
||||
│ └── icon/
|
||||
│ ├── styles/
|
||||
│ │ └── icon.module.css
|
||||
│ ├── types/
|
||||
│ │ └── icon.interface.ts
|
||||
│ ├── icon.tsx
|
||||
│ └── index.ts
|
||||
├── lib/ # Утилиты и хелперы
|
||||
├── services/ # Общие сервисы и клиенты
|
||||
├── config/ # Общие конфигурации и константы
|
||||
└── assets/ # Ресурсы
|
||||
├── images/
|
||||
├── icons/
|
||||
├── fonts/
|
||||
└── video/
|
||||
└── shared/ # Переиспользуемый код (UI, утилиты, типы и др.)
|
||||
```
|
||||
|
||||
### Слой `app/`
|
||||
Принципы организации слоёв описаны в разделе [Архитектура](../basics/architecture).
|
||||
|
||||
Папка `app/` совмещает две роли: инициализация приложения (провайдеры, глобальные стили) и файловый роутинг Next.js (route-сегменты, `layout.tsx`, `page.tsx`).
|
||||
#### Папка `app/`
|
||||
|
||||
- `providers/` и `styles/` -- это инфраструктура приложения, они не являются частью роутинга.
|
||||
- Route-сегменты (вложенные папки с `page.tsx`) -- это роутинг Next.js. Они не содержат логики, только импортируют экраны из `screens/`.
|
||||
Совмещает два слоя: инициализацию приложения по FSD (провайдеры, глобальные стили) и файловый роутинг Next.js (`layout.tsx`, `page.tsx`, route-сегменты).
|
||||
|
||||
```text
|
||||
src/app/
|
||||
├── providers/ # Провайдеры приложения
|
||||
├── styles/ # Глобальные стили
|
||||
├── layout.tsx # Корневой layout
|
||||
└── page.tsx # Главная страница
|
||||
```
|
||||
|
||||
### Папка `.templates/`
|
||||
|
||||
Содержит шаблоны для генерации кода. Каждый подкаталог — шаблон отдельного типа модуля:
|
||||
|
||||
```text
|
||||
.templates/
|
||||
├── component/ # Шаблон компонента
|
||||
├── screen/ # Шаблон экрана
|
||||
├── layout/ # Шаблон layout
|
||||
├── widget/ # Шаблон виджета
|
||||
├── feature/ # Шаблон фичи
|
||||
├── entity/ # Шаблон сущности
|
||||
└── store/ # Шаблон стора
|
||||
```
|
||||
|
||||
Подробнее о генерации описано в разделе [Шаблоны и генерация кода](./templates-generation).
|
||||
|
||||
### Конфигурационные файлы
|
||||
|
||||
| Файл | Назначение |
|
||||
|---|---|
|
||||
| `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-агентов, работающих в проекте |
|
||||
|
||||
### Переменные окружения
|
||||
|
||||
- `.env` — переменные окружения проекта, запрещено коммитить
|
||||
- `.env.example` — шаблон, коммитится в репозиторий
|
||||
|
||||
Переменные с префиксом `NEXT_PUBLIC_` доступны в клиентском коде. Остальные доступны только на сервере.
|
||||
|
||||
<!-- /applied/components -->
|
||||
## Компоненты
|
||||
|
||||
Правила написания React-компонентов: файловая структура модуля, типизация пропсов, документирование и реализация. Раздел охватывает компоненты всех слоёв — от `shared/ui` до `screens`.
|
||||
|
||||
Архитектурные слои и их назначение описаны в разделе [Архитектура](/basics/architecture).
|
||||
|
||||
Компоненты, хуки, стили и утилиты не размещаются внутри route-сегментов -- всё это живёт в соответствующих слоях FSD.
|
||||
|
||||
### Правила организации
|
||||
|
||||
- В слоях FSD (`features`, `entities`, `widgets`, `screens` и т.д.) `ui/` используется только для дочерних элементов, которые относятся к модулю и не экспортируются отдельно. Главные компоненты, которые составляют сам слой, держат собственные `*.feature.tsx`, `*.widget.tsx` и т. п., а `ui/` служит для вспомогательных мелких компонентов.
|
||||
- В `shared/ui/` хранятся базовые UI-элементы/компоненты, которыми пользуются сразу несколько модулей; в этом случае они экспортируются наружу и не считаются «дочерними» для слоя.
|
||||
- Если модуль строится вокруг «главного» компонента (`*.feature.tsx`, `*.screen.tsx`, `*.widget.tsx`), помещайте его в корень модуля и экспортируйте через `index.ts`. Проверяйте, что `ui/` не используется просто как «контейнер» слоя.
|
||||
- Каждый слой и модуль хранится в собственной папке.
|
||||
- Внутренние реализации разделяются на `ui/`, `model/`, `styles/`, `helpers/`, `lib/`, `api/`.
|
||||
- Публичный API модуля объявляется в `index.ts`.
|
||||
- Внутренние файлы не импортируются напрямую извне.
|
||||
- Не смешивать ответственность разных слоёв в одном модуле.
|
||||
|
||||
### Пример организации структуры
|
||||
|
||||
**Плохо** -- плоская структура без архитектуры:
|
||||
```text
|
||||
src/
|
||||
├── components/
|
||||
│ ├── Header.tsx
|
||||
│ ├── LoginForm.tsx
|
||||
│ ├── UserCard.tsx
|
||||
│ └── Button.tsx
|
||||
├── hooks/
|
||||
│ ├── useAuth.ts
|
||||
│ └── useUser.ts
|
||||
├── api/
|
||||
│ ├── auth.ts
|
||||
│ └── user.ts
|
||||
├── styles/
|
||||
│ ├── header.module.css
|
||||
│ └── login.module.css
|
||||
├── types/
|
||||
│ └── user.ts
|
||||
└── utils/
|
||||
└── format.ts
|
||||
```
|
||||
|
||||
Нет слоёв, нет границ ответственности -- Header и Button лежат рядом, хотя это разные уровни абстракции. LoginForm знает про API напрямую. При росте проекта `components/` превращается в свалку.
|
||||
|
||||
**Хорошо** -- та же функциональность в FSD:
|
||||
```text
|
||||
src/
|
||||
├── widgets/
|
||||
│ └── header/
|
||||
│ ├── header.widget.tsx
|
||||
│ └── index.ts
|
||||
├── features/
|
||||
│ └── auth-by-email/
|
||||
│ ├── ui/
|
||||
│ │ └── login-form.tsx
|
||||
│ ├── model/
|
||||
│ │ └── auth.store.ts
|
||||
│ ├── auth-by-email.feature.tsx
|
||||
│ └── index.ts
|
||||
├── entities/
|
||||
│ └── user/
|
||||
│ ├── ui/
|
||||
│ │ └── user-card.tsx
|
||||
│ ├── model/
|
||||
│ │ └── user.store.ts
|
||||
│ ├── user.entity.tsx
|
||||
│ └── index.ts
|
||||
└── shared/
|
||||
├── ui/
|
||||
│ └── button/
|
||||
│ ├── button.tsx
|
||||
│ └── index.ts
|
||||
└── lib/
|
||||
└── format.ts
|
||||
```
|
||||
|
||||
Каждый элемент на своём слое, с публичным API и чёткими границами ответственности.
|
||||
|
||||
<!-- /applied/components -->
|
||||
## UI и компоненты
|
||||
|
||||
Раздел описывает правила создания UI‑компонентов. Эти правила обязательны для всех слоёв FSD: `app`, `screens`, `layouts`, `widgets`, `features`, `entities`, `shared`.
|
||||
1. Один компонент — один файл.
|
||||
2. Компонент не содержит бизнес-логики — логика и сайд-эффекты выносятся в хуки или сторы.
|
||||
3. Дочерние компоненты размещаются в сегменте `ui/` и подчиняются тем же правилам структуры.
|
||||
4. Публичный API модуля — только `index.ts`. Прямые импорты внутренних файлов запрещены.
|
||||
|
||||
### Базовая структура компонента
|
||||
|
||||
@@ -943,26 +850,48 @@ container/
|
||||
└── index.ts
|
||||
```
|
||||
|
||||
### Пример базового компонента
|
||||
### Именования
|
||||
|
||||
`styles/container.module.css`
|
||||
```scss
|
||||
.root {}
|
||||
```
|
||||
В CSS Modules использование имени класса **.root** — это общепринятое соглашение (best practice)
|
||||
- Имя корневого css класса всегда `.root`
|
||||
- Интерфейс именуется `{ComponentName}Props`.
|
||||
|
||||
### Типизация
|
||||
|
||||
- Компонент типизируется через `FC<Props>`.
|
||||
- Интерфейс пропсов наследует HTML-атрибуты своего корневого элемента.
|
||||
- `children` отдельно не объявляется — приходит из `HTMLAttributes`.
|
||||
|
||||
### Реализация
|
||||
|
||||
- Пропсы деструктурируются в теле компонента, не в параметрах.
|
||||
- Порядок: пользовательские → системные (`children`, `className`) → `...htmlAttr`.
|
||||
- `className` объединяется с корневым классом через `cl()`: `cl(styles.root, className)`.
|
||||
- `...htmlAttr` прокидывается на корневой элемент.
|
||||
|
||||
### Пример
|
||||
|
||||
`container/types/container.interface.ts`
|
||||
|
||||
`types/container.interface.ts`
|
||||
```ts
|
||||
import type { HTMLAttributes } from 'react'
|
||||
|
||||
/**
|
||||
* Параметры контейнера.
|
||||
* Параметры компонента Container.
|
||||
*/
|
||||
export interface ContainerProps extends HTMLAttributes<HTMLDivElement> {}
|
||||
```
|
||||
Интерфес параметров компонента всегда наследует свойства своего тега: div, button, итд..
|
||||
|
||||
`container.tsx`
|
||||
`container/styles/container.module.css`
|
||||
|
||||
```css
|
||||
.root {
|
||||
max-width: var(--content-width);
|
||||
margin: 0 auto;
|
||||
padding: 0 var(--spacing-4);
|
||||
}
|
||||
```
|
||||
|
||||
`container/container.tsx`
|
||||
|
||||
```tsx
|
||||
import type { FC } from 'react'
|
||||
@@ -974,43 +903,26 @@ import styles from './styles/container.module.css'
|
||||
* Контейнер с адаптивной максимальной шириной.
|
||||
*
|
||||
* Используется для:
|
||||
* - ограничения ширины контента
|
||||
* - центрирования содержимого
|
||||
* - построения адаптивной сетки страницы
|
||||
* - обёртки контента страниц с ограничением ширины
|
||||
* - центрирования блоков в лейауте
|
||||
*/
|
||||
export const Container: FC<ContainerProps> = ({ className, ...htmlAttr }) => {
|
||||
export const Container: FC<ContainerProps> = (props) => {
|
||||
const { children, className, ...htmlAttr } = props
|
||||
|
||||
return (
|
||||
<div {...htmlAttr} className={cl(styles.root, className)}>
|
||||
Container...
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
- Компонент объявляется через `const` и экспортируется именованно.
|
||||
- Пропсы деструктурируются в сигнатуре; если их больше двух — деструктуризацию переносим в тело компонента.
|
||||
- Из пропсов отдельно извлекаются `className` и `...htmlAttr`, чтобы корректно объединять классы и прокидывать остальные атрибуты.
|
||||
- `cl` — короткое имя функции для конкатенации CSS‑классов.
|
||||
- `FC<>` используется для декларации `children`.
|
||||
|
||||
`index.ts`
|
||||
`container/index.ts`
|
||||
|
||||
```ts
|
||||
export { Container } from './container'
|
||||
```
|
||||
|
||||
### Шаблоны и генерация кода
|
||||
|
||||
Создание компонентов — **только через шаблоны**. Ручное создание файловой структуры компонента запрещено. Это обеспечивает единообразие каркаса, одинаковые папки и имена файлов, уменьшает ручные ошибки и ускоряет старт работы.
|
||||
|
||||
После генерации через **@gromlab/create** — проверить название компонента/файлов и заполнить описание назначения. Подробный порядок действий и перечень обязательных шаблонов — в разделе «Workflow».
|
||||
|
||||
### Вложенные (дочерние) компоненты
|
||||
|
||||
Если для реализации функционала нужны компоненты, которые используются только внутри текущего компонента, создавайте их как вложенные в папке `ui/`. Такие компоненты не экспортируются наружу и используются только локально.
|
||||
|
||||
Вложенные компоненты подчиняются тем же правилам по структуре, именованию и стилю (включая папку `styles/` для их стилей).
|
||||
|
||||
<!-- /applied/page-level -->
|
||||
## Страницы (App Router)
|
||||
|
||||
@@ -1295,10 +1207,12 @@ import styles from './styles/{{name.kebabCase}}.module.css'
|
||||
/**
|
||||
* {{name.pascalCase}}.
|
||||
*/
|
||||
export const {{name.pascalCase}}: FC<{{name.pascalCase}}Props> = ({ className, ...htmlAttr }) => {
|
||||
export const {{name.pascalCase}}: FC<{{name.pascalCase}}Props> = (props) => {
|
||||
const { children, className, ...htmlAttr } = props
|
||||
|
||||
return (
|
||||
<div {...htmlAttr} className={cl(styles.root, className)}>
|
||||
{{name.kebabCase}}
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1607,3 +1521,88 @@ npx @gromlab/create <шаблон> <имя> <путь>
|
||||
|
||||
<!-- /applied/svg-sprites -->
|
||||
## 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` с общими для команды настройками.
|
||||
Reference in New Issue
Block a user