docs: обновить прикладные разделы
- обновлён порядок и состав прикладных разделов - добавлены разделы про компоненты, изображения, шрифты и локализацию - уточнены правила модулей, страниц, сегментов и именования - удалены устаревшие пустые разделы и обзор документации
This commit is contained in:
@@ -70,10 +70,10 @@ const sidebar = [
|
|||||||
{
|
{
|
||||||
text: 'Прикладные разделы',
|
text: 'Прикладные разделы',
|
||||||
items: [
|
items: [
|
||||||
{ text: 'Алиасы импортов', link: '/docs/applied/aliases' },
|
{ text: 'Структура проекта', link: '/docs/applied/project-structure' },
|
||||||
{ text: 'Biome', link: '/docs/applied/biome' },
|
{ text: 'Страницы', link: '/docs/applied/page-level' },
|
||||||
{ text: 'PostCSS', link: '/docs/applied/postcss' },
|
{ text: 'Компонент', link: '/docs/applied/component' },
|
||||||
{ text: 'VS Code', link: '/docs/applied/vscode' },
|
{ text: 'Модуль', link: '/docs/applied/module' },
|
||||||
{
|
{
|
||||||
text: 'Стили',
|
text: 'Стили',
|
||||||
collapsed: true,
|
collapsed: true,
|
||||||
@@ -91,6 +91,9 @@ const sidebar = [
|
|||||||
{ text: 'Использование', link: '/docs/applied/svg-sprites/svg-sprites-usage' },
|
{ text: 'Использование', link: '/docs/applied/svg-sprites/svg-sprites-usage' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{ text: 'Изображения', link: '/docs/applied/images' },
|
||||||
|
{ text: 'Шрифты', link: '/docs/applied/fonts' },
|
||||||
|
{ text: 'Алиасы импортов', link: '/docs/applied/aliases' },
|
||||||
{
|
{
|
||||||
text: 'Шаблоны генерации',
|
text: 'Шаблоны генерации',
|
||||||
collapsed: true,
|
collapsed: true,
|
||||||
@@ -101,18 +104,13 @@ const sidebar = [
|
|||||||
{ text: 'Использование', link: '/docs/applied/templates/templates-usage' },
|
{ text: 'Использование', link: '/docs/applied/templates/templates-usage' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{ text: 'Структура проекта', link: '/docs/applied/project-structure' },
|
{ text: 'Biome', link: '/docs/applied/biome' },
|
||||||
{ text: 'Модуль', link: '/docs/applied/module' },
|
{ text: 'PostCSS', link: '/docs/applied/postcss' },
|
||||||
{ text: 'Компонент · в разработке' },
|
{ text: 'VS Code', link: '/docs/applied/vscode' },
|
||||||
{ text: 'Страницы (App Router)', link: '/docs/applied/page-level' },
|
{ text: 'Локализация', link: '/docs/applied/localization' },
|
||||||
// Неактивные разделы: страницы существуют, но пока пустые.
|
// Неактивные разделы: страницы существуют, но пока пустые.
|
||||||
// Оставляем в sidebar без `link`, чтобы видеть план, но без перехода.
|
// Оставляем в sidebar без `link`, чтобы видеть план, но без перехода.
|
||||||
{ text: 'Изображения · в разработке' },
|
{ text: 'Stores · в разработке' }
|
||||||
{ text: 'Видео · в разработке' },
|
|
||||||
{ text: 'Stores · в разработке' },
|
|
||||||
{ text: 'Хуки · в разработке' },
|
|
||||||
{ text: 'Шрифты · в разработке' },
|
|
||||||
{ text: 'Локализация · в разработке' }
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -37,30 +37,35 @@ docs/
|
|||||||
│ ├── from-template.md
|
│ ├── from-template.md
|
||||||
│ ├── manual.md
|
│ ├── manual.md
|
||||||
│ └── nextjs.md
|
│ └── nextjs.md
|
||||||
|
├── data/ # Работа с данными
|
||||||
|
│ ├── index.md
|
||||||
|
│ ├── realtime.md
|
||||||
|
│ └── rest/
|
||||||
└── applied/ # Прикладные разделы: настройка и использование
|
└── applied/ # Прикладные разделы: настройка и использование
|
||||||
├── aliases.md
|
├── project-structure.md
|
||||||
├── biome.md
|
├── page-level.md
|
||||||
├── postcss.md
|
├── component.md
|
||||||
├── vscode.md
|
├── module.md
|
||||||
├── styles/ # Стили: настройка + использование
|
├── styles/ # Стили: настройка + использование
|
||||||
│ ├── styles-setup.md
|
│ ├── styles-setup.md
|
||||||
│ └── styles-usage.md
|
│ └── styles-usage.md
|
||||||
├── svg-sprites/ # SVG-спрайты: настройка + использование
|
├── svg-sprites/ # SVG-спрайты: введение + настройка + использование
|
||||||
|
│ ├── svg-sprites-intro.md
|
||||||
│ ├── svg-sprites-setup.md
|
│ ├── svg-sprites-setup.md
|
||||||
│ └── svg-sprites-usage.md
|
│ └── svg-sprites-usage.md
|
||||||
├── templates/ # Шаблоны генерации: настройка + использование
|
├── images.md
|
||||||
│ ├── templates-setup.md
|
|
||||||
│ └── templates-usage.md
|
|
||||||
├── project-structure.md
|
|
||||||
├── components.md
|
|
||||||
├── page-level.md
|
|
||||||
├── images-sprites.md
|
|
||||||
├── video.md
|
|
||||||
├── data/
|
|
||||||
├── stores.md
|
|
||||||
├── hooks.md
|
|
||||||
├── fonts.md
|
├── fonts.md
|
||||||
└── localization.md
|
├── aliases.md
|
||||||
|
├── templates/ # Шаблоны генерации: введение + настройка + использование
|
||||||
|
│ ├── templates-intro.md
|
||||||
|
│ ├── templates-setup.md
|
||||||
|
│ ├── templates-create.md
|
||||||
|
│ └── templates-usage.md
|
||||||
|
├── biome.md
|
||||||
|
├── postcss.md
|
||||||
|
├── vscode.md
|
||||||
|
├── localization.md
|
||||||
|
└── stores.md
|
||||||
.vitepress/
|
.vitepress/
|
||||||
└── config.ts # Конфигурация VitePress, сайдбар
|
└── config.ts # Конфигурация VitePress, сайдбар
|
||||||
generate-llms.ts # Скрипт генерации llms.txt и README
|
generate-llms.ts # Скрипт генерации llms.txt и README
|
||||||
|
|||||||
174
docs-overview.md
174
docs-overview.md
@@ -1,174 +0,0 @@
|
|||||||
# Обзор страниц документации
|
|
||||||
|
|
||||||
Список всех `.md`-страниц в `docs/docs/` в порядке сайдбара (`.vitepress/config.ts`).
|
|
||||||
Поля: путь к файлу, заголовок (`h1`), описание (абзац под заголовком).
|
|
||||||
|
|
||||||
## Главная
|
|
||||||
|
|
||||||
### docs/docs/index.md
|
|
||||||
**Заголовок:** NextJS Style Guide
|
|
||||||
**Описание:** Стандарты разработки фронтенд-приложений на Next.js и TypeScript.
|
|
||||||
|
|
||||||
## Подсказки
|
|
||||||
|
|
||||||
### docs/docs/workflow.md
|
|
||||||
**Заголовок:** Подсказки
|
|
||||||
**Описание:** Короткие ответы на типовые вопросы и решения для спорных ситуаций.
|
|
||||||
|
|
||||||
## Базовые правила
|
|
||||||
|
|
||||||
### docs/docs/basics/tech-stack.md
|
|
||||||
**Заголовок:** Технологии и библиотеки
|
|
||||||
**Описание:** Какие библиотеки и инструменты используются в проекте.
|
|
||||||
|
|
||||||
### docs/docs/basics/naming.md
|
|
||||||
**Заголовок:** Именование
|
|
||||||
**Описание:** Как называть переменные, файлы и прочие сущности в коде.
|
|
||||||
|
|
||||||
### docs/docs/basics/architecture/index.md
|
|
||||||
**Заголовок:** SLM Design
|
|
||||||
**Описание:** Архитектурный подход проекта: что такое SLM и как он устроен.
|
|
||||||
|
|
||||||
### docs/docs/basics/architecture/reference/layers.md
|
|
||||||
**Заголовок:** Слои SLM
|
|
||||||
**Описание:** Из каких слоёв состоит SLM-архитектура и как они связаны.
|
|
||||||
|
|
||||||
### docs/docs/basics/architecture/reference/modules.md
|
|
||||||
**Заголовок:** Модули SLM
|
|
||||||
**Описание:** Что такое модуль в SLM-архитектуре и как он устроен.
|
|
||||||
|
|
||||||
### docs/docs/basics/architecture/reference/segments.md
|
|
||||||
**Заголовок:** Сегменты SLM
|
|
||||||
**Описание:** Что такое сегмент модуля в SLM-архитектуре и какие они бывают.
|
|
||||||
|
|
||||||
### docs/docs/basics/code-style.md
|
|
||||||
**Заголовок:** Стиль кода
|
|
||||||
**Описание:** Как оформляется код в проекте.
|
|
||||||
|
|
||||||
### docs/docs/basics/documentation.md
|
|
||||||
**Заголовок:** Документирование
|
|
||||||
**Описание:** Что и как документировать в коде.
|
|
||||||
|
|
||||||
### docs/docs/basics/typing.md
|
|
||||||
**Заголовок:** Типизация
|
|
||||||
**Описание:** Как типизируется код в проекте.
|
|
||||||
|
|
||||||
## Создание проекта
|
|
||||||
|
|
||||||
### docs/docs/creating-project/from-template.md
|
|
||||||
**Заголовок:** Создание проекта из шаблона
|
|
||||||
**Описание:** Создание нового проекта на основе готового шаблона.
|
|
||||||
|
|
||||||
### docs/docs/creating-project/manual.md
|
|
||||||
**Заголовок:** Создание проекта вручную
|
|
||||||
**Описание:** Поэтапное создание нового проекта без использования шаблона.
|
|
||||||
|
|
||||||
### docs/docs/creating-project/nextjs.md
|
|
||||||
**Заголовок:** Чистая установка Next.js
|
|
||||||
**Описание:** Установка Next.js без лишнего шаблона — голый каркас под дальнейшую сборку.
|
|
||||||
|
|
||||||
## Настройка
|
|
||||||
|
|
||||||
### docs/docs/setup/aliases.md
|
|
||||||
**Заголовок:** Алиасы импортов
|
|
||||||
**Описание:** Какие алиасы импортов есть в проекте и как ими пользоваться.
|
|
||||||
|
|
||||||
### docs/docs/setup/biome.md
|
|
||||||
**Заголовок:** Biome
|
|
||||||
**Описание:** Установка и настройка линтера-форматтера в новом проекте.
|
|
||||||
|
|
||||||
### docs/docs/setup/postcss.md
|
|
||||||
**Заголовок:** PostCSS
|
|
||||||
**Описание:** Установка и настройка CSS-процессора в новом проекте.
|
|
||||||
|
|
||||||
### docs/docs/setup/styles.md
|
|
||||||
**Заголовок:** Стили
|
|
||||||
**Описание:** Подготовка стилевой основы проекта: токены, медиа-запросы, глобальные стили.
|
|
||||||
|
|
||||||
### docs/docs/setup/svg-sprites.md
|
|
||||||
**Заголовок:** SVG-спрайты
|
|
||||||
**Описание:** Подключение SVG-спрайтов в новом проекте.
|
|
||||||
|
|
||||||
### docs/docs/setup/templates.md
|
|
||||||
**Заголовок:** Шаблоны генерации
|
|
||||||
**Описание:** Подключение шаблонов кодогенерации в новом проекте.
|
|
||||||
|
|
||||||
### docs/docs/setup/vscode.md
|
|
||||||
**Заголовок:** VS Code
|
|
||||||
**Описание:** Единые настройки редактора и расширений для команды.
|
|
||||||
|
|
||||||
## Использование
|
|
||||||
|
|
||||||
### docs/docs/usage/project-structure.md
|
|
||||||
**Заголовок:** Структура проекта
|
|
||||||
**Описание:** Из чего состоит проект и где что лежит.
|
|
||||||
|
|
||||||
### docs/docs/usage/components.md
|
|
||||||
**Заголовок:** Компоненты
|
|
||||||
**Описание:** Как устроен и пишется React-компонент в проекте.
|
|
||||||
|
|
||||||
### docs/docs/usage/page-level.md
|
|
||||||
**Заголовок:** Файлы роутинга
|
|
||||||
**Описание:** Что должно лежать в файлах роутинга, а что — в экранах.
|
|
||||||
|
|
||||||
### docs/docs/usage/templates-generation.md
|
|
||||||
**Заголовок:** Шаблоны и генерация кода
|
|
||||||
**Описание:** Как устроены шаблоны кодогенерации и как ими пользоваться.
|
|
||||||
|
|
||||||
### docs/docs/usage/styles.md
|
|
||||||
**Заголовок:** Стили
|
|
||||||
**Описание:** Как пишутся стили в проекте.
|
|
||||||
|
|
||||||
### docs/docs/usage/images-sprites.md
|
|
||||||
**Заголовок:** —
|
|
||||||
**Описание:** _(файл пустой)_
|
|
||||||
|
|
||||||
### docs/docs/usage/svg-sprites.md
|
|
||||||
**Заголовок:** SVG-спрайты
|
|
||||||
**Описание:** Как добавлять и использовать SVG-иконки в коде.
|
|
||||||
|
|
||||||
### docs/docs/usage/video.md
|
|
||||||
**Заголовок:** —
|
|
||||||
**Описание:** _(файл пустой)_
|
|
||||||
|
|
||||||
### docs/docs/usage/stores.md
|
|
||||||
**Заголовок:** —
|
|
||||||
**Описание:** _(файл пустой)_
|
|
||||||
|
|
||||||
### docs/docs/usage/hooks.md
|
|
||||||
**Заголовок:** —
|
|
||||||
**Описание:** _(файл пустой)_
|
|
||||||
|
|
||||||
### docs/docs/usage/fonts.md
|
|
||||||
**Заголовок:** —
|
|
||||||
**Описание:** _(файл пустой)_
|
|
||||||
|
|
||||||
### docs/docs/usage/localization.md
|
|
||||||
**Заголовок:** —
|
|
||||||
**Описание:** _(файл пустой)_
|
|
||||||
|
|
||||||
## Данные
|
|
||||||
|
|
||||||
### docs/docs/usage/data/index.md
|
|
||||||
**Заголовок:** Источники данных
|
|
||||||
**Описание:** Какие источники данных используются в проекте и как с ними работать.
|
|
||||||
|
|
||||||
### docs/docs/usage/data/rest/clients/auto.md
|
|
||||||
**Заголовок:** Автогенерация REST-клиента
|
|
||||||
**Описание:** Генерация REST-клиента из OpenAPI-спецификации.
|
|
||||||
|
|
||||||
### docs/docs/usage/data/rest/clients/manual.md
|
|
||||||
**Заголовок:** Ручное создание REST-клиента
|
|
||||||
**Описание:** Создание REST-клиента вручную, когда нет OpenAPI-спецификации.
|
|
||||||
|
|
||||||
### docs/docs/usage/data/rest/fetching/server.md
|
|
||||||
**Заголовок:** Серверные компоненты
|
|
||||||
**Описание:** Получение REST-данных в серверных компонентах.
|
|
||||||
|
|
||||||
### docs/docs/usage/data/rest/fetching/client.md
|
|
||||||
**Заголовок:** Клиентские компоненты
|
|
||||||
**Описание:** Получение REST-данных в клиентских компонентах.
|
|
||||||
|
|
||||||
### docs/docs/usage/data/realtime.md
|
|
||||||
**Заголовок:** Realtime
|
|
||||||
**Описание:** Работа с push-данными от сервера: подписки и события.
|
|
||||||
@@ -36,19 +36,23 @@
|
|||||||
|
|
||||||
## Прикладные разделы
|
## Прикладные разделы
|
||||||
|
|
||||||
- [Алиасы импортов](./applied/aliases.md) — Какие алиасы импортов есть в проекте и как ими пользоваться.
|
- [Структура проекта](./applied/project-structure.md) — Из чего состоит проект и где что лежит.
|
||||||
- [Biome](./applied/biome.md) — Установка и настройка линтера-форматтера в новом проекте.
|
- [Страницы](./applied/page-level.md) — Как работать со страницами и другими файлами роутинга Next.js App Router.
|
||||||
- [PostCSS](./applied/postcss.md) — Установка и настройка CSS-процессора в новом проекте.
|
- [Компонент](./applied/component.md) — Как создавать React-компоненты внутри SLM-модулей.
|
||||||
- [VS Code](./applied/vscode.md) — Единые настройки редактора и расширений для команды.
|
- [Модуль](./applied/module.md) — Как создавать и организовывать SLM-модули в проекте.
|
||||||
- [Стили: Настройка](./applied/styles/styles-setup.md) — Подготовка стилевой основы проекта: токены, медиа-запросы, глобальные стили.
|
- [Стили: Настройка](./applied/styles/styles-setup.md) — Подготовка стилевой основы проекта: токены, медиа-запросы, глобальные стили.
|
||||||
- [Стили: Использование](./applied/styles/styles-usage.md) — Как пишутся стили в проекте.
|
- [Стили: Использование](./applied/styles/styles-usage.md) — Как пишутся стили в проекте.
|
||||||
- [SVG-спрайты](./applied/svg-sprites/svg-sprites-intro.md) — Что такое SVG-спрайты и какие проблемы они решают.
|
- [SVG-спрайты](./applied/svg-sprites/svg-sprites-intro.md) — Что такое SVG-спрайты и какие проблемы они решают.
|
||||||
- [SVG-спрайты: Настройка](./applied/svg-sprites/svg-sprites-setup.md) — Подключение SVG-спрайтов в новом проекте.
|
- [SVG-спрайты: Настройка](./applied/svg-sprites/svg-sprites-setup.md) — Подключение SVG-спрайтов в новом проекте.
|
||||||
- [SVG-спрайты: Использование](./applied/svg-sprites/svg-sprites-usage.md) — Как добавлять и использовать SVG-иконки в коде.
|
- [SVG-спрайты: Использование](./applied/svg-sprites/svg-sprites-usage.md) — Как добавлять и использовать SVG-иконки в коде.
|
||||||
|
- [Изображения](./applied/images.md) — Как подключать изображения через Next.js Image в проекте.
|
||||||
|
- [Шрифты](./applied/fonts.md) — Как подключать шрифты через Next.js Font в проекте.
|
||||||
|
- [Алиасы импортов](./applied/aliases.md) — Какие алиасы импортов есть в проекте и как ими пользоваться.
|
||||||
- [Шаблоны генерации](./applied/templates/templates-intro.md) — Что такое шаблоны кодогенерации и какие проблемы они решают.
|
- [Шаблоны генерации](./applied/templates/templates-intro.md) — Что такое шаблоны кодогенерации и какие проблемы они решают.
|
||||||
- [Шаблоны генерации: Настройка](./applied/templates/templates-setup.md) — Первичная установка шаблонов кодогенерации в проект.
|
- [Шаблоны генерации: Настройка](./applied/templates/templates-setup.md) — Первичная установка шаблонов кодогенерации в проект.
|
||||||
- [Шаблоны генерации: Создание шаблонов](./applied/templates/templates-create.md) — Структура шаблонов, синтаксис переменных и примеры.
|
- [Шаблоны генерации: Создание шаблонов](./applied/templates/templates-create.md) — Структура шаблонов, синтаксис переменных и примеры.
|
||||||
- [Шаблоны генерации: Использование](./applied/templates/templates-usage.md) — Генерация файлов из шаблонов через VS Code плагин и CLI.
|
- [Шаблоны генерации: Использование](./applied/templates/templates-usage.md) — Генерация файлов из шаблонов через VS Code плагин и CLI.
|
||||||
- [Структура проекта](./applied/project-structure.md) — Из чего состоит проект и где что лежит.
|
- [Biome](./applied/biome.md) — Установка и настройка линтера-форматтера в новом проекте.
|
||||||
- [Модуль](./applied/module.md) — Как устроен и пишется React-компонент в проекте.
|
- [PostCSS](./applied/postcss.md) — Установка и настройка CSS-процессора в новом проекте.
|
||||||
- [Страницы (App Router)](./applied/page-level.md) — Что должно лежать в файлах роутинга, а что — в экранах.
|
- [VS Code](./applied/vscode.md) — Единые настройки редактора и расширений для команды.
|
||||||
|
- [Локализация](./applied/localization.md) — Как организовать локализацию как infrastructure-модуль.
|
||||||
|
|||||||
@@ -1,4 +1,201 @@
|
|||||||
---
|
---
|
||||||
title: Компонент
|
title: Компонент
|
||||||
description: Как устроен и пишется React-компонент в проекте.
|
description: Как создавать React-компоненты внутри SLM-модулей.
|
||||||
---
|
---
|
||||||
|
|
||||||
|
# Компонент
|
||||||
|
|
||||||
|
Как создавать React-компоненты внутри SLM-модулей.
|
||||||
|
|
||||||
|
## Назначение
|
||||||
|
|
||||||
|
Компонент — минимальная UI-единица проекта. Это один `.tsx` файл без собственной папки, сегментов и публичного API.
|
||||||
|
|
||||||
|
Компонент может использовать стили, типы, хуки и другие ресурсы родительского модуля. Наличие связанных файлов в `styles/` или `types/` не превращает компонент в модуль.
|
||||||
|
|
||||||
|
## Компонент или модуль
|
||||||
|
|
||||||
|
Классификация определяется границей владения:
|
||||||
|
|
||||||
|
- `component` — один `.tsx` файл внутри модуля;
|
||||||
|
- `module` — папка с `index.ts`, сегментами и собственной публичной границей.
|
||||||
|
|
||||||
|
```text
|
||||||
|
user/
|
||||||
|
├── ui/
|
||||||
|
│ └── user-avatar.tsx # компонент
|
||||||
|
├── styles/
|
||||||
|
│ └── user-avatar.module.css # ресурс родительского модуля
|
||||||
|
├── types/
|
||||||
|
│ └── user-avatar.type.ts # ресурс родительского модуля
|
||||||
|
└── user.tsx # корневой компонент модуля
|
||||||
|
```
|
||||||
|
|
||||||
|
`user-avatar.tsx` остаётся компонентом, потому что у него нет собственной папки, `index.ts` и сегментов.
|
||||||
|
|
||||||
|
## Где размещать
|
||||||
|
|
||||||
|
Компонент размещается внутри модуля:
|
||||||
|
|
||||||
|
- В корне модуля, если это главная UI-сущность модуля.
|
||||||
|
- В `ui/`, если это вспомогательный компонент модуля.
|
||||||
|
|
||||||
|
```text
|
||||||
|
user/
|
||||||
|
├── ui/
|
||||||
|
│ └── user-avatar.tsx
|
||||||
|
├── styles/
|
||||||
|
│ ├── user.module.css
|
||||||
|
│ └── user-avatar.module.css
|
||||||
|
├── types/
|
||||||
|
│ ├── user.type.ts
|
||||||
|
│ └── user-avatar.type.ts
|
||||||
|
├── user.tsx
|
||||||
|
└── index.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
`user.tsx` — корневой компонент модуля. `ui/user-avatar.tsx` — вспомогательный компонент этого же модуля.
|
||||||
|
|
||||||
|
## Что запрещено
|
||||||
|
|
||||||
|
- Заворачивать компонент в папку: `ui/header/header.tsx`.
|
||||||
|
- Создавать для компонента отдельный `index.ts`.
|
||||||
|
- Создавать собственные сегменты внутри папки компонента: `ui/header/styles/`, `ui/header/types/`, `ui/header/hooks/` и т.п.
|
||||||
|
- Декларировать внутри `.tsx` сторы, сервисы, API-клиенты, мапперы или утилиты. Для этого есть сегменты родительского модуля.
|
||||||
|
- Размещать бизнес-правила прямо в компоненте. Компонент может использовать готовые зависимости модуля, но не определяет их.
|
||||||
|
- Размещать компонент в `parts/` напрямую. `parts/` содержит только модули.
|
||||||
|
|
||||||
|
**Плохо**
|
||||||
|
|
||||||
|
```text
|
||||||
|
user/
|
||||||
|
└── ui/
|
||||||
|
└── user-avatar/
|
||||||
|
├── styles/
|
||||||
|
│ └── user-avatar.module.css
|
||||||
|
├── user-avatar.tsx
|
||||||
|
└── index.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
**Хорошо**
|
||||||
|
|
||||||
|
```text
|
||||||
|
user/
|
||||||
|
├── ui/
|
||||||
|
│ └── user-avatar.tsx
|
||||||
|
├── styles/
|
||||||
|
│ └── user-avatar.module.css
|
||||||
|
└── types/
|
||||||
|
└── user-avatar.type.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
## Стили и типы
|
||||||
|
|
||||||
|
Компонент использует ресурсы родительского модуля.
|
||||||
|
|
||||||
|
`styles/` и `types/` рядом с корневым компонентом — это сегменты модуля, а не собственные папки `.tsx` файла.
|
||||||
|
|
||||||
|
- CSS Module компонента лежит в `styles/` родительского модуля и называется по компоненту: `user-avatar.module.css`.
|
||||||
|
- Если у компонента есть CSS Module, его корневой класс всегда называется `.root`.
|
||||||
|
- Типы компонента лежат в `types/` родительского модуля и называются по компоненту: `user-avatar.type.ts`.
|
||||||
|
- Локальный `type Props` внутри `.tsx` не используется. Типы пропсов всегда выносятся в `types/` родительского модуля.
|
||||||
|
- Экспорт типа из `types/` не делает его публичным API. Публичным он становится только при реэкспорте из `index.ts` модуля.
|
||||||
|
|
||||||
|
Причина `.root`: в DevTools проще находить корневой DOM-узел компонента и отличать его от внутренних элементов.
|
||||||
|
|
||||||
|
## Реализация
|
||||||
|
|
||||||
|
- Компоненты объявляются через `const`.
|
||||||
|
- `React.FC` не используется.
|
||||||
|
- JSDoc-комментарий обязателен для компонента.
|
||||||
|
- Пропсы деструктурируются в теле компонента.
|
||||||
|
- `className` объединяется с `styles.root` через `cl()`.
|
||||||
|
- Побочные эффекты и состояние выносятся в хуки модуля, если перестают быть тривиальными.
|
||||||
|
- Компонент возвращает JSX и не содержит orchestration-код страницы или бизнес-домена.
|
||||||
|
|
||||||
|
`user/types/user-avatar.type.ts`
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import type { ImageProps } from 'next/image'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Параметры UserAvatar.
|
||||||
|
*/
|
||||||
|
export type UserAvatarParams = {}
|
||||||
|
|
||||||
|
/** Пропсы базового изображения. */
|
||||||
|
type RootAttrs = ImageProps
|
||||||
|
|
||||||
|
export type UserAvatarProps = RootAttrs & UserAvatarParams
|
||||||
|
```
|
||||||
|
|
||||||
|
`user/ui/user-avatar.tsx`
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import cl from 'clsx'
|
||||||
|
import Image from 'next/image'
|
||||||
|
import type { UserAvatarProps } from '../types/user-avatar.type'
|
||||||
|
import styles from '../styles/user-avatar.module.css'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Аватар пользователя.
|
||||||
|
*
|
||||||
|
* Используется для:
|
||||||
|
* - отображения пользователя в карточке
|
||||||
|
* - отображения пользователя в шапке профиля
|
||||||
|
*/
|
||||||
|
export const UserAvatar = (props: UserAvatarProps) => {
|
||||||
|
const { className, ...imageProps } = props
|
||||||
|
|
||||||
|
return <Image {...imageProps} className={cl(styles.root, className)} />
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`user/styles/user-avatar.module.css`
|
||||||
|
|
||||||
|
```css
|
||||||
|
.root {
|
||||||
|
display: block;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Когда нужен модуль
|
||||||
|
|
||||||
|
Решение о выделении модуля остаётся за разработчиком. Поднимать компонент в модуль стоит, если он становится самостоятельной областью:
|
||||||
|
|
||||||
|
- получает свои вложенные компоненты;
|
||||||
|
- получает свои хуки, стор или сервисы;
|
||||||
|
- получает внутренние мапперы или утилиты;
|
||||||
|
- требует собственного публичного API;
|
||||||
|
- начинает переиспользоваться вне родительского модуля;
|
||||||
|
- становится отдельной зоной параллельной разработки.
|
||||||
|
|
||||||
|
Пример: страница — это screen-модуль, а самостоятельные секции страницы — вложенные модули в `parts/`.
|
||||||
|
|
||||||
|
```text
|
||||||
|
screens/home/
|
||||||
|
├── parts/
|
||||||
|
│ ├── hero-section/
|
||||||
|
│ │ ├── styles/
|
||||||
|
│ │ │ └── hero-section.module.css
|
||||||
|
│ │ ├── types/
|
||||||
|
│ │ │ └── hero-section.type.ts
|
||||||
|
│ │ ├── hero-section.tsx
|
||||||
|
│ │ └── index.ts
|
||||||
|
│ └── features-section/
|
||||||
|
│ ├── styles/
|
||||||
|
│ │ └── features-section.module.css
|
||||||
|
│ ├── types/
|
||||||
|
│ │ └── features-section.type.ts
|
||||||
|
│ ├── features-section.tsx
|
||||||
|
│ └── index.ts
|
||||||
|
├── styles/
|
||||||
|
│ └── home.module.css
|
||||||
|
├── types/
|
||||||
|
│ └── home.type.ts
|
||||||
|
├── home.screen.tsx
|
||||||
|
└── index.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
`hero-section` и `features-section` — модули, потому что это самостоятельные части страницы со своей структурой и публичной точкой входа.
|
||||||
|
|||||||
@@ -0,0 +1,128 @@
|
|||||||
|
---
|
||||||
|
title: Шрифты
|
||||||
|
description: Как подключать шрифты через Next.js Font в проекте.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Шрифты
|
||||||
|
|
||||||
|
Как подключать шрифты через Next.js Font в проекте.
|
||||||
|
|
||||||
|
## Назначение
|
||||||
|
|
||||||
|
Шрифты подключаются через `next/font`. Это стандартный способ Next.js: шрифты загружаются без ручных `<link>`, `@font-face` и настройки preconnect.
|
||||||
|
|
||||||
|
Шрифт подключается в точке инициализации приложения, а в CSS используется через переменную.
|
||||||
|
|
||||||
|
## Google Fonts
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
// src/app/layout.tsx
|
||||||
|
import type { ReactNode } from 'react'
|
||||||
|
import { Inter } from 'next/font/google'
|
||||||
|
import 'shared/styles/global.css'
|
||||||
|
|
||||||
|
const inter = Inter({
|
||||||
|
subsets: ['latin', 'cyrillic'],
|
||||||
|
variable: '--font-main',
|
||||||
|
display: 'swap',
|
||||||
|
})
|
||||||
|
|
||||||
|
type RootLayoutProps = {
|
||||||
|
children: ReactNode
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function RootLayout({ children }: RootLayoutProps) {
|
||||||
|
return (
|
||||||
|
<html lang="ru" className={inter.variable}>
|
||||||
|
<body>{children}</body>
|
||||||
|
</html>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```css
|
||||||
|
/* src/shared/styles/global.css */
|
||||||
|
body {
|
||||||
|
font-family: var(--font-main), system-ui, sans-serif;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Локальные шрифты
|
||||||
|
|
||||||
|
Каждый локальный шрифт размещается в отдельной папке внутри `src/shared/fonts/`. В этой же папке лежит `.font.ts`, где объявляется `localFont`.
|
||||||
|
|
||||||
|
```text
|
||||||
|
src/shared/fonts/
|
||||||
|
└── roboto/
|
||||||
|
├── roboto.font.ts
|
||||||
|
├── Roboto-Regular.woff2
|
||||||
|
├── Roboto-Italic.woff2
|
||||||
|
├── Roboto-Bold.woff2
|
||||||
|
└── Roboto-BoldItalic.woff2
|
||||||
|
```
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// src/shared/fonts/roboto/roboto.font.ts
|
||||||
|
import localFont from 'next/font/local'
|
||||||
|
|
||||||
|
export const roboto = localFont({
|
||||||
|
src: [
|
||||||
|
{
|
||||||
|
path: './Roboto-Regular.woff2',
|
||||||
|
weight: '400',
|
||||||
|
style: 'normal',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: './Roboto-Italic.woff2',
|
||||||
|
weight: '400',
|
||||||
|
style: 'italic',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: './Roboto-Bold.woff2',
|
||||||
|
weight: '700',
|
||||||
|
style: 'normal',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: './Roboto-BoldItalic.woff2',
|
||||||
|
weight: '700',
|
||||||
|
style: 'italic',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
variable: '--font-main',
|
||||||
|
display: 'swap',
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
`app/` импортирует готовый объект шрифта и только подключает его к документу:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
// src/app/layout.tsx
|
||||||
|
import type { ReactNode } from 'react'
|
||||||
|
import { roboto } from 'shared/fonts/roboto/roboto.font'
|
||||||
|
import 'shared/styles/global.css'
|
||||||
|
|
||||||
|
type RootLayoutProps = {
|
||||||
|
children: ReactNode
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function RootLayout({ children }: RootLayoutProps) {
|
||||||
|
return (
|
||||||
|
<html lang="ru" className={roboto.variable}>
|
||||||
|
<body>{children}</body>
|
||||||
|
</html>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Путь в `localFont` указывается относительно `.font.ts`, поэтому файлы шрифта импортируются коротко: `./Roboto-Regular.woff2`.
|
||||||
|
|
||||||
|
Если шрифтов несколько, у каждого своя папка и свой `.font.ts`.
|
||||||
|
|
||||||
|
## Правила
|
||||||
|
|
||||||
|
- Использовать `next/font/google` или `next/font/local`.
|
||||||
|
- Не подключать шрифты через ручные `<link>` и `@font-face` без необходимости.
|
||||||
|
- Подключать шрифты один раз — в корневом layout через готовый объект шрифта.
|
||||||
|
- Использовать CSS-переменные `variable`, а не жёстко прописывать семейство в каждом компоненте.
|
||||||
|
- Локальные файлы шрифтов хранить в `src/shared/fonts/{font-name}/` рядом с `{font-name}.font.ts`.
|
||||||
|
- Не объявлять `localFont` внутри `src/app/layout.tsx`; layout только импортирует готовый шрифт.
|
||||||
|
|||||||
95
docs/docs/applied/images.md
Normal file
95
docs/docs/applied/images.md
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
---
|
||||||
|
title: Изображения
|
||||||
|
description: Как подключать изображения через Next.js Image в проекте.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Изображения
|
||||||
|
|
||||||
|
Как подключать изображения через Next.js Image в проекте.
|
||||||
|
|
||||||
|
## Назначение
|
||||||
|
|
||||||
|
Изображения рендерятся через компонент `Image` из `next/image`. Это сохраняет единый API для размеров, `alt`, lazy-loading и `priority`, даже если оптимизация изображений отключена.
|
||||||
|
|
||||||
|
В проекте оптимизация Next.js Image отключается через `unoptimized`, чтобы сборка и рантайм не зависели от встроенного image optimizer.
|
||||||
|
|
||||||
|
## Настройка
|
||||||
|
|
||||||
|
Отключение оптимизации задаётся глобально в `next.config.ts`:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import type { NextConfig } from 'next'
|
||||||
|
|
||||||
|
const nextConfig: NextConfig = {
|
||||||
|
images: {
|
||||||
|
unoptimized: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default nextConfig
|
||||||
|
```
|
||||||
|
|
||||||
|
После этого `unoptimized` не нужно повторять на каждом `Image`.
|
||||||
|
|
||||||
|
## Использование
|
||||||
|
|
||||||
|
Статические изображения, доступные по URL, размещаются в `public/`:
|
||||||
|
|
||||||
|
```text
|
||||||
|
public/
|
||||||
|
└── images/
|
||||||
|
└── user-avatar.png
|
||||||
|
```
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import Image from 'next/image'
|
||||||
|
|
||||||
|
export const UserAvatar = () => {
|
||||||
|
return (
|
||||||
|
<Image
|
||||||
|
src="/images/user-avatar.png"
|
||||||
|
alt="Аватар пользователя"
|
||||||
|
width={96}
|
||||||
|
height={96}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Правила
|
||||||
|
|
||||||
|
- Использовать `Image` из `next/image`, не обычный `<img>`.
|
||||||
|
- Для контентных изображений всегда писать осмысленный `alt`.
|
||||||
|
- Для декоративных изображений использовать `alt=""`.
|
||||||
|
- Указывать `width` и `height`, если изображение не использует `fill`.
|
||||||
|
- При `fill` задавать `sizes` и контролировать размеры родителя стилями.
|
||||||
|
- `priority` ставить только для изображений первого экрана.
|
||||||
|
- SVG-иконки не оформлять как изображения — для них используется раздел [SVG-спрайты](/docs/applied/svg-sprites/svg-sprites-intro).
|
||||||
|
|
||||||
|
## Пример с `fill`
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import Image from 'next/image'
|
||||||
|
import styles from '../styles/article-card-cover.module.css'
|
||||||
|
|
||||||
|
export const ArticleCardCover = () => {
|
||||||
|
return (
|
||||||
|
<div className={styles.root}>
|
||||||
|
<Image
|
||||||
|
src="/images/article-cover.jpg"
|
||||||
|
alt="Обложка статьи"
|
||||||
|
fill
|
||||||
|
sizes="(min-width: 768px) 33vw, 100vw"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```css
|
||||||
|
.root {
|
||||||
|
position: relative;
|
||||||
|
aspect-ratio: 16 / 9;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
---
|
||||||
|
title: Локализация
|
||||||
|
description: Как организовать локализацию как infrastructure-модуль.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Локализация
|
||||||
|
|
||||||
|
Как организовать локализацию как infrastructure-модуль.
|
||||||
|
|
||||||
|
## Назначение
|
||||||
|
|
||||||
|
Локализация — инфраструктурная подсистема приложения. Она отвечает за текущую локаль, словари, форматирование переводов и API для компонентов.
|
||||||
|
|
||||||
|
Код локализации живёт в `src/infrastructure/i18n/`. Компоненты и модули не читают словари напрямую — они используют публичный API infrastructure-модуля.
|
||||||
|
|
||||||
|
## Структура
|
||||||
|
|
||||||
|
```text
|
||||||
|
src/infrastructure/i18n/
|
||||||
|
├── config/
|
||||||
|
│ └── i18n.config.ts
|
||||||
|
├── dictionaries/
|
||||||
|
│ ├── ru.ts
|
||||||
|
│ └── en.ts
|
||||||
|
├── hooks/
|
||||||
|
│ └── use-translation.hook.ts
|
||||||
|
├── providers/
|
||||||
|
│ └── i18n-provider.tsx
|
||||||
|
├── types/
|
||||||
|
│ └── i18n.type.ts
|
||||||
|
└── index.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
Набор сегментов может отличаться, но публичная точка входа остаётся одна — `infrastructure/i18n`.
|
||||||
|
|
||||||
|
## Подключение
|
||||||
|
|
||||||
|
`app/` только подключает готовый провайдер локализации. Реализация провайдера, словари и конфиг остаются в `infrastructure/i18n/`.
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
// src/app/layout.tsx
|
||||||
|
import type { ReactNode } from 'react'
|
||||||
|
import { I18nProvider } from 'infrastructure/i18n'
|
||||||
|
|
||||||
|
type RootLayoutProps = {
|
||||||
|
children: ReactNode
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function RootLayout({ children }: RootLayoutProps) {
|
||||||
|
return (
|
||||||
|
<html lang="ru">
|
||||||
|
<body>
|
||||||
|
<I18nProvider locale="ru">{children}</I18nProvider>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Использование
|
||||||
|
|
||||||
|
Компоненты получают переводы через готовый API модуля локализации:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { useTranslation } from 'infrastructure/i18n'
|
||||||
|
|
||||||
|
export const ProfileTitle = () => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
|
return <h1>{t('profile.title')}</h1>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Правила
|
||||||
|
|
||||||
|
- Локализация живёт в `infrastructure/i18n/`.
|
||||||
|
- `app/` только подключает готовый provider и передаёт locale.
|
||||||
|
- Словари не импортируются напрямую в компоненты, screens или business-модули.
|
||||||
|
- Ключи переводов не собираются динамически из строк, если это ломает типизацию и поиск.
|
||||||
|
- Тексты интерфейса не хардкодятся в переиспользуемых компонентах, если они должны переводиться.
|
||||||
|
- Форматирование дат, чисел и валют должно проходить через API локализации или отдельные утилиты infrastructure-модуля.
|
||||||
|
|||||||
@@ -1,110 +1,162 @@
|
|||||||
---
|
---
|
||||||
title: Модуль
|
title: Модуль
|
||||||
description: Как устроен и пишется React-компонент в проекте.
|
description: Как создавать и организовывать SLM-модули в проекте.
|
||||||
---
|
---
|
||||||
|
|
||||||
# Модуль
|
# Модуль
|
||||||
|
|
||||||
Как устроен и пишется React-компонент в проекте.
|
Как создавать и организовывать SLM-модули в проекте.
|
||||||
|
|
||||||
## Правила организации
|
## Назначение
|
||||||
|
|
||||||
1. Один компонент — один файл.
|
Модуль — основной строительный блок SLM-архитектуры. Это папка с публичным API (`index.ts`) и опциональными сегментами: компонентами, стилями, типами, хуками, сторами, сервисами и вложенными модулями.
|
||||||
2. Компонент не содержит бизнес-логики — логика и сайд-эффекты выносятся в хуки или сторы.
|
|
||||||
3. Дочерние компоненты размещаются в сегменте `ui/` и подчиняются тем же правилам структуры.
|
|
||||||
4. Публичный API модуля — только `index.ts`. Прямые импорты внутренних файлов запрещены.
|
|
||||||
|
|
||||||
## Базовая структура компонента
|
Если UI-сущность остаётся одним `.tsx` файлом и использует ресурсы родительского модуля — это [компонент](/docs/applied/component), а не модуль. Связанные файлы в `styles/` и `types/` родителя не создают новую модульную границу.
|
||||||
|
|
||||||
Минимальный набор файлов: компонент, стили, типы и публичный экспорт.
|
Архитектурное определение: [Модули SLM](/docs/basics/architecture/reference/modules). Список сегментов: [Сегменты SLM](/docs/basics/architecture/reference/segments).
|
||||||
|
|
||||||
|
## Когда нужен модуль
|
||||||
|
|
||||||
|
Создавайте модуль, если сущности нужны:
|
||||||
|
|
||||||
|
- публичный API;
|
||||||
|
- хуки, сторы, сервисы, мапперы или утилиты;
|
||||||
|
- вложенные части;
|
||||||
|
- переиспользование вне родительского модуля;
|
||||||
|
- самостоятельная ответственность на слое.
|
||||||
|
|
||||||
|
Если понадобилась папка вокруг компонента — это сигнал, что нужен модуль.
|
||||||
|
|
||||||
|
## Где размещать
|
||||||
|
|
||||||
|
Модуль размещается на самом низком уровне использования.
|
||||||
|
|
||||||
|
- Нужен только одному модулю — размещается в `parts/` родителя.
|
||||||
|
- Нужен одной странице — размещается в `screens/{name}/parts/`.
|
||||||
|
- Нужен одному layout — размещается в `layouts/{name}/parts/`.
|
||||||
|
- Переиспользуется между страницами или layout — поднимается в `widgets/`.
|
||||||
|
- Представляет бизнес-домен — размещается в `business/`.
|
||||||
|
- Является UI-китом — размещается в `ui/`.
|
||||||
|
|
||||||
|
`app/` не содержит модулей. Это слой файлового роутинга и инициализации.
|
||||||
|
|
||||||
|
## Структура
|
||||||
|
|
||||||
|
Минимальный UI-модуль:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
container/
|
user/
|
||||||
├── styles/
|
├── user.tsx
|
||||||
│ └── container.module.css
|
|
||||||
├── types/
|
|
||||||
│ └── container.type.ts
|
|
||||||
├── container.tsx
|
|
||||||
└── index.ts
|
└── index.ts
|
||||||
```
|
```
|
||||||
|
|
||||||
## Именования
|
Модуль расширяется сегментами только при реальной потребности:
|
||||||
|
|
||||||
- Имя корневого css класса всегда `.root`
|
```text
|
||||||
- Тип пропсов именуется `{ComponentName}Props`.
|
user/
|
||||||
- Тип пользовательских параметров именуется `{ComponentName}Params`.
|
├── ui/
|
||||||
|
│ └── user-avatar.tsx
|
||||||
|
├── parts/
|
||||||
|
│ └── user-posts/
|
||||||
|
│ ├── user-posts.tsx
|
||||||
|
│ └── index.ts
|
||||||
|
├── styles/
|
||||||
|
│ ├── user.module.css
|
||||||
|
│ └── user-avatar.module.css
|
||||||
|
├── types/
|
||||||
|
│ ├── user.type.ts
|
||||||
|
│ └── user-avatar.type.ts
|
||||||
|
├── user.tsx
|
||||||
|
└── index.ts
|
||||||
|
```
|
||||||
|
|
||||||
## Типизация
|
Корневой компонент опционален. Business- и infrastructure-модули могут состоять только из хуков, сервисов, типов и публичного API.
|
||||||
|
|
||||||
Структура типов компонента показана в [примере](#пример). Ниже — обоснования ключевых решений.
|
## `ui/` и `parts/`
|
||||||
|
|
||||||
- **`type` вместо `interface`** — гибче для пропсов: поддерживает union, intersection, mapped types. Declaration merging пропсам не нужно.
|
`ui/` содержит только компоненты: отдельные `.tsx` файлы без собственных сегментов.
|
||||||
- **Без `FC`** — неявно добавляет `children`, усложняет дженерики, не даёт преимуществ перед аннотацией параметра.
|
|
||||||
- **Типы в `types/`, а не в `.tsx`** — предотвращает циклические зависимости (компонент импортирует хук, хук импортирует тип из компонента) и разделяет ответственность: `.tsx` для рендера, `.type.ts` для данных.
|
|
||||||
- **Без возвращаемого типа** — TypeScript выводит из JSX. Осознанное исключение из [базового правила](/docs/basics/typing).
|
|
||||||
|
|
||||||
## Реализация
|
`parts/` содержит только модули: каждая запись внутри `parts/` — папка с собственным `index.ts`. Отдельные `.tsx`, стили, хуки или произвольные файлы в `parts/` не кладутся.
|
||||||
|
|
||||||
- Пропсы деструктурируются в теле компонента, не в параметрах.
|
```text
|
||||||
- Порядок: пользовательские → системные (`children`, `className`) → `...htmlAttr`.
|
user/
|
||||||
- `className` объединяется с корневым классом через `cl()`: `cl(styles.root, className)`.
|
├── ui/
|
||||||
- `...htmlAttr` прокидывается на корневой элемент.
|
│ └── user-avatar.tsx # компонент
|
||||||
|
└── parts/
|
||||||
|
└── user-posts/ # модуль
|
||||||
|
├── styles/
|
||||||
|
│ └── user-posts.module.css
|
||||||
|
├── user-posts.tsx
|
||||||
|
└── index.ts
|
||||||
|
```
|
||||||
|
|
||||||
## Пример
|
Если компоненту в `ui/` понадобились стили или типы, они добавляются в `styles/` и `types/` родительского модуля. Если компоненту нужны собственные хуки, вложенные части или публичная граница — он переносится в `parts/` как модуль.
|
||||||
|
|
||||||
`container/types/container.type.ts`
|
## Публичный API
|
||||||
|
|
||||||
|
`index.ts` — единственная точка входа в модуль. Внешние импорты внутренних файлов запрещены.
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import type { HTMLAttributes } from 'react'
|
// user/index.ts
|
||||||
|
export { User } from './user'
|
||||||
/**
|
export type { UserProps } from './types/user.type'
|
||||||
* Параметры компонента Container.
|
|
||||||
*/
|
|
||||||
export type ContainerParams = {}
|
|
||||||
|
|
||||||
/** HTML-атрибуты корневого элемента. */
|
|
||||||
type RootAttrs = HTMLAttributes<HTMLDivElement>
|
|
||||||
|
|
||||||
export type ContainerProps = RootAttrs & ContainerParams
|
|
||||||
```
|
```
|
||||||
|
|
||||||
`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 cl from 'clsx'
|
|
||||||
import type { ContainerProps } from './types/container.type'
|
|
||||||
import styles from './styles/container.module.css'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Контейнер с адаптивной максимальной шириной.
|
|
||||||
*
|
|
||||||
* Используется для:
|
|
||||||
* - обёртки контента страниц с ограничением ширины
|
|
||||||
* - центрирования блоков в лейауте
|
|
||||||
*/
|
|
||||||
export const Container = (props: ContainerProps) => {
|
|
||||||
const { children, className, ...htmlAttr } = props
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div {...htmlAttr} className={cl(styles.root, className)}>
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
`container/index.ts`
|
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
export { Container } from './container'
|
// Плохо: импорт в обход публичного API.
|
||||||
|
import { UserPosts } from 'screens/user/parts/user-posts/user-posts'
|
||||||
|
|
||||||
|
// Хорошо: импорт через публичный API родительского модуля.
|
||||||
|
import { User } from 'screens/user'
|
||||||
|
```
|
||||||
|
|
||||||
|
Вложенный модуль имеет свой `index.ts`, но наружу родителя экспортируется только при необходимости.
|
||||||
|
|
||||||
|
## Именование
|
||||||
|
|
||||||
|
Базовые правила описаны в разделе [Именование](/docs/basics/naming).
|
||||||
|
|
||||||
|
- Папка модуля — `kebab-case`: `user-posts/`.
|
||||||
|
- Файл корневого компонента повторяет имя папки: `user-posts/user-posts.tsx`.
|
||||||
|
- Корневые модули слоёв наследуют роль слоя в имени файла: `screens/profile/profile.screen.tsx`, `layouts/main/main.layout.tsx`.
|
||||||
|
- Корневой компонент именуется в `PascalCase`: `UserPosts`.
|
||||||
|
- Если имя без контекста слишком общее, добавляется префикс родителя или роль слоя: `ProfileUserPosts`, `ProfileScreen`, `MainLayout`.
|
||||||
|
|
||||||
|
## Примеры
|
||||||
|
|
||||||
|
### Screen-модуль
|
||||||
|
|
||||||
|
```text
|
||||||
|
screens/profile/
|
||||||
|
├── ui/
|
||||||
|
│ └── profile-heading.tsx
|
||||||
|
├── parts/
|
||||||
|
│ └── activity-feed/
|
||||||
|
│ ├── styles/
|
||||||
|
│ │ └── activity-feed.module.css
|
||||||
|
│ ├── activity-feed.tsx
|
||||||
|
│ └── index.ts
|
||||||
|
├── styles/
|
||||||
|
│ ├── profile.module.css
|
||||||
|
│ └── profile-heading.module.css
|
||||||
|
├── types/
|
||||||
|
│ ├── profile.type.ts
|
||||||
|
│ └── profile-heading.type.ts
|
||||||
|
├── profile.screen.tsx
|
||||||
|
└── index.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
### Business-модуль без корневого компонента
|
||||||
|
|
||||||
|
```text
|
||||||
|
business/auth/
|
||||||
|
├── hooks/
|
||||||
|
│ └── use-auth.hook.ts
|
||||||
|
├── services/
|
||||||
|
│ └── auth.service.ts
|
||||||
|
├── stores/
|
||||||
|
│ └── auth.store.ts
|
||||||
|
├── types/
|
||||||
|
│ └── auth.type.ts
|
||||||
|
└── index.ts
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,31 +1,61 @@
|
|||||||
---
|
---
|
||||||
title: Файлы роутинга
|
title: Файлы роутинга
|
||||||
description: "Что должно лежать в файлах роутинга, а что — в экранах."
|
description: Как работать со страницами и другими файлами роутинга Next.js App Router.
|
||||||
---
|
---
|
||||||
|
|
||||||
# Файлы роутинга
|
# Файлы роутинга
|
||||||
|
|
||||||
Что должно лежать в файлах роутинга, а что — в экранах.
|
Как работать со страницами и другими файлами роутинга Next.js App Router.
|
||||||
|
|
||||||
## Организация
|
## Назначение
|
||||||
|
|
||||||
- `page.tsx` — тонкий файл: только `metadata` и рендер экрана. Логика, стили и зависимости живут в экране, не в `page.tsx`.
|
`src/app/**` — точка входа приложения и слой файлового роутинга Next.js.
|
||||||
- `error.tsx` и `not-found.tsx` делегируют разметку экранам по тому же принципу.
|
|
||||||
- `layout.tsx` — точка подключения провайдеров и глобальных стилей. Вёрстка layout-обёрток выносится в слой `layouts/`.
|
|
||||||
- Стили в файлах роутинга не используются — стилизация только внутри вызываемых компонентов.
|
|
||||||
|
|
||||||
## Реализация
|
Файлы роутинга не реализуют интерфейс. Они описывают маршрут: читают параметры, получают данные первого рендера, подготавливают кеш или состояние и передают результат в screen.
|
||||||
|
|
||||||
- Каждый `page.tsx` экспортирует `metadata` с `title` — он подставляется в шаблон корневого layout (`%s | App`).
|
Границы слоя описаны в [Архитектура → Слои → App](/docs/basics/architecture/reference/layers#слой-app).
|
||||||
- Корневой `layout.tsx` задаёт `metadata` с `title.template`, `description`, `metadataBase` и OpenGraph-настройками.
|
|
||||||
|
|
||||||
## Примеры
|
## Граница ответственности
|
||||||
|
|
||||||
`src/app/profile/[id]/page.tsx`
|
| Область | Где живёт |
|
||||||
|
|---|---|
|
||||||
|
| Файлы маршрутов (`page.tsx`, `layout.tsx`, `loading.tsx`, `error.tsx`, `not-found.tsx`) | `src/app/**` |
|
||||||
|
| Параметры маршрута, `metadata`, `redirect()`, `notFound()` | `src/app/**` |
|
||||||
|
| Серверные запросы для первого рендера | `src/app/**`, через готовые клиенты и сервисы нижних слоёв |
|
||||||
|
| Прогрев SWR-кеша, начальное состояние, подключение провайдеров | `src/app/**`, только через готовые обёртки из нижних слоёв |
|
||||||
|
| UI страницы | `screens/` |
|
||||||
|
| Каркас страницы: header, footer, sidebar | `layouts/` |
|
||||||
|
| Провайдеры, сторы, хуки, API-клиенты, сервисы | нижние слои (`screens/`, `business/`, `infrastructure/`, `shared/`) |
|
||||||
|
| CSS Modules и стили компонентов | рядом с компонентами, не в `src/app/**` |
|
||||||
|
|
||||||
|
## Что можно делать в `page.tsx`
|
||||||
|
|
||||||
|
- Экспортировать `metadata` или `generateMetadata`.
|
||||||
|
- Читать `params` и `searchParams`.
|
||||||
|
- Нормализовать и валидировать параметры маршрута.
|
||||||
|
- Делать серверные запросы для первого рендера через готовые клиенты или сервисы.
|
||||||
|
- Вызывать `redirect()` и `notFound()`.
|
||||||
|
- Готовить начальные данные для screen.
|
||||||
|
- Готовить SWR `fallback` и передавать его в готовый провайдер.
|
||||||
|
- Подключать готовый провайдер стора страницы и передавать начальное состояние.
|
||||||
|
- Рендерить screen или композицию из готовых обёрток и screen.
|
||||||
|
|
||||||
|
## Что запрещено
|
||||||
|
|
||||||
|
- Писать UI-разметку страницы прямо в файле роутинга.
|
||||||
|
- Создавать локальные компоненты внутри `src/app/**`.
|
||||||
|
- Добавлять CSS Modules, стили компонентов, `components/`, `styles/`, `hooks/`, `stores/`, `services/` внутри `src/app/**`.
|
||||||
|
- Реализовывать провайдеры, сторы, хуки, API-клиенты или сервисы в файлах роутинга.
|
||||||
|
- Размещать бизнес-логику, мапперы и правила предметной области в файлах роутинга.
|
||||||
|
- Вызывать `useSWR` и доменные клиентские хуки в файлах роутинга.
|
||||||
|
|
||||||
|
## Страницы
|
||||||
|
|
||||||
|
Страница объявляется через `export default function`. Для серверных запросов используется `async function`.
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
import type { Metadata } from 'next'
|
import type { Metadata } from 'next'
|
||||||
import { ProfileScreen } from '@/screens/profile'
|
import { ProfileScreen } from 'screens/profile'
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'Профиль',
|
title: 'Профиль',
|
||||||
@@ -43,12 +73,101 @@ export default async function ProfilePage({ params }: ProfilePageProps) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`src/app/error.tsx`
|
## Данные первого рендера
|
||||||
|
|
||||||
|
Если данные нужны до первого рендера, `page.tsx` получает их на сервере и передаёт в screen. Сам запрос выполняется через готовый клиент или сервис нижнего слоя.
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { notFound } from 'next/navigation'
|
||||||
|
import { userApi } from 'infrastructure/backend-api'
|
||||||
|
import { UserScreen } from 'screens/user'
|
||||||
|
|
||||||
|
type UserPageProps = {
|
||||||
|
params: Promise<{ id: string }>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function UserPage({ params }: UserPageProps) {
|
||||||
|
const { id } = await params
|
||||||
|
const user = await userApi.users.get(id)
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
notFound()
|
||||||
|
}
|
||||||
|
|
||||||
|
return <UserScreen user={user} />
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Если данные нужны нескольким клиентским SWR-хукам, файл роутинга может обернуть дерево в `SWRConfig` и передать `fallback`. Запросы стартуют на сервере, а клиентские хуки получают готовые данные из кеша.
|
||||||
|
|
||||||
|
Ключи `fallback` должны совпадать с ключами внутри готовых SWR-хуков.
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import type { ReactNode } from 'react'
|
||||||
|
import { SWRConfig } from 'swr'
|
||||||
|
import { backendApi } from 'infrastructure/backend-api'
|
||||||
|
|
||||||
|
type FeedLayoutProps = {
|
||||||
|
children: ReactNode
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function FeedLayout({ children }: FeedLayoutProps) {
|
||||||
|
const userPromise = backendApi.user.getCurrent()
|
||||||
|
const postsPromise = backendApi.posts.list()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SWRConfig
|
||||||
|
value={{
|
||||||
|
fallback: {
|
||||||
|
'/api/user': userPromise,
|
||||||
|
'/api/posts': postsPromise,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</SWRConfig>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Подробнее о серверных запросах и SWR-кеше: [REST → Серверные компоненты](/docs/data/rest/fetching/server), [REST → Клиентские компоненты](/docs/data/rest/fetching/client).
|
||||||
|
|
||||||
|
## Инициализация состояния
|
||||||
|
|
||||||
|
Файл роутинга может подключить готовый провайдер стора страницы, если состояние зависит от маршрута или данных первого рендера. Реализация стора и провайдера не размещается в `src/app/**`.
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { ProfileScreen, ProfileStoreProvider } from 'screens/profile'
|
||||||
|
|
||||||
|
type ProfilePageProps = {
|
||||||
|
params: Promise<{ id: string }>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function ProfilePage({ params }: ProfilePageProps) {
|
||||||
|
const { id } = await params
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ProfileStoreProvider initialState={{ userId: id }}>
|
||||||
|
<ProfileScreen />
|
||||||
|
</ProfileStoreProvider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Layout
|
||||||
|
|
||||||
|
`layout.tsx` подключает готовую инициализацию приложения: глобальные стили, провайдеры и верхнеуровневые обёртки из нижних слоёв.
|
||||||
|
|
||||||
|
Вёрстка layout-каркаса выносится в слой `layouts/`. Реализация провайдеров, стилей и UI не размещается в `app/`.
|
||||||
|
|
||||||
|
## Error и Not Found
|
||||||
|
|
||||||
|
`error.tsx` и `not-found.tsx` делегируют разметку готовым screen или widget. В файле роутинга остаётся только адаптация API Next.js к пропсам нижнего слоя.
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { ErrorScreen } from '@/screens/error'
|
import { ErrorScreen } from 'screens/error'
|
||||||
|
|
||||||
type ErrorPageProps = {
|
type ErrorPageProps = {
|
||||||
error: Error & { digest?: string }
|
error: Error & { digest?: string }
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ public/
|
|||||||
|
|
||||||
```text
|
```text
|
||||||
src/
|
src/
|
||||||
├── app/ # Роутинг Next.js, провайдеры, глобальные стили
|
├── app/ # Роутинг Next.js и точка входа приложения
|
||||||
├── layouts/ # Каркасы страниц (header, footer, sidebar)
|
├── layouts/ # Каркасы страниц (header, footer, sidebar)
|
||||||
├── screens/ # Контент конкретной страницы
|
├── screens/ # Контент конкретной страницы
|
||||||
├── widgets/ # Составные блоки интерфейса, не привязанные к домену
|
├── widgets/ # Составные блоки интерфейса, не привязанные к домену
|
||||||
@@ -55,12 +55,13 @@ src/
|
|||||||
|
|
||||||
### Папка `app/`
|
### Папка `app/`
|
||||||
|
|
||||||
Точка входа приложения: инициализация (провайдеры, глобальные стили) и файловый роутинг Next.js (`layout.tsx`, `page.tsx`, route-сегменты).
|
Точка входа приложения и файловый роутинг Next.js (`layout.tsx`, `page.tsx`, route-сегменты).
|
||||||
|
`app/` подключает готовую инициализацию из нижних слоёв, но не реализует провайдеры, стили, UI-компоненты, хуки, сторы или сервисы.
|
||||||
|
|
||||||
|
Подробнее о границах слоя: [Архитектура → Слои → App](/docs/basics/architecture/reference/layers#слой-app).
|
||||||
|
|
||||||
```text
|
```text
|
||||||
src/app/
|
src/app/
|
||||||
├── providers/ # Провайдеры приложения
|
|
||||||
├── styles/ # Глобальные стили
|
|
||||||
├── layout.tsx # Корневой layout
|
├── layout.tsx # Корневой layout
|
||||||
└── page.tsx # Главная страница
|
└── page.tsx # Главная страница
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ description: Как пишутся стили в проекте.
|
|||||||
- Только **PostCSS** и **CSS Modules** для кастомной стилизации.
|
- Только **PostCSS** и **CSS Modules** для кастомной стилизации.
|
||||||
- Подход **Mobile First** — стили пишутся от мобильных к десктопу.
|
- Подход **Mobile First** — стили пишутся от мобильных к десктопу.
|
||||||
- Именование классов — `camelCase` (`.root`, `.buttonNext`, `.itemTitle`).
|
- Именование классов — `camelCase` (`.root`, `.buttonNext`, `.itemTitle`).
|
||||||
|
- Корневой класс каждого CSS Module компонента всегда называется `.root` — это упрощает ориентацию в DevTools и отладку DOM.
|
||||||
- Модификаторы — отдельный класс с `_`, применяется через `&._modifier`.
|
- Модификаторы — отдельный класс с `_`, применяется через `&._modifier`.
|
||||||
|
|
||||||
**Хорошо**
|
**Хорошо**
|
||||||
@@ -143,13 +144,13 @@ description: Как пишутся стили в проекте.
|
|||||||
|
|
||||||
## CSS-переменные
|
## CSS-переменные
|
||||||
|
|
||||||
- Цвета (`--color-*`), отступы (`--space-*`), скругления (`--radius-*`) определяются в `app/styles/variables.css` через `:root`.
|
- Цвета (`--color-*`), отступы (`--space-*`), скругления (`--radius-*`) определяются в `src/shared/styles/variables.css` через `:root`.
|
||||||
- Файл переменных подключается один раз в корневом layout/entry point — после этого переменные доступны глобально через каскад.
|
- Файл переменных подключается через `src/shared/styles/global.css`, который импортируется один раз в `src/app/layout.tsx`.
|
||||||
- Не дублировать магические значения в компонентах.
|
- Не дублировать магические значения в компонентах.
|
||||||
|
|
||||||
**Хорошо**
|
**Хорошо**
|
||||||
```css
|
```css
|
||||||
/* app/styles/variables.css */
|
/* src/shared/styles/variables.css */
|
||||||
:root {
|
:root {
|
||||||
--color-primary: #3b82f6;
|
--color-primary: #3b82f6;
|
||||||
--color-bg: #ffffff;
|
--color-bg: #ffffff;
|
||||||
@@ -183,11 +184,11 @@ description: Как пишутся стили в проекте.
|
|||||||
|
|
||||||
## Custom Media
|
## Custom Media
|
||||||
|
|
||||||
- Breakpoints определяются через Custom Media Queries в `app/styles/media.css`.
|
- Breakpoints определяются через Custom Media Queries в `src/shared/styles/media.css`.
|
||||||
- Custom media подключаются глобально через конфиг PostCSS (плагин `postcss-custom-media`) — не импортировать в файлы стилей.
|
- Custom media подключаются глобально через конфиг PostCSS (плагин `postcss-custom-media`) — не импортировать в файлы стилей.
|
||||||
|
|
||||||
```css
|
```css
|
||||||
/* app/styles/media.css */
|
/* src/shared/styles/media.css */
|
||||||
@custom-media --sm (min-width: 36em);
|
@custom-media --sm (min-width: 36em);
|
||||||
@custom-media --md (min-width: 62em);
|
@custom-media --md (min-width: 62em);
|
||||||
@custom-media --lg (min-width: 82em);
|
@custom-media --lg (min-width: 82em);
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ description: Что такое сегмент модуля в SLM-архитек
|
|||||||
|
|
||||||
| Сегмент | Содержимое |
|
| Сегмент | Содержимое |
|
||||||
|---------|------------|
|
|---------|------------|
|
||||||
| `ui/` | Компоненты модуля — только `.tsx` файлы |
|
| `ui/` | Вспомогательные компоненты модуля — только `.tsx` файлы |
|
||||||
| `parts/` | Вложенные модули со своими сегментами |
|
| `parts/` | Вложенные модули со своими сегментами |
|
||||||
| `hooks/` | React-хуки |
|
| `hooks/` | React-хуки |
|
||||||
| `stores/` | Сторы состояния |
|
| `stores/` | Сторы состояния |
|
||||||
@@ -28,16 +28,18 @@ description: Что такое сегмент модуля в SLM-архитек
|
|||||||
|
|
||||||
## Сегмент ui/
|
## Сегмент ui/
|
||||||
|
|
||||||
Компоненты, принадлежащие модулю. Содержит только `.tsx` файлы — без своих сегментов, стилей, типов, хуков. Использует сегменты родительского модуля.
|
Вспомогательные компоненты модуля. Содержит только `.tsx` файлы — без своих сегментов, стилей, типов, хуков и публичного API. Использует сегменты родительского модуля.
|
||||||
|
|
||||||
|
Корневой компонент модуля в `ui/` не размещается. Он лежит в корне модуля: `{module-name}.tsx`.
|
||||||
|
|
||||||
```text
|
```text
|
||||||
auth/
|
user/
|
||||||
├── ui/
|
├── ui/
|
||||||
│ ├── auth-provider.tsx
|
│ ├── user-avatar.tsx
|
||||||
│ ├── auth-guard.tsx
|
│ └── user-status.tsx
|
||||||
│ └── logout-button.tsx
|
|
||||||
├── types/
|
├── types/
|
||||||
├── hooks/
|
├── hooks/
|
||||||
|
├── user.tsx
|
||||||
└── index.ts
|
└── index.ts
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -45,7 +47,7 @@ auth/
|
|||||||
|
|
||||||
## Сегмент parts/
|
## Сегмент parts/
|
||||||
|
|
||||||
Вложенные модули со своими сегментами. Каждый элемент `parts/` — полноценный модуль: папка с компонентом, хуками, стилями, типами и т.д.
|
Вложенные модули со своими сегментами. `parts/` содержит только модули: каждый элемент `parts/` — папка полноценного модуля с собственным публичным API. Отдельные `.tsx`, стили, хуки или произвольные файлы в `parts/` не размещаются.
|
||||||
|
|
||||||
```text
|
```text
|
||||||
home/
|
home/
|
||||||
@@ -53,17 +55,20 @@ home/
|
|||||||
│ ├── hero-section/
|
│ ├── hero-section/
|
||||||
│ │ ├── hero-section.tsx
|
│ │ ├── hero-section.tsx
|
||||||
│ │ ├── styles/
|
│ │ ├── styles/
|
||||||
│ │ └── parts/
|
│ │ ├── parts/
|
||||||
│ │ └── top-banner/
|
│ │ │ └── top-banner/
|
||||||
│ │ └── top-banner.tsx
|
│ │ │ ├── top-banner.tsx
|
||||||
|
│ │ │ └── index.ts
|
||||||
|
│ │ └── index.ts
|
||||||
│ └── features-section/
|
│ └── features-section/
|
||||||
│ ├── features-section.tsx
|
│ ├── features-section.tsx
|
||||||
│ └── hooks/
|
│ ├── hooks/
|
||||||
|
│ └── index.ts
|
||||||
├── home.screen.tsx
|
├── home.screen.tsx
|
||||||
└── index.ts
|
└── index.ts
|
||||||
```
|
```
|
||||||
|
|
||||||
Отличие от `ui/`: элемент `parts/` — модуль со своими сегментами. Элемент `ui/` — компонент, один `.tsx` файл.
|
Отличие от `ui/`: элемент `parts/` — модульная папка со своими сегментами. Элемент `ui/` — вспомогательный компонент, один `.tsx` файл.
|
||||||
|
|
||||||
Вложенность `parts/` инкапсулирует область разработки горизонтально: каждый разработчик работает в своём `parts/`-модуле, не затрагивая чужие. Это снижает конфликты при параллельной разработке.
|
Вложенность `parts/` инкапсулирует область разработки горизонтально: каждый разработчик работает в своём `parts/`-модуле, не затрагивая чужие. Это снижает конфликты при параллельной разработке.
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,12 @@ description: Как называть переменные, файлы и про
|
|||||||
- `.store.ts` — стор
|
- `.store.ts` — стор
|
||||||
- `.service.ts` — сервис
|
- `.service.ts` — сервис
|
||||||
|
|
||||||
|
**Корневые компоненты слоёв**
|
||||||
|
- `.screen.tsx` — корневой компонент screen-модуля: `screens/profile/profile.screen.tsx`, компонент `ProfileScreen`
|
||||||
|
- `.layout.tsx` — корневой компонент layout-модуля: `layouts/main/main.layout.tsx`, компонент `MainLayout`
|
||||||
|
|
||||||
|
Обычные и вложенные модули не получают суффикс слоя: `ui/button/button.tsx`, `screens/profile/parts/activity-feed/activity-feed.tsx`.
|
||||||
|
|
||||||
**Типы и контракты**
|
**Типы и контракты**
|
||||||
- `.type.ts` — типы и интерфейсы
|
- `.type.ts` — типы и интерфейсы
|
||||||
- `.interface.ts` — интерфейсы
|
- `.interface.ts` — интерфейсы
|
||||||
|
|||||||
@@ -48,4 +48,4 @@ keywords: [данные, api, rest, realtime, клиент, swr, infrastructure,
|
|||||||
|
|
||||||
- **Глобальное состояние UI** — Stores, формы, фичефлаги. Это [Stores](/docs/applied/stores).
|
- **Глобальное состояние UI** — Stores, формы, фичефлаги. Это [Stores](/docs/applied/stores).
|
||||||
- **Доменная логика** — как данные превращаются в сценарии бизнеса. Это слой `business/` в [Архитектуре](/docs/basics/architecture/).
|
- **Доменная логика** — как данные превращаются в сценарии бизнеса. Это слой `business/` в [Архитектуре](/docs/basics/architecture/).
|
||||||
- **Хуки общего назначения** — переиспользуемые хуки UI, не привязанные к конкретному API. Это [Хуки](/docs/applied/hooks).
|
- **Хуки общего назначения** — переиспользуемые хуки UI, не привязанные к конкретному API. Отдельный прикладной раздел для них пока не ведётся.
|
||||||
|
|||||||
Reference in New Issue
Block a user