NextJSとの併用
srcフォルダー
Section titled “srcフォルダー”NextJSは、プロジェクトのルートまたはsrcフォルダーのいずれかに、特別なappまたはpagesフォルダーを期待します。一般的には、srcフォルダーにFSDコードのみが含まれるように、NextJSのフォルダーをプロジェクトのルートに配置する方が簡単ですが、必須ではありません。
App Router
Section titled “App Router”NextJSはApp Routerにappフォルダーを、Pages Routerにpagesフォルダーを使用しますが、これはFSDの層名と競合します。この競合を解決するには、appの代わりに_app、pagesの代わりに_pagesのように、FSD層にプレフィックス付きの名前を使用してください。このアプローチは公式のリンターとも互換性があります。
ディレクトリapp NextJSのappフォルダー
ディレクトリapi/
ディレクトリget-example/
- route.ts
ディレクトリexample/
- page.tsx
ディレクトリsrc/
ディレクトリ_app/ FSD層
ディレクトリapi-routes/ APIルート
- …
ディレクトリ_pages/ FSD層
ディレクトリexample/
- index.ts
ディレクトリui/
- example.tsx
ディレクトリwidgets/
- …
ディレクトリfeatures/
- …
ディレクトリentities/
- …
ディレクトリshared/
- …
NextJSのapp内でsrc/_pagesからページを再エクスポートする例:
export { ExamplePage as default, metadata } from '@/_pages/example';サーバーとクライアントのパブリックAPI
Section titled “サーバーとクライアントのパブリックAPI”NextJSのApp Routerでは、クライアントで使用できるモジュールとサーバー専用のモジュールが、1つのスライス内に共存することがあります。サーバー専用のモジュールがindex.tsからエクスポートされている場合、クライアントコンポーネントがそのスライスをインポートすると、サーバー専用の副作用がクライアントのモジュールグラフに伝播し、ビルドエラーにつながる可能性があります。
この問題が発生した場合は、パブリックAPIにindex.server.tsを追加してください。
index.server.ts: サーバーコンポーネントやserver-onlyでマークされたデータアクセス関数など、サーバーでのみインポートされる必要があるモジュール
Middleware
Section titled “Middleware”プロジェクトでミドルウェアを使用する場合は、NextJSのappおよびpagesフォルダーと並んでプロジェクトのルートに配置する必要があります。
Instrumentation
Section titled “Instrumentation”instrumentation.jsファイルを使用すると、アプリケーションのパフォーマンスと動作を監視できます。使用する場合は、middleware.jsと同様にプロジェクトのルートに配置する必要があります。
Pages Router
Section titled “Pages Router”pages層におけるFSDとNextJSの競合
Section titled “pages層におけるFSDとNextJSの競合”App Routerのappフォルダーと同様に、ルートはプロジェクトのルートにあるpagesフォルダーに配置する必要があります。層フォルダーが配置されているsrc内の構造は変わりません。
ディレクトリpages/ pagesフォルダー(NextJS)
- _app.tsx
ディレクトリapi/
- example.ts APIルートの再エクスポート
ディレクトリexample/
- index.tsx
ディレクトリsrc/
ディレクトリ_app/ FSD層
ディレクトリcustom-app/
- custom-app.tsx カスタムAppコンポーネント
ディレクトリapi-routes/
- get-example-data.ts APIルート
ディレクトリ_pages/ FSD層
ディレクトリexample/
- index.ts
ディレクトリui/
- example.tsx
ディレクトリwidgets/
- …
ディレクトリfeatures/
- …
ディレクトリentities/
- …
ディレクトリshared/
- …
NextJSのpages内でsrc/_pagesからページを再エクスポートする例:
export { Example as default } from '@/_pages/example';カスタム_appコンポーネント
Section titled “カスタム_appコンポーネント”カスタムAppコンポーネントはsrc/_app/_appまたはsrc/_app/custom-appに配置できます:
import type { AppProps } from 'next/app';
export const MyApp = ({ Component, pageProps }: AppProps) => { return ( <> <p>My Custom App component</p> <Component { ...pageProps } /> </> );};export { App as default } from '@/_app/custom-app';ルートハンドラー(APIルート)
Section titled “ルートハンドラー(APIルート)”ルートハンドラーを扱うには、_app層のapi-routesセグメントを使用します。
FSD構造内でバックエンドのコードを書く際は注意してください。FSDは主にフロントエンドを対象としており、それが人々が見つけることを期待するものだからです。 多くのエンドポイントが必要な場合は、モノレポ内の別のパッケージに分離することを検討してください。
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', }); }};export { getExampleData as GET } from '@/_app/api-routes';import type { NextApiRequest, NextApiResponse } from 'next';
const config = { api: { bodyParser: { sizeLimit: '1mb', }, }, maxDuration: 5,};
const handler = (req: NextApiRequest, res: NextApiResponse<ResponseData>) => { res.status(200).json({ message: 'Hello from FSD' });};
export const getExampleData = { config, handler } as const;export { getExampleData } from './get-example-data';import { getExampleData } from '@/_app/api-routes';
export const config = getExampleData.config;export default getExampleData.handler;追加の推奨事項
Section titled “追加の推奨事項”- データベースクエリの記述と上位層でのその利用には、
shared層のdbセグメントを使用してください。 - クエリのキャッシュと再検証のロジックは、クエリ自体と同じ場所に保持する方が良いでしょう。