2023年5月にappDirがStatable版となった Next.js13.4 を社内プロジェクトで使用することになりました。
appDirではコロケーション化に適したディレクトリ構成が可能です。
Next.js12以前は主流だったpagesDirのディレクトリ構成では、pages/配下にファイルを置くことでページ扱いとなっており、pages/配下にページファイル以外のものを置くことはできません。
// ページ以外のファイルは置いちゃダメ
├─pages
| ├─pageA.jsx
| └─...
したがって、hogehoge.com/pageでしか使用しないコンポーネントがあったとしたら、大体の人がcomponentsディレクトリを作成してその配下にhome/componentA.jsxみたいなディレクトリ構成を試みるのではないでしょうか。
├─pages
| ├─pageA.jsx
| └─...
├─components
| ├─pageA
| | ├─componentA.jsx
| | └─...
それがappDirの構成だとコロケーション化が望めるわけです。
├─app
| ├─pageA
| | ├─page.jsx
| | ├─_components
| | | ├─componentA
| | | | ├─index.jsx
| | | | └─...
| | | └─...
appDirの構成の場合、app/配下の route directory 内でプライベートディレクトリを作る時は_components のようにアンダースコアをつければプライベートディレクトリとみなされるのでこれがコロケーション化を捗らせます。
TypeScriptの場合、homeページでしか使用しない型定義ファイルなんかも
├─app
| ├─pageA
| | ├─page.jsx
| | ├─_components
| | | ├─componentA
| | | | ├─index.jsx
| | | | └─...
| | | └─...
| | ├─_types
| | | ├─typeA.ts
| | | └─...
ただ、ドメインルートのページでのみ使用したいあれこれが出てきた時に...
├─app
| ├─_components
| | ├─componentA
| | | └─index.tsx
| | | └─...
| | └─...
| ├─_types
| | └─types.ts
| ├─pageA
| | ├─page.tsx
| | ├─_components
| | | └─componentA
| | | ├─index.tsx
| | | └─...
| | └─_types
| | └─types.ts
| └─page.tsx
こうなる。
見づらいしドメインルートのページでしか使わないようには見えない。
この問題を解決するために
├─app
| ├─(root)
| | ├─page.tsx
| │ ├─_components
| │ │ └─componentA
| │ │ │ ├─index.tsx
| │ │ │ └─...
| │ │ └─...
| │ └─_types
| | ├─types.ts
| | └─...
| ├─pageA
| │ ├─page.tsx
| │ ├─_components
| │ │ └─componentA
| │ │ ├─index.tsx
| │ │ └─...
| │ └─_types
| │ ├─types.ts
| │ └─...
のように(root)ディレクトリを作ることでURLに影響を与えることなくドメインルートのページをグルーピングできました。
汎用コンポーネントはapp/と同じ階層にcomponents/ディレクトリを作成してそこに置くようにしました。
汎用コンポーネントなのかコード分割用コンポーネントなのかをディレクトリ構成でわかるのは便利です。
(使い回す型定義などあればtypes/ディレクトリを作ったり)
styleシートやStoryBookやtestコードも入れちゃいます。
【完成系】
├─app
| ├─(root)
| | ├─page.tsx
| │ ├─_components
| │ │ └─componentA
| | │ ├─index.tsx
| | │ ├─index.module.css
| | │ ├─index.stories.tsx
| | │ └─index.test.tsx
| │ └─_types
| | └─types.ts
| └─pageA
| ├─page.tsx
| ├─_components
| │ └─componentA
| │ ├─index.tsx
| │ ├─index.module.css
| │ ├─index.stories.tsx
| │ └─index.test.tsx
| └─_types
| └─types.ts
├─components
| └─Button
| ├─index.tsx
| ├─index.module.css
| ├─index.stories.tsx
| └─index.test.tsx
├─types
| └─apiType.ts
こんな感じ
すっきりしました