最新記事の通知を受け取る

最新記事公開時にプッシュ通知します

App Router時代における「大規模React開発」のフォルダ設計術。Colocationによる関心の分離

2025年9月10日

App Router時代における「大規模React開発」のフォルダ設計術。Colocationによる関心の分離[レバテックLAB]

執筆

中川 幸哉

有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)に所属するテクニカルライター。新潟県上越市出身。会津大学コンピュータ理工学部卒業後、現在は新潟市に在住。ReactやAndroidを軸に、モバイルアプリ開発やWebサイト制作、Webメディア編集部の業務改善や、プログラミング技術記事の執筆等に携わっている。著書に「たった1日で基本が身に付く! Androidアプリ開発超入門」(技術評論社)、「基礎から学ぶ React Native入門」(翔泳社)他。

監修

山田 祥寛

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。
主な著書に「独習」シリーズ、「これからはじめるReact実践入門」、「改訂3版 JavaScript本格入門」他、著書多数

はじめに:理論から実践へ

前回は、フォルダ設計の基礎理論として、フラット構造から技術別分類、そして機能別分類への進化について学びました。特に機能別分類の優位性として、関連ファイルの物理的近接、変更影響範囲の明確化、チーム分業の責任範囲明確化という3つの重要なメリットを確認しました。

今回は、機能別分類の理論を実際のプロジェクトでどう実装するかに焦点を当てます。現代のReact開発で特に有効な具体的なパターン、Next.js App Routerとの組み合わせ方法、そしてプロジェクトの特性に応じた選択指針について詳しく解説していきましょう。

▲Feature-based Patternのフォルダ階層

実践的フォルダ設計パターン

機能別分類の理論を理解したところで、実際にどのような構造で実装するかを見ていきましょう。ここでは現代のReact開発で特に有効な2つのパターンを詳しく解説します。

Feature-based Pattern:機能別分類の実践

Feature-based Patternは、アプリケーションの機能を軸としてファイルを分類する手法です。ECサイトを例に、具体的な構造を見てみましょう。

src/
  components/          # 共通コンポーネント
    ui/
      Button.tsx
      Modal.tsx
  features/           # 機能別フォルダ
    product/
      components/
        ProductCard.tsx
        ProductDetail.tsx
      hooks/
        useProduct.tsx
        useProductSearch.tsx
      types/
        product.types.ts
      utils/
        productUtils.ts
      index.ts          # 公開API
    cart/
      components/
        CartItem.tsx
        CartSummary.tsx
      hooks/
        useCart.tsx
      types/
        cart.types.ts
      index.ts
    auth/
      components/
        LoginForm.tsx
        SignupForm.tsx
      hooks/
        useAuth.tsx
      types/
        auth.types.ts
      index.ts

この構造では、features/フォルダ配下にproduct/cart/auth/といった機能別フォルダが配置され、それぞれの機能フォルダ内ではさらに技術別分類(components/hooks/types/utils/)を採用しています。これにより「機能単位でのまとまり」と「技術別でのわかりやすさ」を両立できます。また、components/フォルダは機能固有のコンポーネントと全体で共有される汎用コンポーネントに分けられています。

なお、Feature-based PatternはNext.js App Routerとも効果的に組み合わせることができ、これについては次のセクションで詳しく解説します。

▲Feature-based Patternのフォルダ階層

特に重要なのが各機能フォルダのindex.tsファイルです。これは機能の公開APIを定義し、他の機能から使用する際のインターフェースを明確にします。

// features/product/index.ts
export { ProductCard, ProductDetail } from './components'
export { useProduct, useProductSearch } from './hooks'
export type { Product, ProductSearchQuery } from './types'

他の機能から商品機能を使用する際は、以下のようにインポートします。

// features/cart/components/CartItem.tsx
import { ProductCard, type Product } from '../product'

この構造により、機能間の依存関係が明確になり、不適切な結合を防ぐことができます。

▲index.tsを介してファイル間の依存をまとめる

app内Colocationパターン:Next.js App Routerとの組み合わせ

Next.js App Routerを使用している場合、さらに効果的なパターンがあります。それが「app内Colocation」パターンです。

App Routerでは、page.tsxlayout.tsxloading.tsxなどの予約ファイル名以外は、app/ディレクトリ内に任意のファイルを配置できます。この特性を活用して、関連するコンポーネントをルートの近くに配置できます。

app/
  products/
    [id]/
      page.tsx             # /products/[id] のページ
      _components/         # /products/[id] のためのコンポーネント置き場
        ProductDetail.tsx
        ReviewList.tsx
      _hooks/              # /products/[id] のためのカスタムフック置き場
        useProduct.tsx
        useReviews.tsx
    page.tsx               # /products のページ
    _components/           # /products のためのコンポーネント置き場
      ProductGrid.tsx
      ProductFilters.tsx
    _hooks/                # /products のためのカスタムフック置き場
      useProductSearch.tsx
  cart/
    page.tsx               # /cart のページ
    _components/           # /cart のためのコンポーネント置き場
      CartItem.tsx
      CartSummary.tsx
    _hooks/                # /cart のためのカスタムフック置き場
      useCart.tsx

注目すべきは、ネストした動的ルート([id]/)でも同様のパターンが適用されていることです。/productsページと/products/[id]ページそれぞれに専用のコンポーネントフォルダが用意され、階層的な構造を保ちながらも関連するファイルが近接配置されています。アンダースコア接頭辞(_components/_hooks/)は、Next.jsのPrivate Folderという機能で、これらのフォルダをルーティング対象から除外し、ルート以外のファイルを整理するために使用されます。

この構造には以下のメリットがあります。

ルート特化の最適化:そのページでのみ使用されるコンポーネントを近くに配置することで、必要なコードの特定が容易になる
バンドルサイズの最適化:Next.jsの自動バンドル分割(※)と組み合わせることで、不要なコードの読み込みを避けられる
機能とルートの一致:URLの構造とフォルダ構造が一致するため、直感的な理解が可能になる
※ 各ルートで使用されるコンポーネントを自動的に別々のJavaScriptファイルに分割する機能のことを言います。

大規模なアプリケーションでは、Feature-based PatternとColocationパターンを組み合わせることも可能です。

app/
  products/
    [id]/
      page.tsx               # /products/[id] のページ
      _components/           # /products/[id] ページ専用コンポーネント
        ProductDetail.tsx    # 商品詳細ページでのみ使用
src/
  features/
    product/                 # アプリ全体で共有する商品ドメイン機能
      components/            # 複数ページで再利用可能な商品コンポーネント
        ProductCard.tsx      # 商品一覧、検索結果などで共通利用
      hooks/                 # 商品関連の共通ビジネスロジック
        useProduct.tsx       # 商品データ取得・操作の共通フック
      types/                 # 商品関連の型定義
        product.types.ts     # Product型など、アプリ全体で使用

それぞれのパターンを個別に運用した場合には、課題がありました。Feature-based Patternは複数ページで使用される共通コンポーネントの配置場所が曖昧になりがちで、Colocationパターンはドメインロジックがページ間で重複しやすいという問題があります。

このハイブリッド構造により、これらの課題を解決し、ページ固有の処理とドメイン共通の処理を適切に分離できます。

▲app/とsrc/features/の役割分担

その他のパターン:選択肢の理解

機能別分類以外にも、知っておくと選択肢が広がるパターンがいくつかあります。ここでは代表的なものを詳しく見てみましょう。

Feature-Sliced Design(FSD)

Feature-Sliced Designは、階層的な責任分離を重視したアーキテクチャです。app/(アプリケーション固有の初期化処理)、pages/(ページレベルのコンポーネント)、widgets/(ページ内の大きな機能ブロック)、features/(ビジネス機能の実装)、entities/(ビジネスエンティティ)、shared/(共通リソース)という6層のレイヤーを定義します。

このアーキテクチャの特徴は、上位層が下位層のみに依存する厳密なルールを持つことです。標準化を重視するチームや大規模プロジェクトで威力を発揮しますが、学習コストが高く、小規模プロジェクトには過度な構造となる場合があります。

Layer-based Pattern

Layer-based Patternは、プレゼンテーション層、ビジネスロジック層、データアクセス層といった関心の分離を重視したアプローチです。バックエンド的な思考に慣れたチームには理解しやすい構造ですが、フロントエンドの特性であるコンポーネント間の密な連携には必ずしも適さない場合があります。

特に、UIコンポーネントとそれに関連するフックやユーティリティが離れてしまうため、開発時の利便性が損なわれることがあります。

これらのパターンの詳細は本連載の範囲を超えますが、「機能別分類だけが唯一の解ではない」ことは理解しておくとよいでしょう。

実装時の重要ポイント

これらのパターンを実際に導入する際に押さえておくべき重要なポイントを整理しておきましょう。

index.tsによる公開API設計

機能の境界を明確にすることが最重要です。各feature内の詳細な実装は隠蔽し、必要最小限のインターフェースのみを公開することで、機能間の結合度を下げられます。export文で公開するコンポーネント、フック、型を慎重に選定し、将来的な変更の影響範囲を限定しましょう。

 段階的な移行戦略

既存プロジェクトではすべてを一度に変更するのではなく、新機能から新しい構造を適用し、既存機能は必要に応じてリファクタリングする漸進的なアプローチが現実的です。チーム全体での理解を深めながら進めることで、移行時の混乱を最小限に抑えられます。

テストファイルの配置

テスト対象のファイルと同じディレクトリに__tests__/フォルダを作成するか、.test.tsx.spec.tsx拡張子でテスト対象ファイルの隣に配置する方法があります。機能別分類では、各feature内にテストも含めることで、機能単位での完結性を保てます。

まとめ:実践的なフォルダ設計で開発効率を向上させる

今回は機能別分類の具体的な実装パターンを学びました。Feature-based PatternとNext.js App Routerとの組み合わせパターンを活用することで、現代のWebアプリケーション開発における複雑さに対応できる強固な基盤を構築できます。

特に重要なのは、小さく始めて段階的に改善する姿勢です。完璧な構造を最初から目指すのではなく、プロジェクトの成長に合わせて適切なタイミングで適用することが成功の鍵となります。

継続的なリファクタリングを通じて、チームにとって最適な構造を見つけていってください。過度な設計は避けつつ、必要なタイミングで適切なパターンを導入することが、長期的な開発効率向上につながります。

次回は、コンポーネント間のデータフローを決定する「Props設計の実践論」について詳しく解説します。Props の効果的な設計方法、型定義のベストプラクティス、そしてパフォーマンス最適化の観点まで、実践的な内容をお届けする予定です。

関連記事

人気記事

  • コピーしました

RSS
RSS