DT 技術解説 Astroプロジェクトの実践的フォルダ設計 -

Astroプロジェクトの実践的フォルダ設計 - スケーラブルな構造の構築

Astroプロジェクトの規模拡大に対応できる効果的なフォルダ構造と設計パターンを解説。実践的な例とベストプラクティスを紹介

約5分で読めます
技術記事
実践的

この記事のポイント

Astroプロジェクトの規模拡大に対応できる効果的なフォルダ構造と設計パターンを解説。実践的な例とベストプラクティスを紹介

この記事では、実践的なアプローチで技術的な課題を解決する方法を詳しく解説します。具体的なコード例とともに、ベストプラクティスを学ぶことができます。

Astroプロジェクトが成長するにつれて、適切なフォルダ構造の重要性が増してきます。本記事では、保守性とスケーラビリティを考慮した実践的なフォルダ設計パターンを紹介します。

基本的なAstroプロジェクト構造

graph TD
    A[プロジェクトルート] --> B[src/]
    A --> C[public/]
    A --> D[astro.config.mjs]
    B --> E[pages/]
    B --> F[components/]
    B --> G[layouts/]
    B --> H[content/]
    B --> I[styles/]

Astroの基本構造は以下の主要ディレクトリで構成されます:

  • src/pages/ - ルーティングとページコンポーネント
  • src/components/ - 再利用可能なコンポーネント
  • src/layouts/ - ページレイアウトテンプレート
  • src/content/ - コンテンツコレクション(ブログ、ドキュメントなど)
  • public/ - 静的アセット

スケーラブルなフォルダ構造

大規模プロジェクトに対応するための拡張構造:

project-root/
├── src/
│   ├── pages/
│   │   ├── index.astro
│   │   ├── about/
│   │   │   └── index.astro
│   │   └── blog/
│   │       ├── index.astro
│   │       └── [...slug].astro
│   ├── components/
│   │   ├── common/
│   │   │   ├── Button.astro
│   │   │   ├── Card.astro
│   │   │   └── Modal.astro
│   │   ├── layout/
│   │   │   ├── Header.astro
│   │   │   ├── Footer.astro
│   │   │   └── Navigation.astro
│   │   └── features/
│   │       ├── blog/
│   │       │   ├── BlogCard.astro
│   │       │   └── BlogList.astro
│   │       └── shop/
│   │           ├── ProductCard.astro
│   │           └── CartButton.astro
│   ├── layouts/
│   │   ├── BaseLayout.astro
│   │   ├── BlogLayout.astro
│   │   └── MarkdownLayout.astro
│   ├── content/
│   │   ├── config.ts
│   │   ├── blog/
│   │   │   ├── post-1.md
│   │   │   └── post-2.md
│   │   └── products/
│   │       └── product-1.json
│   ├── lib/
│   │   ├── api/
│   │   │   └── client.ts
│   │   ├── utils/
│   │   │   ├── formatters.ts
│   │   │   └── validators.ts
│   │   └── hooks/
│   │       └── useTheme.ts
│   ├── stores/
│   │   ├── cartStore.ts
│   │   └── userStore.ts
│   ├── styles/
│   │   ├── global.css
│   │   ├── variables.css
│   │   └── components/
│   │       └── button.css
│   └── types/
│       ├── content.ts
│       └── api.ts
├── public/
│   ├── fonts/
│   ├── images/
│   └── icons/
├── scripts/
│   └── build-hooks.js
└── tests/
    ├── unit/
    └── e2e/

フォルダ設計の原則

1. 機能別の整理

graph LR
    A[components/] --> B[common/]
    A --> C[layout/]
    A --> D[features/]
    D --> E[blog/]
    D --> F[shop/]
    D --> G[auth/]

コンポーネントを機能や責務で分類することで、関連するコードをまとめて管理できます。

2. コロケーション戦略

関連するファイルは近くに配置:

features/
└── blog/
    ├── BlogList.astro
    ├── BlogCard.astro
    ├── BlogCard.test.ts
    └── blog.types.ts

3. バレルエクスポート

各ディレクトリにindex.tsを配置してインポートを簡潔に:

// components/common/index.ts
export { default as Button } from './Button.astro';
export { default as Card } from './Card.astro';
export { default as Modal } from './Modal.astro';

実践的なパターン

ページ構造の設計

pages/
├── index.astro              # ホームページ
├── blog/
│   ├── index.astro         # ブログ一覧
│   ├── [...slug].astro     # 動的ルート
│   └── category/
│       └── [category].astro # カテゴリ別表示
└── api/
    └── posts/
        └── [id].ts         # APIルート

コンテンツコレクションの活用

// src/content/config.ts
import { z, defineCollection } from 'astro:content';

const blogCollection = defineCollection({
  type: 'content',
  schema: z.object({
    title: z.string(),
    pubDate: z.date(),
    description: z.string(),
    author: z.string(),
    tags: z.array(z.string()),
  }),
});

export const collections = {
  blog: blogCollection,
};

ユーティリティの整理

lib/
├── api/
│   ├── client.ts           # APIクライアント
│   └── endpoints.ts        # エンドポイント定義
├── utils/
│   ├── date.ts            # 日付処理
│   ├── string.ts          # 文字列処理
│   └── seo.ts             # SEOユーティリティ
└── constants/
    ├── routes.ts          # ルート定数
    └── config.ts          # 設定値

型定義の管理

graph TD
    A[types/] --> B[content.ts]
    A --> C[api.ts]
    A --> D[components.ts]
    B --> E[BlogPost型]
    B --> F[Product型]
    C --> G[APIレスポンス型]
    D --> H[Props型定義]

型定義を一元管理することで、プロジェクト全体の型安全性を確保:

// types/content.ts
export interface BlogPost {
  id: string;
  title: string;
  content: string;
  pubDate: Date;
  author: Author;
  tags: string[];
}

// types/api.ts
export interface ApiResponse<T> {
  data: T;
  status: number;
  message?: string;
}

パフォーマンス最適化

動的インポートの活用

// 必要な時にのみコンポーネントをロード
const { default: HeavyComponent } = await import('../components/HeavyComponent.astro');

アセットの整理

public/
├── images/
│   ├── hero/           # 大きな画像
│   ├── thumbnails/     # サムネイル
│   └── icons/          # アイコン
├── fonts/
│   └── Inter.woff2     # Webフォント
└── assets/
    └── data.json       # 静的データ

ベストプラクティス

  1. 一貫性のある命名規則

    • コンポーネント: PascalCase
    • ユーティリティ: camelCase
    • 定数: UPPER_SNAKE_CASE
  2. 適切な粒度

    • 1ファイル1コンポーネント
    • 関連する機能はまとめる
    • 過度な細分化は避ける
  3. ドキュメント化

    • 各ディレクトリにREADMEを配置
    • 複雑なコンポーネントにはコメント追加
  4. テストの配置

    • コンポーネントと同じディレクトリ
    • または専用のtestsディレクトリ

まとめ

効果的なフォルダ構造は、プロジェクトの成長とチーム開発の基盤となります。Astroの柔軟性を活かしながら、プロジェクトの要件に応じて構造を調整していくことが重要です。

定期的にフォルダ構造を見直し、必要に応じてリファクタリングを行うことで、長期的に保守しやすいプロジェクトを維持できます。