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には以下のような特徴があります。
項目 | Webpack | Vite |
---|---|---|
開発時の処理 | 全ファイルをバンドル | 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公式ドキュメント
- Vite公式サイト - Viteの基本的な使い方と設定方法
- Vite設定リファレンス - 詳細な設定オプション
- Vite プラグインガイド - プラグインの活用方法
ベストプラクティス参考資料
- React アプリケーションアーキテクチャ - Reactアプリケーションの設計思想
- Vue.js スタイルガイド - Vue.jsプロジェクトの構造化指針
- TypeScript ハンドブック - TypeScriptの型システム活用法
- ESLint 設定ガイド - コード品質管理の設定方法
- review
今の自分に満足していますか?『持たざる者の逆襲 まだ何者でもない君へ』溝口勇児
- review
ついに語られた業界の裏側!『フジテレビの正体』堀江貴文が描くテレビ局の本当の姿
- review
愛する勇気を持てば人生が変わる!『幸せになる勇気』岸見一郎・古賀史健のアドラー実践編で真の幸福を手に入れる
- review
週末を変えれば年収も変わる!『世界の一流は「休日」に何をしているのか』越川慎司の一流週末メソッド
- review
新しい自分に会いに行こう!『自分の変え方』村岡大樹の認知科学コーチングで人生リセット
- review
科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来