Next.js ディレクトリ設計

TL;DR

- __tests__
- components // アプリケーション全体で共有されるコンポーネントを定義
- config // アプリケーションで使用される設定ファイルを管理
- features // featureごとにモジュールを管理
  - auth
    - api
    - components
    - types
- layouts // ページごとに異なるLayoutを定義
- lib // アプリケーションで使用されるライブラリを管理
- pages // Next.jsのページを管理
- providers // Context APIのProviderを管理
- stores //  Globalに管理するStateを定義
- testing // テストに関連するファイルを管理
- types // アプリケーション全体で使用されるTypeScriptの型定義を管理
- utils // ユーティリティ関数を管理

featuresディレクトリ

features/auth
- api // API関連のファイルを管理
- components // featureに関心のあるcomponentを管理
- types // 型定義
- index.ts // 外部に公開するもののみを選択してexportする

package by layerとpackage by feature

Bad

- components
  - User
    - UserCard.tsx
    - UserList.tsx
- hooks
  - useUsers.ts
- pages
  - users
    - [id].tsx
    - index.tsx
- services
  - userService.ts
- types
  - User.ts
- utils
  - formatUserDate.ts

こちらのディレクトリ設定の何が問題なのかというと、「ユーザー管理」機能に関連するファイルが分散していることです。

例えば、以下の機能を改修したいとします。

  • ユーザーAPIのエンドポイントを変更する
  • ユーザーAPIのレスポンスを加工する
  • ユーザーのUIを変更する

この時に、hooksやservicesなどプロジェクト全体を探し回る必要がありコストがかかります。もし、これらのファイルが一つのフォルダ(users)にまとめられていれば、探すコストがかかりません。 また、特定の機能に関する変更が複数のレイヤーにまたがるため、変更の影響範囲が広がりやすいです。

こちらのディレクトリ設計は、componentsやhooks、servicesといった技術的なレイヤーの単位で分けられています。 この設計を「package by layer」と呼びます。他にも、技術駆動パッケージングとも呼ばれます。

Good

- features
  - users
    - components
      - UserCard.tsx
      - UserList.tsx
    - hooks
      - useUsers.ts
    - pages
      - [id].tsx
      - index.tsx
    - services
      - userService.ts
    - types
        - User.ts
    - utils
      - formatUserDate.ts

良いコードの例です。こちらは「ユーザー管理」機能に関連するファイルが一つのフォルダ(features/users)にまとめられています。そのため、対象のファイルを探すコストがかかりません。 この設計を「package by feature」と呼びます。

参考