Astro
Astroは静的構造を担当します。ページ、レイアウト、および純粋な表示領域です。
SolidJSまたはReactはすべてのインタラクティビティを担当します。ユーザー入力を処理する、状態を管理する、またはイベントに応答するすべてのコンポーネントは、フレームワークアイランドであり、.astroファイルではありません。
CSS Modulesはすべてのコンポーネントのスタイリングに使用されます。常に別のstyles.module.cssファイルに配置し、インラインやAstroの<style>ブロック内には決して記述しません。
このスキルを使用するタイミング
- 新しいAstroプロジェクトの構築、またはページやレイアウト領域の追加
.astroページ、レイアウト、または静的な表示領域の構築- 何かをAstroで実装するか、SolidJS/Reactアイランドで実装するかを決定する
- アイランドに使用するハイドレーションディレクティブの選択
.astroファイルまたはフレームワークアイランド内でのCSS Modulesスタイルの適用- コンテンツコレクション(
src/content/、src/content.config.ts)の操作 - サービス層のデータをサーバーサイドレンダリングされたAstroページに組み込む
- サーバーアイランド(
server:defer)を使用したパーソナライズされた遅延領域の実装 - アダプターとミドルウェアを使用したオンデマンドレンダリング(SSR)のセットアップ
- 型安全なサーバー側ミューテーションのためのAstro Actionsの定義と呼び出し
Astro vs アイランド — 中核となるアーキテクチャ上の決定
これはAstroプロジェクトにおいて最も重要な決定です。
| 何をするか | 使用するもの |
|---|---|
| データから静的なHTMLをレンダリングする — ユーザー操作なし | .astro |
| ページシェル、レイアウトラッパー、ナビゲーション構造 | .astro |
| コンテンツセクション、ブログ投稿、マーケティング領域 | .astro |
onClick、onChange、フォーム状態、またはリアクティブデータを持つコンポーネント | SolidJS または React アイランド |
| 基礎的なUIコンポーネント(Button、Input、Modal、Alertなど) | SolidJS または React アイランド |
| ストアやサービスフックの読み書きを行うコンポーネント | SolidJS または React アイランド |
平たく言うと、ルールは次のとおりです:
- Astroは構造とコンテンツをレンダリングします。ユーザー操作は処理しません。
- SolidJSまたはReactは、すべてのインタラクティビティ、すべてのフォーム状態、およびすべての基本的なインタラクティブUIプリミティブ(イベントを発生させる単純なボタンでさえも)を処理します。
- インタラクティブなUIを
.astroファイルに構築しないでください。Astroにはリアクティビティがありません。.astroファイルにインタラクティビティを追加しようとすると、脆弱でテスト不可能なコードになります。
どのフレームワークを選ぶか — SolidJS それとも React?
プロジェクトは一貫して1つを使用します。astro.config.mjsで設定された統合(@astrojs/solid-js または @astrojs/react)を確認し、プロジェクト内のすべてのアイランドにそのフレームワークを使用してください。同じプロジェクトで両方のフレームワークを混在させないでください。
完全な意思決定ガイドとハイドレーションディレクティブのリファレンスについては、./references/islands-and-hydration.mdを参照してください。
スタイリングルール — 別ファイルのCSS Modules
これはこのスキルにおいて最も重要なルールです。
すべてのAstroコンポーネント、ページ、レイアウトは、スコープ付きスタイリングのためにCSS Modulesを使用します。CSSは別のファイルに配置します。Astroの<style>タグ内には決して記述しません。
ComponentName/
├── index.astro ← コンポーネントロジックとマークアップ
└── styles.module.css ← このコンポーネントのすべてのスタイル、常に別ファイル
- 常に
index.astroと一緒にstyles.module.cssを作成します。 - Astroの
<style>ブロック内にスタイルを決して記述しません。 - インラインの
style属性を決して使用しません。 - フロントマターのフェンスの先頭でモジュールをインポートします:
import styles from './styles.module.css' class:listディレクティブまたは直接のクラスバインディングを使用してクラスを適用します:<div class={styles.container}><div class:list={[styles.container, isActive && styles.active]}>
- セマンティックなクラス名を使用します。ユーティリティクラスの積み重ねは避けます。
- すべてのデザイントークン(色、スペーシング、タイポグラフィ)にはCSSカスタムプロパティを使用します。
!importantは使用しません。深いセレクターは使用しません。スタイリングにIDセレクターは使用しません。
トークン戦略、テーマ変数、レスポンシブルール、アニメーションガイダンスについては、./references/styling-and-css-modules.mdを参照してください。
完全なButtonの例(別のCSS Moduleファイル付き)については、./examples/button-component/を参照してください。
プロジェクト構造
src/
├── components/
│ ├── foundation/ # インタラクティブなUIプリミティブ — SolidJS または React、.astro ではありません
│ │ ├── Button/
│ │ │ ├── index.tsx ← SolidJS (.tsx) または React (.tsx)
│ │ │ └── styles.module.css
│ │ └── Input/
│ │ ├── index.tsx
│ │ └── styles.module.css
│ ├── layout/ # 静的なレイアウト構造 — .astro
│ │ ├── Header/
│ │ │ ├── index.astro
│ │ │ └── styles.module.css
│ │ └── Footer/
│ │ ├── index.astro
│ │ └── styles.module.css
│ └── features/ # インタラクティブな機能領域 — SolidJS または React
│ └── SomeFeature/
│ ├── index.tsx ← アイランドコンポーネント
│ └── styles.module.css
├── layouts/
│ └── BaseLayout/
│ ├── index.astro ← レイアウトシェルは常に .astro
│ └── styles.module.css
├── pages/
│ ├── index/
│ │ ├── index.astro ← ページは常に .astro
│ │ └── styles.module.css
│ └── [dynamic]/
│ ├── index.astro
│ └── styles.module.css
├── content/
│ ├── blog/
│ └── [collection-name]/
├── content.config.ts ← Astro 5 コレクションスキーマとローダー
├── store/
│ ├── repository/
│ ├── service/
│ └── config.ts
├── styles/
│ ├── tokens/
│ │ ├── _colors.css
│ │ ├── _spacing.css
│ │ └── _typography.css
│ ├── global.css
│ └── themes/
│ ├── light.css
│ └── dark.css
└── utils/
命名規則:
.astroページとレイアウト:PascalCase/フォルダにindex.astro- フレームワークアイランドコンポーネント:
PascalCase/フォルダにindex.tsx - ページ:
kebab-case/フォルダにindex.astroまたは[dynamic]/フォルダにindex.astro - CSS Moduleファイル: 常に
styles.module.css— コンポーネントディレクトリごとに1つ - ユーティリティ:
kebab-case.ts
ディレクトリの責任範囲と命名規則の完全な内訳については、./references/project-structure.mdを参照してください。
Astroコンポーネントの形状
.astroファイルは静的構造専用です。propsとデータからHTMLをレンダリングします。イベントを処理したり、状態を管理したりしません。
- フロントマターフェンス内で
interface Propsを使用して型付きのpropsを使用します。 Astro.propsでpropsにアクセスします。- コンポーネントは小さく、単一目的に保ちます。
- propsのドリルよりもコンポジションを優先します。
- 式はシンプルに保ちます。複雑なロジックはフロントマター変数に移動します。
- セマンティックなHTML要素 —
<section>、<article>、<nav>、<main>、<header>— を、要素にセマンティックな意味がある場合は汎用的な<div>ラッパーではなく使用します。
---
import styles from './styles.module.css'
interface Props {
title: string
subtitle?: string
}
const { title, subtitle } = Astro.props
---
<section class={styles.hero} aria-label={title}>
<h1 class={styles.title}>{title}</h1>
{subtitle && <p class={styles.subtitle}>{subtitle}</p>}
<slot />
</section>
フロントマターの規則、スロットの使用法、Astro APIリファレンスについては、./references/component-patterns.mdを参照してください。
基礎コンポーネント — SolidJS または React、Astro ではありません
基礎的なUIプリミティブ(Button、Input、Alert、Modal、Select、Toggleなど)は常にSolidJSまたはReactコンポーネントとして構築します。これらは決して.astroファイルではありません。
理由: 基礎コンポーネントはユーザーイベントを処理し、フォーカスを管理し、onClickやonChangeコールバックを公開し、場合によっては内部状態を保持します。これらは.astroファイルでは不可能です。「ボタン」を.astroとして構築すると、型付けされた再利用可能な方法でクリックに応答できない静的なHTMLが生成されます。
決定ルール:
- プリミティブが存在する — それを使用します。
- プリミティブは近いがpropが足りない — 既存のプリミティブを拡張します。
- プリミティブが存在しない — 使用する前に、
components/foundation/にSolidJSまたはReactコンポーネントとして作成します。ページや機能コンポーネントで、その場限りのインタラクティブ要素をインライン化してはいけません。
すべての基礎コンポーネントは、一貫性があり、アクセシブルで、強く型付けされている必要があります。アイランドコンポーネント内で適用される実装規則については、solid.js または react のスキルを参照してください。
アイランドとハイドレーション
インタラクティブなコンポーネントはすべてアイランドです。.astroページとレイアウトから client:* ディレクティブを使用してアイランドをマウントします。インタラクション要件を満たす最小限のディレクティブを選択してください。
| ディレクティブ | 使用するタイミング |
|---|---|
client:load | ページ読み込み時にすぐにインタラクティブである必要がある |
client:idle | ブラウザがアイドル状態になるまで待機できる |
client:visible | ビューポートに入ったときにのみハイドレーションが必要 |
client:media="(query)" | 特定のビューポートサイズでのみインタラクティブ |
client:only="solid-js" または client:only="react" | レンダリング時にブラウザAPIが必要。SSRをスキップ |
デフォルトは client:visible または client:idle にします。client:load は、ユーザーがすぐに操作するUI(プライマリフォーム、ナビゲーションドロップダウン、認証ページ)にのみ使用します。
アイランドコンポーネントは常に独自の styles.module.css を持ちます:
components/features/ContactForm/
├── index.tsx ← SolidJS または React アイランド
└── styles.module.css ← 別のCSS Module、他の場所と同じルール
Astroページからのアイランドのマウント:
---
import styles from './styles.module.css'
import ContactForm from '../../components/features/ContactForm/index.tsx'
const { prefillEmail } = Astro.props
---
<section class={styles.section}>
<h2 class={styles.heading}>Contact Us</h2>
<ContactForm client:visible prefillEmail={prefillEmail} />
</section>
完全な決定ガイド、フレームワーク固有の注意点、データ受け渡しルールについては、./references/islands-and-hydration.mdを参照してください。
コンテンツコレクション
コンテンツコレクションは、完全なTypeScriptの型安全性を備えてMarkdown、MDX、および構造化データファイルを管理するための標準的な方法です。
Astro 5 の主な変更点:
- 設定ファイルは
src/content.config.tsにあります(src/content/config.tsではありません) - コレクションは
loaderを使用します。astro/loadersからのglob()またはfile() render(entry)はastro:contentからインポートされる関数です(entry.render()ではありません)zはzodから直接ではなく、astro:contentからインポートします
// src/content.config.ts
import { defineCollection, z, reference } from 'astro:content'
import { glob } from 'astro/loaders'
const blog = defineCollection({
loader: glob({ pattern: '**/*.md', base: './src/content/blog' }),
schema: z.object({
title: z.string(),
pubDate: z.coerce.date(),
draft: z.boolean().default(false),
}),
})
export const collections = { blog }
ページでのレンダリング:
---
import { getEntry, render } from 'astro:content'
const post = await getEntry('blog', Astro.params.slug)
const { Content } = await render(post)
---
<Content />
完全なAPI(ローダー、コレクション間参照、カスタムローダー、ランタイムコレクション、動的ルートパターン)については、./references/content-collections.mdを参照してください。
サーバーアイランド、SSR、およびアクション
サーバーアイランド (server:defer)
ページシェルを即座に提供しながら、パーソナライズされたまたは動的な.astroコンポーネントを遅延させます。アダプターが必要です。
<UserCart server:defer>
<span slot="fallback">···</span>
</UserCart>
遅延されたコンポーネントはサーバーサイドで実行され、ストリーミングで読み込まれます。静的ページの配信を妨げる可能性があるユーザー固有のUI(カート数、通知、パーソナライズされた挨拶)に使用します。
オンデマンドレンダリング (SSR)
export const prerender = false(ハイブリッドモード)を使用してページをサーバーレンダリングにオプトインするか、グローバルに output: 'server' を設定します。
SSRページは、Astro.cookies、Astro.request、Astro.redirect()、およびAstro.locals(ミドルウェアによって設定される)にアクセスできます。
ミドルウェア
src/middleware.ts でリクエストインターセプトロジックを定義します:
import { defineMiddleware } from 'astro:middleware'
export const onRequest = defineMiddleware(async (context, next) => {
context.locals.user = await getUser(context.cookies.get('session')?.value)
return next()
})
Astro Actions
src/actions/index.ts で定義された型安全なサーバー関数で、アイランドまたはHTMLフォームから呼び出せます:
// src/actions/index.ts
import { defineAction, ActionError } from 'astro:actions'
import { z } from 'astro:content'
export const server = {
newsletter: {
subscribe: defineAction({
input: z.object({ email: z.string().email() }),
handler: async ({ email }) => {
await addSubscriber(email)
return { success: true }
},
}),
},
}
アイランドからの呼び出し:
import { actions } from 'astro:actions'
const { data, error } = await actions.newsletter.subscribe({ email })
isInputError(error) を使用して、Zod検証エラーとハンドラーエラーを区別します。
完全なカバレッジ(レンダリングモード、アダプター設定、ミドルウェア、サーバーアイランド、オンデマンドAPI、フォームを使用したアクション、エラーコード、型付き環境変数(astro:env)、ビュートランジション)については、./references/server-rendering.mdを参照してください。
Astro API リファレンス
Astro.props— 型付けされたコンポーネント propsAstro.params— 動的ルートパラメータ([slug]、[...path])Astro.request— サーバーサイドリクエストオブジェクト(ヘッダー、クッキー、URL)Astro.url— 現在のページURLgetStaticPaths()— 静的サイト生成のためのパスを列挙するgetEntry()/getCollection()— コンテンツコレクションクエリ
サービス層データフロー
Astroページとレイアウトは、フロントマターフェンス内でサービス関数やリポジトリ関数を呼び出すのに適切な場所です。コンポーネントはデータをpropsとして受け取る必要があります。
- ページのフロントマターでデータをフェッチし、コンポーネント内ではフェッチしないでください。
- データを型付けされたpropsとして渡します。
- コンポーネントはリポジトリや外部APIを直接呼び出してはいけません。
- バリデーションとビジネスロジックはサービス層に保持します。
アクセシビリティ
- 要素に意味がある場合は、セマンティックなHTML要素を使用します。
- 実際のセマンティック情報を追加するARIA属性を追加します。
- すべてのインタラクティブ要素にアクセシブルな名前があることを確認します。
- 可視フォーカス状態を維持します。
- インタラクティブ要素には最低44pxのタッチターゲットサイズを維持します。
prefers-reduced-motionを尊重します。- ページコンテンツ内で見出しを論理的に構成します(
h1→h2→h3)。
ARIAパターン、フォームラベル、見出し階層のガイダンスについては、./references/accessibility-patterns.mdを参照してください。
サポートファイル
./references/styling-and-css-modules.mdCSS Modulesルール、トークン戦略、テーマ変数、レスポンシブルール、アニメーション。./references/component-patterns.mdAstroフロントマターの規則、コンポーネントAPI、スロットの使用法。./references/islands-and-hydration.mdアイランドの決定ガイド、ハイドレーションディレクティブ、データ受け渡し。./references/project-structure.mdディレクトリ構成と命名規則の内訳。./references/content-collections.mdAstro 5 コンテンツコレクション、ローダー、スキーマ、レンダリングAPI。./references/server-rendering.mdSSR、サーバーアイランド、ミドルウェア、アクション、環境変数、ビュートランジション。./references/accessibility-patterns.mdARIA、見出し階層、フォームラベル、キーボードナビゲーション。./examples/button-component/CSS Modulesを使用したButtonコンポーネントの実装例。./examples/card-component/Astro Cardコンポーネントとスタイリングの実装例。