Files
nextjs-template/ai/nextjs-style-guide/applied/page-level.md
S.Gromov f2358da397 docs: добавить стайлгайд nextjs-style-guide в репозиторий
- Добавлена документация SLM-архитектуры, базовых правил и прикладных разделов
- Добавлены разделы: стили, SVG-спрайты, шаблоны генерации, PostCSS, REST, Realtime
- Удалены устаревшие файлы (спрайты, скрипты, стили из app/)
2026-04-30 19:32:10 +03:00

187 lines
8.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: Файлы роутинга
description: Как работать со страницами и другими файлами роутинга Next.js App Router.
---
# Файлы роутинга
Как работать со страницами и другими файлами роутинга Next.js App Router.
## Назначение
`src/app/**` — точка входа приложения и слой файлового роутинга Next.js.
Файлы роутинга не реализуют интерфейс. Они описывают маршрут: читают параметры, получают данные первого рендера, подготавливают кеш или состояние и передают результат в screen.
Границы слоя описаны в [Архитектура → Слои → App](../basics/architecture/reference/layers.md#слой-app).
## Граница ответственности
| Область | Где живёт |
|---|---|
| Файлы маршрутов (`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
import type { Metadata } from 'next'
import { ProfileScreen } from 'screens/profile'
export const metadata: Metadata = {
title: 'Профиль',
description: 'Страница профиля пользователя',
}
type ProfilePageProps = {
params: Promise<{ id: string }>
}
export default async function ProfilePage({ params }: ProfilePageProps) {
const { id } = await params
return <ProfileScreen id={id} />
}
```
## Данные первого рендера
Если данные нужны до первого рендера, `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` должны совпадать с ключами внутри GET-хуков REST-клиента. Для array-key используется `unstable_serialize`.
```tsx
import type { ReactNode } from 'react'
import { SWRConfig, unstable_serialize } from 'swr'
import {
backendApi,
getCurrentUserKey,
getPostListKey,
} 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: {
[unstable_serialize(getCurrentUserKey())]: userPromise,
[unstable_serialize(getPostListKey())]: postsPromise,
},
}}
>
{children}
</SWRConfig>
)
}
```
Подробнее о стратегиях запросов и начальных данных для клиентских хуков: [REST → Стратегии получения данных](../data/rest/strategies/index.md), [REST → Начальные данные для клиентских хуков](../data/rest/strategies/client-hooks-initial-data.md).
## Инициализация состояния
Файл роутинга может подключить готовый провайдер стора страницы, если состояние зависит от маршрута или данных первого рендера. Реализация стора и провайдера не размещается в `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
'use client'
import { ErrorScreen } from 'screens/error'
type ErrorPageProps = {
error: Error & { digest?: string }
reset: () => void
}
const ErrorPage = ({ error, reset }: ErrorPageProps) => {
return <ErrorScreen error={error} reset={reset} />
}
export default ErrorPage
```