chibaqn /
Posts
2022-08-10 00:19:22

Next.js のディレクトリ構成と依存方向について

はじめに

Next.js でブログを開発する中で特定の機能(ページ)に関するロジックが散らばっているのが気になった。

下記について考えてみて、このブログのディレクトリ構成(設計モデル・アーキテクチャ)を決める。

  • 各モジュールの責務
  • 依存方向

現状のディレクトリ構成と依存方向

Next.js 公式のサンプルアプリ のディレクトリ構成そのままである。

├── _post/
├── .next/
├── components/
│   ├── header/
│   ├── post/
│   ├── footer.tsx
│   ├── header.tsx
│   ├── layout.tsx
│   └── postList.tsx
├── interfaces/
│   ├── post.ts
│   └── tag.ts
├── lib/
│   ├── markdownToHtml.ts
│   ├── posts.ts
│   └── tags.ts
├── node_modules/
├── pages/
│   ├── posts/
│   ├── tags/
│   ├── _app.tsx
│   ├── _document.tsx
│   └── index.tsx
├── public/
├── styles/
│   └── globals.css
├── .eslintrc.json
├── .gitignore
├── .node-version
├── next-env.d.ts
├── next-config.js
├── package-lock.json
├── package.json
├── postcss.config.js
├── README.md
├── tailwind.config.js
├── tsconfig.json
└── yarn.lock

依存方向は下記の通り。

  • interfaces(TypeScriptの型定義)pages, components, lib それぞれから参照(import)されている。
  • componentslib はお互いに参照しない。
  • 自分と同じ種別は参照できる。

気になっていること

components について

  • components 配下に置かれているファイルが「アプリケーション内での共通度合い(全ページ共通、複数ページで共通、1つのページ固有)」の観点でごちゃまぜであり、components 内での依存関係が整理されていない。
  • 特定のページでしか使わないコンポーネントも components 配下に置くでOKなのか。
  • また、業務ロジックは components に実装するで OK なのか。
  • 汎用的なUI要素のコンポーネントと業務ロジックをもった(特定のページ専用の)コンポーネントが混在するのが分かりづらいと思うがどうするのがよいのか。

その他

  • interfaces は型の定義なのでグローバルに参照されうると思うのだが、ソフトウェアの設計として問題ないのか(TypeScript で開発するソフトウェアでは普通のことなのか)。
  • pages にてコンポーネントを呼び出してUIを組み立てているが、pages の枠割はルーティングでは?
  • lib に置いている posts.ts, tags.ts がライブラリと呼べるのか疑問(それぞれ記事情報やタグ情報を取得するための関数を提供(export)している)。Rails だったら Model に実装するロジックだと思う。

新しいディレクトリ構成

下記を理想状態としてディレクトリ構成を考えた。

  • アプリ全体で使うものと、特定のページ・機能で使うものが区別しやすい。
  • 特定のページ・機能に関するロジックが1箇所にまとまっていて分かりやすい。
  • 依存方向が設計されていて、単方向の依存性が実現されている。

ディレクトリ構成

├── _post/
├── .next/
├── node_modules/
├── public/
├── src/
│   ├── components/
│   │   ├── layouts/
│   │   │   ├── Footer/
│   │   │   ├── Header/
│   │   │   └── layout.tsx
│   │   ├── post/
│   │   │   ├── PostBody/
│   │   │   ├── PostHeader/
│   │   │   └── index.tsx
│   │   ├── posts/
│   │   │   └── index.tsx
│   │   └── tags/
│   │       └── index.tsx
│   ├── lib/
│   │   ├── markdownToHtml.ts
│   │   ├── posts.ts
│   │   └── tags.ts
│   ├── pages/
│   │   ├── posts/
│   │   ├── tags/
│   │   ├── _app.tsx
│   │   ├── _document.tsx
│   │   └── index.tsx
│   ├─ styles/
│   │  └── globals.css
│   └─ types/
│       ├── post.ts
│       └── tag.ts
├── .eslintrc.json
├── .gitignore
├── .node-version
├── next-env.d.ts
├── next-config.js
├── package-lock.json
├── package.json
├── postcss.config.js
├── README.md
├── tailwind.config.js
├── tsconfig.json
└── yarn.lock

components

  • アプリケーションで共通のコンポーネントは components/layouts に置く。
  • 特定のページ・機能でした使わないコンポーネントは、ページ・機能単位でディレクトリを作成することにした。

その他

  • src ディレクトリにソースコードを配置した。
  • pageslib は変化なし。

依存方向

変化なし。公式のデモアプリ も同様の依存方向となっていたので、OKと判断した。

おわりに

このブログアプリくらいの規模の場合、コンポーネントが機能単位でまとまっていれば十分と思った。

ただ、下記の部分がもやもやするので、Next.js のディレクトリ構成(依存方向の制御)については引き続き事例をキャッチアップしたい。

モヤモヤ🤔

  • 静的ページをビルドするために pages/ では、getStaticProps, getStaticPaths を呼び出す必要がある。
  • getStaticProps, getStaticPaths では関数を呼び出してデータを取得し、レンダリングやパス情報の取得をする。
  • この「データを取得するための関数」は現状 lib/ に置いている。
  • 特定のページ・機能でしか呼ばれない関数の場合、lib/ に置くのは不自然ではないか。components/機能名 配下に置くのが良い気もするが、コンポーネントではないので微妙な気がする。
  • 特定のページ・機能でしか呼ばれないコンポーネントや関数は、1つのディレクトリにまとめて配置するのがよいのではないか?

参考資料