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

8.2 KiB
Raw Blame History

title, description
title description
Файлы роутинга Как работать со страницами и другими файлами роутинга Next.js App Router.

Файлы роутинга

Как работать со страницами и другими файлами роутинга Next.js App Router.

Назначение

src/app/** — точка входа приложения и слой файлового роутинга Next.js.

Файлы роутинга не реализуют интерфейс. Они описывают маршрут: читают параметры, получают данные первого рендера, подготавливают кеш или состояние и передают результат в screen.

Границы слоя описаны в Архитектура → Слои → 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.

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. Сам запрос выполняется через готовый клиент или сервис нижнего слоя.

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.

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 → Стратегии получения данных, REST → Начальные данные для клиентских хуков.

Инициализация состояния

Файл роутинга может подключить готовый провайдер стора страницы, если состояние зависит от маршрута или данных первого рендера. Реализация стора и провайдера не размещается в src/app/**.

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 к пропсам нижнего слоя.

'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