Astro の使い方 — 高速なWebサイトを構築するオールインワンフレームワーク
一言でいうと
Astroは、デフォルトでゼロJavaScriptのHTMLを出力し、必要な箇所だけインタラクティブにできる「アイランドアーキテクチャ」を採用したWebフレームワークです。コンテンツ主体のサイト(ブログ、ドキュメント、ECなど)を圧倒的なパフォーマンスで構築できます。
どんな時に使う?
- ブログやドキュメントサイト — Markdownとの親和性が高く、Content Collectionsで型安全にコンテンツを管理できる
- マーケティングサイト・コーポレートサイト — 静的生成(SSG)でビルドし、CDNから超高速配信したい場合
- React/Vue/Svelteを混在させたいプロジェクト — 複数のUIフレームワークを同一プロジェクトで共存させられる(アイランドアーキテクチャ)
インストール
# 推奨: インタラクティブなセットアップウィザード
npm create astro@latest
# yarn
yarn create astro
# pnpm
pnpm create astro@latest
既存プロジェクトへの手動インストール:
npm install astro
yarn add astro
pnpm add astro
基本的な使い方
プロジェクト構成
my-project/
├── astro.config.mjs
├── src/
│ ├── pages/ # ファイルベースルーティング
│ │ ├── index.astro
│ │ └── about.astro
│ ├── layouts/
│ │ └── Base.astro
│ ├── components/
│ │ └── Header.astro
│ └── content/ # Content Collections
│ └── blog/
│ └── first-post.md
├── public/ # 静的アセット
└── package.json
ページの作成(src/pages/index.astro)
---
// フロントマター(サーバーサイドで実行されるTypeScript)
import Layout from '../layouts/Base.astro';
import Header from '../components/Header.astro';
const title = 'ホームページ';
const posts = await fetch('https://api.example.com/posts').then(r => r.json());
---
<Layout title={title}>
<Header />
<main>
<h1>{title}</h1>
<ul>
{posts.map((post: { id: number; title: string }) => (
<li><a href={`/blog/${post.id}`}>{post.title}</a></li>
))}
</ul>
</main>
</Layout>
レイアウト(src/layouts/Base.astro)
---
interface Props {
title: string;
}
const { title } = Astro.props;
---
<!doctype html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{title}</title>
</head>
<body>
<slot />
</body>
</html>
<style is:global>
body {
margin: 0;
font-family: system-ui, sans-serif;
}
</style>
開発サーバーの起動
npx astro dev # 開発サーバー (localhost:4321)
npx astro build # 本番ビルド
npx astro preview # ビルド結果のプレビュー
よく使うAPI
1. astro.config.mjs — プロジェクト設定
// astro.config.mjs
import { defineConfig } from 'astro/config';
import react from '@astrojs/react';
import tailwind from '@astrojs/tailwind';
import node from '@astrojs/node';
export default defineConfig({
// SSRを有効化
output: 'server',
adapter: node({ mode: 'standalone' }),
// インテグレーション(プラグイン)
integrations: [react(), tailwind()],
// サイトURL(sitemap生成などに使用)
site: 'https://example.com',
// Viteの設定を直接カスタマイズ可能
vite: {
ssr: {
noExternal: ['some-package'],
},
},
});
2. Astro グローバルオブジェクト
---
// リクエスト情報の取得(SSRモード時)
const url = Astro.url; // URL オブジェクト
const params = Astro.params; // 動的ルートパラメータ
const searchParams = Astro.url.searchParams;
const cookies = Astro.cookies; // Cookie操作
const clientAddress = Astro.clientAddress; // クライアントIP
// リダイレクト
if (!isAuthenticated) {
return Astro.redirect('/login', 302);
}
// レスポンスヘッダーの設定
Astro.response.headers.set('Cache-Control', 'max-age=3600');
---
3. Content Collections — 型安全なコンテンツ管理
// src/content.config.ts
import { defineCollection, z } 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.date(),
tags: z.array(z.string()).default([]),
draft: z.boolean().default(false),
image: z.string().optional(),
}),
});
export const collections = { blog };
---
// src/pages/blog/index.astro
import { getCollection } from 'astro:content';
const posts = await getCollection('blog', ({ data }) => !data.draft);
const sortedPosts = posts.sort(
(a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf()
);
---
<ul>
{sortedPosts.map((post) => (
<li>
<a href={`/blog/${post.id}`}>
<time datetime={post.data.pubDate.toISOString()}>
{post.data.pubDate.toLocaleDateString('ja-JP')}
</time>
{post.data.title}
</a>
</li>
))}
</ul>
4. アイランドアーキテクチャ(client:* ディレクティブ)
---
// Reactコンポーネントをアイランドとして読み込む
import Counter from '../components/Counter.tsx';
import HeavyChart from '../components/HeavyChart.tsx';
import Sidebar from '../components/Sidebar.tsx';
---
<!-- ページ読み込み時に即座にハイドレーション -->
<Counter client:load initialCount={0} />
<!-- ビューポートに入ったらハイドレーション(遅延読み込み) -->
<HeavyChart client:visible data={chartData} />
<!-- ブラウザがアイドル状態になったらハイドレーション -->
<Sidebar client:idle />
<!-- 指定メディアクエリに一致した場合のみハイドレーション -->
<MobileMenu client:media="(max-width: 768px)" />
<!-- client:* なし → サーバーでHTMLだけレンダリング、JSは送信しない -->
<Counter initialCount={0} />
5. 動的ルーティングとSSR APIルート
---
// src/pages/blog/[slug].astro
import { getCollection, render } from 'astro:content';
import Layout from '../../layouts/Base.astro';
// SSGの場合: 全パスを事前生成
export async function getStaticPaths() {
const posts = await getCollection('blog');
return posts.map((post) => ({
params: { slug: post.id },
props: { post },
}));
}
const { post } = Astro.props;
const { Content } = await render(post);
---
<Layout title={post.data.title}>
<article>
<h1>{post.data.title}</h1>
<Content />
</article>
</Layout>
// src/pages/api/search.ts — APIエンドポイント
import type { APIRoute } from 'astro';
export const GET: APIRoute = async ({ url }) => {
const query = url.searchParams.get('q') ?? '';
const results = await searchDatabase(query);
return new Response(JSON.stringify(results), {
status: 200,
headers: { 'Content-Type': 'application/json' },
});
};
類似パッケージとの比較
| 特徴 | Astro | Next.js | Nuxt | Gatsby |
|---|---|---|---|---|
| デフォルト出力 | 静的HTML(ゼロJS) | JavaScript バンドル | JavaScript バンドル | 静的HTML + JS |
| UIフレームワーク | React/Vue/Svelte等を混在可 | React専用 | Vue専用 | React専用 |
| アイランドアーキテクチャ | ✅ ネイティブ対応 | ❌(Server Componentsで部分的) | ❌ | ❌ |
| SSR対応 | ✅ | ✅ | ✅ | △(限定的) |
| コンテンツ管理 | Content Collections(組み込み) | 外部CMS/MDX | Nuxt Content | GraphQLデータレイヤー |
| 学習コスト | 低〜中 | 中〜高 | 中 | 中〜高 |
| 最適な用途 | コンテンツ主体サイト | Webアプリ全般 | Vueエコシステム | コンテンツサイト(メンテ停滞気味) |
選定の指針: インタラクティブ性が高いSPAやダッシュボードにはNext.js/Nuxtが適しています。ブログ、ドキュメント、マーケティングサイトなどコンテンツ中心のサイトではAstroが圧倒的にパフォーマンス面で有利です。
注意点・Tips
⚠️ client:* を付け忘れるとインタラクティブにならない
Astroではコンポーネントはデフォルトでサーバーサイドのみでレンダリングされます。ボタンのクリックイベントなどが動かない場合、client:load 等の付け忘れを疑ってください。
<!-- ❌ クリックイベントが動かない -->
<ReactButton onClick={handleClick} />
<!-- ✅ ハイドレーションされるので動く -->
<ReactButton client:load onClick={handleClick} />
⚠️ output モードの選択
// astro.config.mjs
export default defineConfig({
output: 'static', // デフォルト。全ページを事前ビルド(SSG)
output: 'server', // 全ページをリクエスト時にレンダリング(SSR)
output: 'hybrid', // デフォルトSSGだが、ページ単位でSSRに切替可能
});
※ Astro 5.x 以降、
hybridモードはserverモードに統合されつつあります。バージョンに応じて公式ドキュメントを確認してください。
💡 画像最適化は <Image /> コンポーネントを使う
---
import { Image } from 'astro:assets';
import heroImage from '../assets/hero.jpg';
---
<!-- 自動でWebP変換・リサイズ・width/height属性付与 -->
<Image src={heroImage} alt="ヒーロー画像" width={800} />
💡 View Transitions でSPA風のページ遷移
---
// src/layouts/Base.astro
import { ViewTransitions } from 'astro:transitions';
---
<head>
<ViewTransitions />
</head>
これだけでページ遷移時にスムーズなアニメーションが適用され、SPA風の体験を実現できます。
💡 TypeScriptはゼロコンフィグで動作
Astroは tsconfig.json を自動生成し、.astro ファイル内のフロントマターでTypeScriptがそのまま使えます。追加設定は不要です。
まとめ
Astroは「コンテンツファースト」の思想で設計されたWebフレームワークで、デフォルトでゼロJavaScriptの高速なHTMLを出力しつつ、必要な箇所だけReactやVueのインタラクティブなコンポーネントを「アイランド」として埋め込めます。Content Collectionsによる型安全なコンテンツ管理、View Transitionsによるモダンなページ遷移、複数UIフレームワークの共存など、コンテンツ主体のサイト構築に必要な機能が一通り揃っています。パフォーマンスを最優先にしたいWebサイトプロジェクトでは、第一候補として検討する価値があるフレームワークです。