はじめに

Astroは、コンテンツ駆動型ウェブサイトのための最も人気のあるフレームワークの一つとして急速に成長しています。Astro 5のリリースにより、強力なContent Layer API、強化されたContent Collections、そしてファーストクラスのView Transitionsサポートが導入されました——モダンなブログを構築するための理想的な選択肢です。

このチュートリアルでは、Astro 5を使ってゼロから完全に機能するブログを構築します。最終的に以下のものが完成します:

  • Content Collectionsによる型安全なコンテンツシステム
  • フロントマター検証付きのMarkdown/MDXブログ投稿
  • レスポンシブデザインの美しいレイアウト
  • View Transitions APIによるスムーズなページ遷移
  • VercelまたはNetlifyへの本番デプロイ
  • 最も素晴らしい点は、AstroはデフォルトでクライアントにJavaScriptをゼロで配信するため、驚くほど高速なページ読み込みが実現できることです。

    前提条件

    始める前に、以下を準備してください:

  • Node.js 18.17.1以上(LTS推奨)
  • npmpnpm、またはyarnパッケージマネージャー
  • コードエディタ(VS CodeとAstro拡張機能推奨)
  • HTML、CSS、JavaScriptの基本的な知識
  • デプロイ用のVercelまたはNetlifyアカウント
  • プロジェクトのセットアップ

    新しいAstro 5プロジェクトを作成しましょう:

    npm create astro@latest my-astro-blog
    

    プロンプトで以下を選択します:

  • How would you like to start your new project? → Empty
  • Do you plan to write TypeScript? → Yes
  • How strict should TypeScript be? → Strict
  • Install dependencies? → Yes
  • Initialize a git repository? → Yes
  • プロジェクトに移動して開発サーバーを起動します:

    cd my-astro-blog
    

    npm run dev

    サイトがhttp://localhost:4321で起動します。

    プロジェクト構成

    構築するプロジェクト構成は以下の通りです:

    my-astro-blog/
    

    ├── src/

    │ ├── content/

    │ │ ├── posts/

    │ │ │ ├── getting-started-with-astro.md

    │ │ │ ├── why-content-collections.md

    │ │ │ └── view-transitions-guide.md

    │ │ └── config.ts

    │ ├── layouts/

    │ │ ├── BaseLayout.astro

    │ │ └── PostLayout.astro

    │ ├── components/

    │ │ ├── Header.astro

    │ │ ├── Footer.astro

    │ │ ├── PostCard.astro

    │ │ └── TableOfContents.astro

    │ ├── pages/

    │ │ ├── index.astro

    │ │ ├── blog/

    │ │ │ ├── index.astro

    │ │ │ └── [...slug].astro

    │ │ └── 404.astro

    │ └── styles/

    │ └── global.css

    ├── public/

    │ └── favicon.svg

    ├── astro.config.mjs

    ├── package.json

    └── tsconfig.json

    Content Collectionsスキーマ

    Content Collectionsは、Astroに組み込まれたコンテンツの管理と検証の仕組みです。Astro 5では、Content Layer APIにより、ローカルファイル、API、データベースなど、あらゆるソースからコレクションを定義できます。

    コンテンツ設定ファイルを作成します:

    // src/content/config.ts
    

    import { defineCollection, z } from 'astro:content';

    import { glob } from 'astro/loaders';

    const posts = defineCollection({

    // ローカルMarkdownファイル用のglobローダーを使用

    loader: glob({ pattern: '*/.{md,mdx}', base: './src/content/posts' }),

    schema: z.object({

    title: z.string().max(100),

    description: z.string().max(300),

    author: z.string().default('Blog Author'),

    publishedAt: z.coerce.date(),

    updatedAt: z.coerce.date().optional(),

    heroImage: z.string().optional(),

    tags: z.array(z.string()).default([]),

    draft: z.boolean().default(false),

    readTime: z.number().optional(),

    }),

    });

    export const collections = { posts };

    重要な概念

  • defineCollection() — 検証付きの型付きコレクションを作成
  • glob()ローダー — Astro 5の新しいContent Layerローダーで、ディレクトリからファイルを読み取る
  • z(Zod) — スキーマ検証を提供。フロントマターが一致しない場合、Astroがビルドエラーを投げる
  • z.coerce.date() — 日付文字列を自動的にDateオブジェクトに変換
  • なぜこれが重要なのか

    Content Collectionsがなければ、フロントマターのタイプミスがサイトを黙って壊します。Content Collectionsを使うと:

  • 型安全性 — TypeScriptがすべての投稿の構造を知っている
  • ビルド時検証 — デプロイ前にエラーを検出
  • 自動生成された型 — エディタで完全なIntelliSenseが利用可能
  • 投稿の作成

    最初のブログ投稿を作成します:

    ---
    

    title: "Astro 5入門"

    description: "コンテンツ駆動型サイトのためのWebフレームワーク、Astro 5でウェブサイトを構築する初心者ガイド。"

    author: "Jane Developer"

    publishedAt: 2026-02-01

    tags: ["astro", "web", "tutorial"]

    heroImage: "/images/astro-hero.jpg"

    readTime: 5

    draft: false

    ---

    # Astro 5入門

    Astroはコンテンツ駆動型ウェブサイトのために設計されたモダンなWebフレームワークです。ReactやVueベースのフレームワークがJavaScriptバンドルをクライアントに送信するのとは異なり、Astroはデフォルトですべてを静的HTMLにレンダリングします。

    なぜAstroを選ぶのか?

    1. デフォルトでJS不要 — ページが瞬時に読み込まれる

    2. アイランドアーキテクチャ — 必要な場所にのみインタラクティブ性を追加

    3. Content Collections — 型安全なコンテンツ管理

    4. フレームワーク非依存 — React、Vue、Svelteなど自由に使用可能

    レイアウトとコンポーネント

    ベースレイアウト

    すべてのページで使用する共有レイアウトを作成します:

    ---
    

    // src/layouts/BaseLayout.astro

    import { ViewTransitions } from 'astro:transitions';

    interface Props {

    title: string;

    description?: string;

    }

    const { title, description = 'Astro 5で構築したモダンなブログ' } = Astro.props;

    ---

    <!doctype html>

    <html lang="ja">

    <head>

    <meta charset="UTF-8" />

    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <meta name="description" content={description} />

    <link rel="icon" type="image/svg+xml" href="/favicon.svg" />

    <title>{title} | My Astro Blog</title>

    <ViewTransitions />

    </head>

    <body>

    <Header />

    <main>

    <slot />

    </main>

    <Footer />

    </body>

    </html>

    投稿カードコンポーネント

    ---
    

    // src/components/PostCard.astro

    interface Props {

    title: string;

    description: string;

    publishedAt: Date;

    tags: string[];

    slug: string;

    readTime?: number;

    }

    const { title, description, publishedAt, tags, slug, readTime } = Astro.props;

    const formattedDate = publishedAt.toLocaleDateString('ja-JP', {

    year: 'numeric',

    month: 'long',

    day: 'numeric',

    });

    ---

    <article class="post-card">

    <a href={/blog/${slug}}>

    <h2>{title}</h2>

    <p class="meta">

    <time datetime={publishedAt.toISOString()}>{formattedDate}</time>

    {readTime && <span> · {readTime}分で読了</span>}

    </p>

    <p class="description">{description}</p>

    <div class="tags">

    {tags.map(tag => <span class="tag">#{tag}</span>)}

    </div>

    </a>

    </article>

    <style>

    .post-card {

    padding: 1.5rem;

    border: 1px solid var(--color-border);

    border-radius: 8px;

    background: var(--color-surface);

    transition: border-color 0.2s;

    }

    .post-card:hover {

    border-color: var(--color-primary);

    }

    </style>

    ブログインデックスページ

    ---
    

    // src/pages/blog/index.astro

    import BaseLayout from '../../layouts/BaseLayout.astro';

    import PostCard from '../../components/PostCard.astro';

    import { getCollection } from 'astro:content';

    const posts = await getCollection('posts', ({ data }) => !data.draft);

    // 日付でソート(新しい順)

    const sortedPosts = posts.sort(

    (a, b) => b.data.publishedAt.getTime() - a.data.publishedAt.getTime()

    );

    ---

    <BaseLayout title="ブログ">

    <h1>ブログ記事</h1>

    <div class="posts-grid">

    {sortedPosts.map(post => (

    <PostCard

    title={post.data.title}

    description={post.data.description}

    publishedAt={post.data.publishedAt}

    tags={post.data.tags}

    slug={post.id}

    readTime={post.data.readTime}

    />

    ))}

    </div>

    </BaseLayout>

    動的投稿ページ

    ---
    

    // src/pages/blog/[...slug].astro

    import PostLayout from '../../layouts/PostLayout.astro';

    import { getCollection, render } from 'astro:content';

    export async function getStaticPaths() {

    const posts = await getCollection('posts', ({ data }) => !data.draft);

    return posts.map(post => ({

    params: { slug: post.id },

    props: { post },

    }));

    }

    const { post } = Astro.props;

    const { Content } = await render(post);

    ---

    <PostLayout post={post}>

    <Content />

    </PostLayout>

    Astro 5では、古いpost.render()メソッドの代わりに、astro:contentからインポートしたスタンドアロンのrender()関数を使用します。

    View Transitions

    AstroにはView Transitions APIのビルトインサポートがあり、クライアントサイドフレームワークなしでスムーズなSPA風のページ遷移を実現できます。

    View Transitionsの有効化

    BaseLayout.astro内にを追加するだけです(上記のレイアウトコードに既に含まれています)。これだけで、すべてのページナビゲーションにスムーズなクロスフェードアニメーションが適用されます!

    カスタムトランジションアニメーション

    transition:animateを使って要素ごとにトランジションをカスタマイズできます:

    <article class="post-card" transition:animate="slide">
    

    <!-- カードの内容 -->

    </article>

    Astroが提供する組み込みアニメーション:

    | アニメーション | 説明 |

    |-------------|------|

    | fade | クロスフェード(デフォルト) |

    | slide | 横からスライドイン |

    | none | トランジション無効 |

    | initial | AstroデフォルトなしでCSSを使用 |

    transition:nameによる持続的要素

    ページ間で要素がスムーズに変形するモーフィング効果を作成:

    <!-- PostCard.astro内 -->
    

    <h2 transition:name={title-${slug}}>{title}</h2>

    <!-- PostLayout.astro内 -->

    <h1 transition:name={title-${post.id}}>{title}</h1>

    投稿カードをクリックすると、タイトルがカードの位置から投稿ヘッダーにスムーズにアニメーションします。JavaScriptのオーバーヘッドなしで、アプリのような体験を提供します。

    RSSフィードの追加

    RSSインテグレーションをインストールします:

    npx astro add @astrojs/rss
    

    RSSエンドポイントを作成します:

    // src/pages/rss.xml.ts
    

    import rss from '@astrojs/rss';

    import { getCollection } from 'astro:content';

    import type { APIContext } from 'astro';

    export async function GET(context: APIContext) {

    const posts = await getCollection('posts', ({ data }) => !data.draft);

    return rss({

    title: 'My Astro Blog',

    description: 'Web開発についてのブログ',

    site: context.site!,

    items: posts.map(post => ({

    title: post.data.title,

    pubDate: post.data.publishedAt,

    description: post.data.description,

    link: /blog/${post.id}/,

    })),

    });

    }

    デプロイ

    Vercelへのデプロイ

    Vercelアダプターをインストールします:

    npx astro add vercel
    

    // astro.config.mjs
    

    import { defineConfig } from 'astro/config';

    import vercel from '@astrojs/vercel';

    export default defineConfig({

    site: 'https://my-astro-blog.vercel.app',

    output: 'static',

    adapter: vercel(),

    });

    デプロイ:

    npm i -g vercel
    

    vercel

    Netlifyへのデプロイ

    npx astro add netlify
    

    // astro.config.mjs
    

    import { defineConfig } from 'astro/config';

    import netlify from '@astrojs/netlify';

    export default defineConfig({

    site: 'https://my-astro-blog.netlify.app',

    output: 'static',

    adapter: netlify(),

    });

    デプロイ:

    npm i -g netlify-cli
    

    npm run build

    netlify deploy --prod --dir=dist

    まとめ

    Astro 5を使ってモダンで高速なブログを構築しました:

  • Content Collections — 型安全なスキーマと新しいContent Layer API
  • Markdown投稿 — フロントマター検証付き
  • レスポンシブレイアウト — スコープ付きCSS
  • View Transitions — スムーズなページナビゲーション
  • RSSフィード — 購読者向け
  • 本番デプロイ — VercelまたはNetlify
  • Astro 5のデフォルトでJavaScriptゼロ配信の哲学は、コンテンツ重視のサイトに最適です。Content Collectionsシステムがブログの成長に合わせてコンテンツの有効性を保証し、View Transitionsがプレミアムなブラウジング体験を提供します。

    次のステップ

  • MDXサポートの追加(npx astro add mdx
  • Tailwind CSSの統合(npx astro add tailwind
  • Pagefindによる検索機能の追加
  • Astro組み込みのi18n国際化ルーティングの実装
  • Decap CMSTina CMSなどのCMSの追加

このチュートリアルの完全なソースコードはGitHubで公開しています。Happy blogging! 🚀