astro の使い方

Astro is a modern site builder with web best practices, performance, and DX front-of-mind.

v6.1.31.9M/週MITフレームワーク
AI生成コンテンツ

この記事はAIによって生成されました。内容の正確性は保証されません。最新の情報は公式ドキュメントをご確認ください。

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' },
  });
};

類似パッケージとの比較

特徴AstroNext.jsNuxtGatsby
デフォルト出力静的HTML(ゼロJS)JavaScript バンドルJavaScript バンドル静的HTML + JS
UIフレームワークReact/Vue/Svelte等を混在可React専用Vue専用React専用
アイランドアーキテクチャ✅ ネイティブ対応❌(Server Componentsで部分的)
SSR対応△(限定的)
コンテンツ管理Content Collections(組み込み)外部CMS/MDXNuxt ContentGraphQLデータレイヤー
学習コスト低〜中中〜高中〜高
最適な用途コンテンツ主体サイト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サイトプロジェクトでは、第一候補として検討する価値があるフレームワークです。