Перейти к основному содержимому

Использование с Next.js

FSD совместим с Next.js как в варианте App Router, так и в варианте Pages Router, если устранить главный конфликт — папки app и pages.

App Router

Конфликт между FSD и Next.js в слое app

Next.js предлагает использовать папку app для определения маршрутов приложения. Он ожидает, что файлы в папке app будут соответствовать маршрутам. Этот механизм маршрутизации не соответствует концепции FSD, потому что невозможно сохранить плоскую структуру слайсов.

Чтоб решить эту проблему, перенесите Next.js-овскую папку app в корень проекта, а затем импортируйте FSD-страницы из src, где располагаются слои FSD, в Next.js-овскую папку app.

Вам также нужно будет добавить в корень проекта папку pages, иначе Next.js будет пытаться использовать src/pages в качестве Pages Router, даже если вы используете App Router, что приведёт к ошибкам при сборке проекта. Имеет смысл положить внутрь этой корневой папки pages файл README.md с описанием, почему эта папка нужна, даже когда она пустая.

├── app                              # Папка app (Next.js)
│ ├── api
│ │ └── get-example
│ │ └── route.ts
│ └── example
│ └── page.tsx
├── pages # Пустая папка pages (Next.js)
│ └── README.md
└── src
├── app
│ └── api-routes # API-маршруты
├── pages
│ └── example
│ ├── index.ts
│ └── ui
│ └── example.tsx
├── widgets
├── features
├── entities
└── shared

Пример ре-экспорта страницы из src/pages в Next.js-овском app:

app/example/page.tsx
export { ExamplePage as default, metadata } from '@/pages/example';

Middleware

Если вы используете middleware в проекте, оно обязательно должно располагаться в корне проекта рядом с Next.js-овскими папками app и pages.

Instrumentation

Файл instrumentation.js позволяет отслеживать производительность и поведение вашего приложения. Если вы его используете, то он обязательно должен находиться в корне проекта по аналогии с middleware.js

Pages Router

Конфликт между FSD и Next.js в слое pages

Роуты страниц должны помещаться в папку pages в корне проекта по аналогии с папкой app для App Router. Структура внутри src, где располагаются папки слоёв, остаётся без изменений.

├── pages                            # Папка pages (Next.js)
│ ├── _app.tsx
│ ├── api
│ │ └── example.ts # Ре-экспорт API-маршрутов
│ └── example
│ └── index.tsx
└── src
├── app
│ ├── custom-app
│ │ └── custom-app.tsx # Кастомный компонент App
│ └── api-routes
│ └── get-example-data.ts # API-маршрут
├── pages
│ └── example
│ ├── index.ts
│ └── ui
│ └── example.tsx
├── widgets
├── features
├── entities
└── shared

Пример ре-экспорта страницы из src/pages в Next.js-овском pages:

pages/example/index.tsx
export { Example as default } from '@/pages/example';

Кастомный компонент _app

Вы можете поместить ваш кастомный компонент App либо в src/app/_app либо в src/app/custom-app:

src/app/custom-app/custom-app.tsx
import type { AppProps } from 'next/app';

export const MyApp = ({ Component, pageProps }: AppProps) => {
return (
<>
<p>My Custom App component</p>
<Component { ...pageProps } />
</>
);
};
pages/_app.tsx
export { App as default } from '@/app/custom-app';

Route Handlers (API-маршруты)

Используйте сегмент api-routes в слое app для работы c Route Handlers.

Будьте внимательны при написании бэкенд-кода в структуре FSD — FSD в первую очередь предназначен для фронтенда, и именно это люди будут ожидать в нём найти. Если вам нужно много эндпоинтов, попробуйте выделить их в отдельный пакет в монорепозитории.

src/app/api-routes/get-example-data.ts
import { getExamplesList } from '@/shared/db';

export const getExampleData = () => {
try {
const examplesList = getExamplesList();

return Response.json({ examplesList });
} catch {
return Response.json(null, {
status: 500,
statusText: 'Ouch, something went wrong',
});
}
};
app/api/example/route.ts
export { getExampleData as GET } from '@/app/api-routes';

Дополнительные рекомендации

  • Используйте сегмент db в слое shared для описания запросов к БД и их дальнейшего использования в вышестоящих слоях.
  • Логику кэширования и ревалидации запросов лучше держать там же, где и сами запросы.

См. также