Claude CodeにAstroを正しく書かせる──clientディレクティブ忘れ・Astro.glob・フェンス内Reactフックを解決する

# Claude CodeにAstroを正しく書かせる──clientディレクティブ忘れ・Astro.glob・フェンス内Reactフックを解決する

## はじめに

Claude CodeにAstroのコードを書かせると、Reactコンポーネントがインタラクティブにならなかったり`Astro.glob()`の古いAPIが使われたりする。Next.jsやSvelteKitとは異なり、Astroには`client:`ディレクティブというアイランドアーキテクチャ固有の概念がある。React/Vue的思考でClaude Codeを使うとこの概念が抜け落ちる。CLAUDE.mdでルールを定義すれば最初から正しいAstroコードが生成される。

---

## Claude CodeがAstroで生成しやすいパターンを正す

### `client:` ディレクティブの省略

Claude CodeがReactコンポーネントをimportする際、`client:`ディレクティブを省略するケースが頻繁に起きる。ディレクティブなしでは静的HTMLのみにレンダリングされ、状態管理・イベントハンドラが一切動作しない。

```astro
---
import Counter from '../components/Counter.jsx';
---


```

```astro
---
import Counter from '../components/Counter.jsx';
import Gallery from '../components/Gallery.jsx';
---


```

`client:load`は即座にハイドレーション、`client:idle`はブラウザの空き時間、`client:visible`はスクロールで見えたとき、`client:only`はSSR不可のコンポーネントに使う。

### `Astro.glob()` → `getCollection()`

Claude Codeが旧来の`Astro.glob()`でMarkdownを取得するパターンが生成されやすい。型安全もスキーマ検証も失われる非推奨パターンだ。

```astro
---
// ❌ 型なし・スキーマ検証なし・非推奨パターン
const posts = await Astro.glob('../content/posts/*.md');
const titles = posts.map(p => p.frontmatter.title);
---
```

```astro
---
// src/content/config.ts でZodスキーマを定義済み(title: z.string(), pubDate: z.coerce.date())
import { getCollection } from 'astro:content';
const posts = await getCollection('blog'); // ✅ 型安全・スキーマ検証済み
const titles = posts.map(p => p.data.title); // entry.data でアクセス(frontmatterは誤り)
---
```

### `---` フェンス内にReactフック・クライアントコードを書く

Claude Codeがフェンス内に`useState`などを書いてしまうケースだ。フェンスはサーバーサイド専用でありブラウザでは実行されない。

```astro
---
import { useState } from 'react'; // ❌ サーバーで実行される→動作しない
const [count, setCount] = useState(0);
---

```

```astro
---
// ✅ フェンス内はサーバー専用(データ取得・Props処理のみ)
const { initialValue = 0 } = Astro.props;
import Counter from '../components/Counter.jsx';
---

```

---

## CLAUDE.mdとPostToolUseでAstroパターンを自動担保する

```markdown
## Astroプロジェクトルール

### clientディレクティブ(必須)
- Reactなどフレームワークコンポーネントには必ず `client:` ディレクティブを付ける
- 使い分け: client:load(即時)/ client:idle(空き時間)/ client:visible(スクロール時)/ client:only(SSR不可時)
- ディレクティブなしのコンポーネントは静的HTMLのみ(状態管理・イベントが動作しない)

### コードフェンス(---)内のルール
- `---` フェンスはサーバーサイドのみで実行される(ブラウザコードを書かない)
- useState・useEffectなどのReactフックはフェンス内に書かない

### Content Collections
- Markdownコンテンツは `getCollection()` で取得する(`Astro.glob()` は禁止)
- `src/content/config.ts` に必ずZodスキーマを定義する
- フロントマターは `entry.data.title` でアクセスする(`entry.frontmatter.title` は誤り)
```

`.astro`ファイル編集後に`astro check`で型チェックを自動実行する。

```json
{
"hooks": {
"PostToolUse": [{
"matcher": "Edit|Write",
"hooks": [{ "type": "command", "command": "npx astro check 2>&1 | head -20" }]
}]
}
}
```

---

## EM視点──アイランドアーキテクチャをClaude Codeで設計する

Astroの最大の特徴は「デフォルト静的・必要な場所だけJS」というアイランドアーキテクチャだ。CLAUDE.mdで`client:`ディレクティブの使い分けを定義することで、Claude CodeがパフォーマンスファーストのAstroパターンを生成できる。既存の`Astro.glob()`を使ったコードベースをContent Collectionsに移行する際も、「このファイルをgetCollection()に書き直して」という依頼がCLAUDE.mdがあることで正確に機能し、Zodスキーマも自動生成される。既存コードに`Astro.glob(`がないかgrepで確認するとよい。

---

## まとめ

Claude CodeがAstroで踏む地雷はclientディレクティブ省略・`Astro.glob()`・フェンス内Reactフックだ。CLAUDE.mdに本記事のテンプレートを追記して今すぐリポジトリにコミットしてほしい。`astro check`のPostToolUseフックを合わせて設定すれば、型定義ミスもその場で自動修正される。

コメント

タイトルとURLをコピーしました