T-CREATOR

Vite プロジェクトのディレクトリ設計ベストプラクティス

Vite プロジェクトのディレクトリ設計ベストプラクティス

Viteプロジェクトで効率的な開発を行うためには、プロジェクト開始時のディレクトリ設計が非常に重要です。適切に構造化されたプロジェクトは、開発効率を大幅に向上させ、チーム開発における混乱を防ぎます。

本記事では、Viteプロジェクトにおけるディレクトリ設計のベストプラクティスを、基本的な考え方から実践的な応用まで段階的にご説明いたします。プロジェクトの規模に応じた最適な構造を理解し、長期的にメンテナンスしやすいコードベースを構築していきましょう。

背景

Viteの特徴とディレクトリ設計への影響

Viteは、ESモジュールベースの高速な開発環境を提供するビルドツールです。その特徴的な仕組みが、ディレクトリ設計にも大きな影響を与えています。

以下の図は、Viteのビルドシステムと開発時の動作を示しています。

mermaidflowchart LR
  dev[開発モード] -->|ESモジュール| browser[ブラウザ]
  build[ビルドモード] -->|バンドル| dist[本番ファイル]
  
  subgraph vite[Vite システム]
    hmr[HMR]
    transform[変換処理]
    optimize[依存関係最適化]
  end
  
  dev --> vite
  vite --> browser
  build --> vite
  vite --> dist

補足:開発時はファイルを個別に配信し、本番時はバンドルして最適化されます。この違いがディレクトリ設計に影響します。

Viteの主な特徴として以下があります:

  • 高速な開発サーバー起動: ESモジュールを活用した即座の起動
  • 効率的なHMR(Hot Module Replacement): 変更したファイルのみを瞬時に更新
  • 最適化されたビルド: Rollupベースの高性能バンドル処理

従来のバンドラーとの違い

従来のWebpackなどのバンドラーと比較すると、Viteには以下のような特徴があります。

項目WebpackVite
開発時の処理全ファイルをバンドルESモジュールで個別配信
起動速度プロジェクトサイズに比例一定時間で高速
HMRバンドル再構築変更ファイルのみ更新
設定の複雑さ高度な設定が必要シンプルな設定

モダンフロントエンド開発における構造化の必要性

現代のフロントエンド開発では、以下のような要素を適切に管理する必要があります:

  • コンポーネント: 再利用可能なUI部品
  • 状態管理: アプリケーション全体の状態
  • API通信: バックエンドとのデータ交換
  • 型定義: TypeScriptでの型安全性
  • テスト: 品質保証のためのテストコード

これらの要素を論理的に整理し、開発者が直感的に理解できる構造を作ることが重要です。

課題

スケールアップ時の構造破綻

多くのプロジェクトが直面する最大の課題は、プロジェクトの成長に伴う構造の破綻です。

初期段階では問題にならない以下のような構造が、プロジェクトの拡大とともに深刻な問題となります:

typescript// 問題のある初期構造の例
src/
├── components/          // すべてのコンポーネントが混在
│   ├── Header.tsx
│   ├── Footer.tsx
│   ├── UserProfile.tsx
│   ├── ProductList.tsx
│   ├── PaymentForm.tsx
│   └── ... (100個以上のファイル)
├── utils/              // 雑多なユーティリティ
│   ├── helpers.ts
│   ├── api.ts
│   ├── validation.ts
│   └── misc.ts
└── App.tsx

このような構造では、以下の問題が発生します:

  • ファイル検索の困難さ: 特定のコンポーネントを見つけるのに時間がかかる
  • 責務の不明確さ: どこに何を配置すべきかの判断基準がない
  • 依存関係の複雑化: コンポーネント間の関係が見えにくい

チーム開発での一貫性不足

チーム開発において一貫性のないディレクトリ構造は、以下の問題を引き起こします:

  • 新メンバーのオンボーディング遅延: プロジェクト構造の理解に時間がかかる
  • コードレビューの非効率性: ファイルの配置場所について議論が発生
  • 機能追加時の迷い: 新しいファイルをどこに配置すべきか判断できない

メンテナンス性の低下

適切な構造化がされていないプロジェクトでは、以下のようなメンテナンス性の問題が発生します:

mermaidflowchart TD
  poor[不適切な構造] --> search[ファイル検索困難]
  poor --> deps[依存関係不明]
  poor --> dup[重複コード]
  
  search --> time[開発時間増加]
  deps --> bugs[バグ発生率上昇]
  dup --> maintenance[メンテナンス負荷]
  
  time --> cost[開発コスト増]
  bugs --> cost
  maintenance --> cost

図で理解できる要点:

  • 不適切な構造が連鎖的に開発効率を下げる
  • 結果的に開発コストの大幅な増加につながる
  • 早期の構造改善が重要

解決策

基本的なディレクトリ構造

Viteプロジェクトの基本的なディレクトリ構造について、段階的に解説いたします。

src/フォルダ構成の基本原則

src/フォルダは、アプリケーションのメインコードを格納する最も重要なディレクトリです。以下の原則に従って構成します:

typescriptsrc/
├── components/         // 再利用可能なUIコンポーネント
├── pages/             // ページコンポーネント
├── layouts/           // レイアウトコンポーネント
├── hooks/             // カスタムフック(React)
├── stores/            // 状態管理
├── services/          // API通信とビジネスロジック
├── utils/             // ユーティリティ関数
├── types/             // 型定義
├── assets/            // 画像、フォントなどの静的ファイル
├── styles/            // グローバルスタイル
└── main.tsx           // エントリーポイント

各ディレクトリの責務を明確に定義することで、開発者が迷うことなくファイルを配置できます。

public/とassets/の使い分け

Viteプロジェクトでは、静的ファイルの管理において2つの主要なディレクトリがあります:

typescript// public/ディレクトリ(ビルド時にそのままコピー)
public/
├── favicon.ico        // ファビコン
├── robots.txt         // SEO関連ファイル
├── manifest.json      // PWA設定
└── images/            // 変更されない画像ファイル
    └── logo.png

// src/assets/ディレクトリ(ビルド時に最適化・ハッシュ化)
src/assets/
├── images/            // コンポーネントで使用する画像
│   ├── icons/
│   └── photos/
├── fonts/             // Webフォント
└── data/              // JSONデータファイル

使い分けのルール

  • public/: 絶対パスでアクセスし、ビルド時に変更されない静的ファイル
  • src/assets/: インポートして使用し、ビルド時に最適化される動的ファイル

設定ファイルの配置方針

プロジェクトルートの設定ファイルは、機能別に整理することが重要です:

typescriptproject-root/
├── vite.config.ts     // Vite設定
├── tsconfig.json      // TypeScript設定
├── package.json       // パッケージ管理
├── .eslintrc.js       // ESLint設定
├── .prettierrc        // Prettier設定
├── tailwind.config.js // Tailwind設定(使用時)
└── .env.example       // 環境変数テンプレート

設定ファイルは、プロジェクトの性質に応じて適切に配置し、チーム全体で一貫性を保つことが重要です。

機能別ディレクトリ設計

コンポーネントの分類方法

コンポーネントは、その役割と再利用性に応じて適切に分類する必要があります。

typescriptsrc/components/
├── ui/                // 基本的なUIコンポーネント
│   ├── Button/
│   │   ├── Button.tsx
│   │   ├── Button.module.css
│   │   └── index.ts
│   ├── Input/
│   └── Modal/
├── features/          // 機能固有のコンポーネント
│   ├── auth/
│   │   ├── LoginForm/
│   │   ├── SignupForm/
│   │   └── UserProfile/
│   ├── products/
│   │   ├── ProductCard/
│   │   ├── ProductList/
│   │   └── ProductFilter/
│   └── checkout/
└── common/            // 共通コンポーネント
    ├── Header/
    ├── Footer/
    └── Navigation/

分類の基準

  • ui/: デザインシステムの基本コンポーネント(ビジネスロジックを含まない)
  • features/: 特定の機能領域に関連するコンポーネント
  • common/: アプリケーション全体で使用される共通コンポーネント

ページとレイアウトの分離

ページコンポーネントとレイアウトコンポーネントを明確に分離することで、保守性が向上します:

typescriptsrc/pages/
├── Home/
│   ├── Home.tsx       // ページコンポーネント
│   ├── Home.module.css
│   └── index.ts
├── Products/
│   ├── ProductList.tsx
│   ├── ProductDetail.tsx
│   └── index.ts
└── Auth/
    ├── Login.tsx
    ├── Signup.tsx
    └── index.ts

src/layouts/
├── AppLayout/         // メインレイアウト
│   ├── AppLayout.tsx
│   ├── AppLayout.module.css
│   └── index.ts
├── AuthLayout/        // 認証ページ用レイアウト
└── AdminLayout/       // 管理画面用レイアウト

レイアウトコンポーネントは、ページの共通構造を定義し、ヘッダー、フッター、サイドバーなどの配置を管理します。

ユーティリティとヘルパーの整理

ユーティリティ関数は、機能別に細かく分類して管理します:

typescriptsrc/utils/
├── format/            // データフォーマット関連
│   ├── date.ts
│   ├── currency.ts
│   └── number.ts
├── validation/        // バリデーション関数
│   ├── email.ts
│   ├── password.ts
│   └── form.ts
├── api/              // API関連ユーティリティ
│   ├── client.ts
│   ├── endpoints.ts
│   └── interceptors.ts
└── dom/              // DOM操作関連
    ├── scroll.ts
    └── focus.ts

各ユーティリティファイルは、単一の責任を持つ純粋関数として実装し、テストしやすい構造にします。

状態管理とAPIの構造化

stores/とservices/の役割分担

状態管理とAPI通信は、明確に役割を分担して管理します:

typescriptsrc/stores/
├── auth/              // 認証状態管理
│   ├── authStore.ts
│   ├── authTypes.ts
│   └── index.ts
├── products/          // 商品状態管理
│   ├── productStore.ts
│   ├── productTypes.ts
│   └── index.ts
└── ui/                // UI状態管理
    ├── modalStore.ts
    ├── themeStore.ts
    └── index.ts

src/services/
├── auth/              // 認証API
│   ├── authApi.ts
│   ├── authService.ts
│   └── index.ts
├── products/          // 商品API
│   ├── productApi.ts
│   ├── productService.ts
│   └── index.ts
└── common/            // 共通API設定
    ├── apiClient.ts
    ├── errorHandler.ts
    └── index.ts

役割分担の原則

  • stores/: アプリケーションの状態管理とビジネスロジック
  • services/: 外部APIとの通信とデータ変換

hooks/とcomposables/の配置

カスタムフック(React)やコンポーザブル(Vue)は、機能別に整理します:

typescriptsrc/hooks/
├── api/               // API関連フック
│   ├── useAuth.ts
│   ├── useProducts.ts
│   └── useApi.ts
├── ui/                // UI関連フック
│   ├── useModal.ts
│   ├── useForm.ts
│   └── useLocalStorage.ts
└── business/          // ビジネスロジック関連
    ├── useCheckout.ts
    ├── useValidation.ts
    └── usePermission.ts

カスタムフックは、ロジックの再利用性を高め、コンポーネントの複雑さを軽減する重要な役割を果たします。

型定義ファイルの管理

TypeScriptの型定義は、機能別に整理し、適切にエクスポートします:

typescriptsrc/types/
├── api/               // API関連の型定義
│   ├── auth.ts
│   ├── products.ts
│   └── common.ts
├── components/        // コンポーネントの型定義
│   ├── ui.ts
│   └── props.ts
├── stores/            // 状態管理の型定義
│   ├── auth.ts
│   └── products.ts
└── index.ts           // 型定義のエクスポート

型定義を適切に整理することで、TypeScriptの恩恵を最大限に活用できます。

具体例

小規模プロジェクトの実装例

小規模プロジェクト(10〜20ページ程度)では、シンプルながら拡張性を考慮した構造を採用します。

typescript// 小規模プロジェクトの構造例
src/
├── components/
│   ├── ui/            // 基本コンポーネント(5-10個)
│   │   ├── Button.tsx
│   │   ├── Input.tsx
│   │   └── Card.tsx
│   └── common/        // 共通コンポーネント(3-5個)
│       ├── Header.tsx
│       ├── Footer.tsx
│       └── Navigation.tsx
├── pages/             // ページコンポーネント(10-20個)
│   ├── Home.tsx
│   ├── About.tsx
│   ├── Contact.tsx
│   └── Products.tsx
├── hooks/             // カスタムフック(3-5個)
│   ├── useApi.ts
│   ├── useForm.ts
│   └── useLocalStorage.ts
├── services/          // API通信(2-3個)
│   ├── apiClient.ts
│   └── productsApi.ts
├── utils/             // ユーティリティ(5-10個)
│   ├── format.ts
│   ├── validation.ts
│   └── constants.ts
├── types/             // 型定義
│   └── index.ts
├── styles/            // グローバルスタイル
│   └── globals.css
└── main.tsx

小規模プロジェクトでの設計ポイントは以下の通りです:

  • シンプルさを重視: 過度な分類は避ける
  • 拡張性の確保: 将来の成長に備えた基本構造
  • 明確な責務分離: 各ディレクトリの役割を明確にする

中規模アプリケーションの構造

中規模アプリケーション(50〜100ページ程度)では、機能別の分類をより詳細に行います。

typescript// 中規模アプリケーションの構造例
src/
├── components/
│   ├── ui/            // デザインシステム(20-30個)
│   │   ├── forms/
│   │   │   ├── Input/
│   │   │   ├── Select/
│   │   │   └── TextArea/
│   │   ├── feedback/
│   │   │   ├── Alert/
│   │   │   ├── Toast/
│   │   │   └── Loading/
│   │   └── navigation/
│   │       ├── Button/
│   │       ├── Link/
│   │       └── Breadcrumb/
│   ├── features/      // 機能別コンポーネント
│   │   ├── auth/
│   │   │   ├── LoginForm/
│   │   │   ├── SignupForm/
│   │   │   └── UserProfile/
│   │   ├── products/
│   │   │   ├── ProductCard/
│   │   │   ├── ProductList/
│   │   │   ├── ProductFilter/
│   │   │   └── ProductSearch/
│   │   ├── orders/
│   │   │   ├── OrderSummary/
│   │   │   ├── OrderHistory/
│   │   │   └── OrderTracking/
│   │   └── dashboard/
│   │       ├── StatsCard/
│   │       ├── Chart/
│   │       └── RecentActivity/
│   └── layouts/       // レイアウトコンポーネント
│       ├── AppLayout/
│       ├── AuthLayout/
│       └── DashboardLayout/
├── pages/             // ページコンポーネント(50-100個)
│   ├── auth/
│   ├── products/
│   ├── orders/
│   ├── dashboard/
│   └── settings/
├── stores/            // 状態管理(5-10個)
│   ├── auth/
│   ├── products/
│   ├── orders/
│   ├── ui/
│   └── index.ts
├── services/          // API通信(10-15個)
│   ├── auth/
│   ├── products/
│   ├── orders/
│   ├── analytics/
│   └── common/
├── hooks/             // カスタムフック(15-25個)
│   ├── api/
│   ├── ui/
│   └── business/
├── utils/             // ユーティリティ(15-20個)
│   ├── format/
│   ├── validation/
│   ├── api/
│   └── dom/
└── types/             // 型定義
    ├── api/
    ├── components/
    └── stores/

中規模アプリケーションでの重要なポイント:

  • 機能別の明確な分類: featureディレクトリによる機能分離
  • 階層的な構造: カテゴリごとのサブディレクトリ
  • 一貫性のある命名: チーム全体で統一された命名規則

以下の図は、中規模アプリケーションにおけるコンポーネント間の依存関係を示しています。

mermaidflowchart TD
  pages[Pages] --> features[Features]
  pages --> layouts[Layouts]
  features --> ui[UI Components]
  layouts --> ui
  features --> hooks[Custom Hooks]
  hooks --> services[Services]
  hooks --> stores[Stores]
  services --> api[API Client]
  stores --> types[Types]
  services --> types

図で理解できる要点:

  • ページコンポーネントが最上位レイヤー
  • 機能別コンポーネントが中間レイヤー
  • UIコンポーネントが最下位レイヤー

大規模システムでの設計パターン

大規模システム(100ページ以上、複数チーム開発)では、モノリポジトリやマイクロフロントエンドの考慮が必要です。

typescript// 大規模システムの構造例
src/
├── apps/              // アプリケーション別
│   ├── admin/         // 管理者画面
│   ├── customer/      // 顧客向け画面
│   └── mobile/        // モバイルアプリ
├── shared/            // 共通モジュール
│   ├── components/    // 共通コンポーネント
│   │   ├── ui/
│   │   └── layouts/
│   ├── hooks/         // 共通フック
│   ├── services/      // 共通サービス
│   ├── stores/        // 共通状態管理
│   ├── utils/         // 共通ユーティリティ
│   └── types/         // 共通型定義
├── features/          // ドメイン別機能
│   ├── auth/          // 認証機能
│   │   ├── components/
│   │   ├── hooks/
│   │   ├── services/
│   │   ├── stores/
│   │   └── types/
│   ├── products/      // 商品機能
│   │   ├── components/
│   │   ├── hooks/
│   │   ├── services/
│   │   ├── stores/
│   │   └── types/
│   └── orders/        // 注文機能
│       ├── components/
│       ├── hooks/
│       ├── services/
│       ├── stores/
│       └── types/
├── libs/              // ライブラリ
│   ├── design-system/ // デザインシステム
│   ├── api-client/    // API通信ライブラリ
│   └── validation/    // バリデーションライブラリ
└── config/            // 設定ファイル
    ├── build/
    ├── env/
    └── deployment/

大規模システムでの設計パターンの特徴:

  • ドメイン駆動設計: ビジネスドメインごとの機能分離
  • 共通モジュール化: 重複コードの排除と一貫性の確保
  • 独立性の確保: 各機能が独立して開発・デプロイ可能

以下の図は、大規模システムにおけるモジュール間の関係を示しています。

mermaidflowchart TB
  subgraph apps[Applications]
    admin[Admin App]
    customer[Customer App]
    mobile[Mobile App]
  end
  
  subgraph features[Domain Features]
    auth[Auth Domain]
    products[Products Domain]
    orders[Orders Domain]
  end
  
  subgraph shared[Shared Modules]
    ui[UI Components]
    hooks[Common Hooks]
    services[Common Services]
  end
  
  subgraph libs[Libraries]
    design[Design System]
    api[API Client]
    validation[Validation]
  end
  
  apps --> features
  apps --> shared
  features --> shared
  features --> libs
  shared --> libs

図で理解できる要点:

  • アプリケーションレイヤーが最上位
  • ドメイン機能が独立したモジュール
  • 共通モジュールとライブラリが基盤

まとめ

ディレクトリ設計のチェックリスト

Viteプロジェクトのディレクトリ設計において、以下のチェックリストを活用してください:

基本構造のチェックポイント

  • 責務の明確性: 各ディレクトリの役割が明確に定義されている
  • 一貫性: 命名規則とファイル配置が一貫している
  • 拡張性: プロジェクトの成長に対応できる構造
  • 検索性: 必要なファイルを素早く見つけることができる

コンポーネント構造のチェックポイント

  • 分類の適切性: ui/features/common の分類が適切
  • 再利用性: コンポーネントの再利用性が考慮されている
  • 依存関係: コンポーネント間の依存関係が明確
  • テスト可能性: 各コンポーネントが独立してテスト可能

状態管理とAPIのチェックポイント

  • 役割分担: stores/とservices/の役割が明確に分離
  • 型安全性: TypeScriptの型定義が適切に管理
  • エラーハンドリング: 一貫したエラー処理の仕組み
  • パフォーマンス: 不要な再レンダリングや通信の回避

開発効率のチェックポイント

  • オンボーディング: 新メンバーが構造を理解しやすい
  • メンテナンス性: 機能追加や修正が容易
  • ビルド最適化: Viteの特性を活かした構造
  • 開発体験: Hot Module Replacementが効率的に動作

プロジェクト成長に合わせた改善方針

プロジェクトの成長段階に応じて、以下のような改善方針を検討してください:

小規模から中規模への移行

プロジェクトが成長し始めたタイミングで実施すべき改善:

typescript// Before: 小規模構造
src/components/
├── Button.tsx
├── Header.tsx
├── ProductCard.tsx
└── UserProfile.tsx

// After: 中規模構造への移行
src/components/
├── ui/
│   └── Button/
├── common/
│   └── Header/
└── features/
    ├── products/
    │   └── ProductCard/
    └── auth/
        └── UserProfile/

移行のポイント:

  • 段階的な移行: 一度にすべてを変更せず、段階的に改善
  • チームの合意: 構造変更についてチーム全体で合意形成
  • 自動化: リファクタリングツールを活用した効率的な移行

中規模から大規模への移行

より大きなプロジェクトへの移行では、以下の点を考慮します:

  • ドメイン分離: ビジネスドメインごとの機能分離
  • 共通化: 重複するコードの共通モジュール化
  • 独立性: 各機能の独立した開発・デプロイ体制

継続的改善のプロセス

ディレクトリ設計の改善は継続的なプロセスです:

mermaidflowchart LR
  analyze[現状分析] --> plan[改善計画]
  plan --> implement[実装]
  implement --> measure[効果測定]
  measure --> analyze
  
  subgraph metrics[測定指標]
    build[ビルド時間]
    search[ファイル検索時間]
    onboard[オンボーディング時間]
  end
  
  measure --> metrics

図で理解できる要点:

  • 継続的な改善サイクルが重要
  • 具体的な指標による効果測定
  • データ駆動での構造改善

改善の指標例

  • 開発効率: 機能実装にかかる時間の短縮
  • コード品質: バグ発生率の低下、テストカバレッジの向上
  • チーム効率: コードレビュー時間の短縮、オンボーディング期間の短縮

ディレクトリ設計は、プロジェクトの成功に直結する重要な要素です。適切な構造を構築し、継続的に改善することで、長期的に安定したプロジェクトを維持できます。Viteの特性を活かしながら、チーム全体が効率的に開発できる環境を整えていきましょう。

関連リンク

Vite公式ドキュメント

ベストプラクティス参考資料