Astro 5.0がリリース - Content Layer APIとServer Islandsで進化

2025.12.02

公式ドキュメント

Astro 5.0の革新

Astro 5.0は、コンテンツ駆動型Webサイト構築フレームワークの新たなマイルストーンです。Content Layer APIによる柔軟なデータソース統合と、Server Islandsによる選択的SSRが大きな特徴です。

flowchart TB
 subgraph ContentLayer["Content Layer API (New)"]
 Local["Local Markdown"]
 CMS["CMS<br/>(Contentful)"]
 API["API<br/>(REST)"]
 Database["Database<br/>(Drizzle)"]
 Collections["Unified Type-Safe Collections"]

 Local --> Collections
 CMS --> Collections
 API --> Collections
 Database --> Collections
 end

 subgraph Rendering["Rendering"]
 SSG["SSG<br/>(静的)"]
 Islands["Server Islands<br/>(部分的SSR)"]
 SSR["Full SSR<br/>(動的)"]
 end

 Collections --> Rendering

Content Layer API

ポイント: Content Layer APIにより、Markdown・CMS・REST API・データベースなど、あらゆるデータソースを型安全なコレクションとして統一的に扱えます

新しいコンテンツ定義

// src/content.config.ts
import { defineCollection, z } from 'astro:content';
import { glob, file } from 'astro/loaders';

// ローカルファイルからのコレクション
const blog = defineCollection({
 loader: glob({ pattern: '**/*.{md,mdx}', base: './src/content/blog' }),
 schema: z.object({
 title: z.string(),
 description: z.string(),
 publishDate: z.coerce.date(),
 tags: z.array(z.string()),
 draft: z.boolean().default(false),
 }),
});

// JSONファイルからのコレクション
const authors = defineCollection({
 loader: file('./src/data/authors.json'),
 schema: z.object({
 name: z.string(),
 email: z.string().email(),
 avatar: z.string().url(),
 bio: z.string(),
 }),
});

export const collections = { blog, authors };

カスタムローダーの作成

// src/loaders/cms-loader.ts
import { Loader } from 'astro/loaders';

export function contentfulLoader(options: {
 spaceId: string;
 accessToken: string;
 contentType: string;
}): Loader {
 return {
 name: 'contentful-loader',
 async load({ store, logger }) {
 logger.info('Fetching content from Contentful...');

 const response = await fetch(
 `https://cdn.contentful.com/spaces/${options.spaceId}/entries?content_type=${options.contentType}`,
 {
 headers: {
 Authorization: `Bearer ${options.accessToken}`,
 },
 }
 );

 const data = await response.json();

 for (const item of data.items) {
 store.set({
 id: item.sys.id,
 data: {
 title: item.fields.title,
 body: item.fields.body,
 slug: item.fields.slug,
 publishedAt: item.sys.createdAt,
 },
 });
 }

 logger.info(`Loaded ${data.items.length} entries`);
 },
 };
}

// src/content.config.ts での使用
import { contentfulLoader } from './loaders/cms-loader';

const articles = defineCollection({
 loader: contentfulLoader({
 spaceId: import.meta.env.CONTENTFUL_SPACE_ID,
 accessToken: import.meta.env.CONTENTFUL_ACCESS_TOKEN,
 contentType: 'article',
 }),
 schema: z.object({
 title: z.string(),
 body: z.string(),
 slug: z.string(),
 publishedAt: z.coerce.date(),
 }),
});

Server Islands

Server Islandsは、静的ページ内に動的なサーバーレンダリングコンポーネントを埋め込む機能です。

flowchart TB
 subgraph StaticHTML["静的HTML (キャッシュ可能)"]
 Header["Header (Static)"]

 subgraph MainContent["Main Content"]
 Article["Article Content<br/>(Static)"]
 subgraph ServerIsland["Server Island"]
 UserInfo["ユーザー情報<br/>(動的)"]
 Comments["コメント数<br/>(動的)"]
 end
 end

 Footer["Footer (Static)"]
 end

 Header --- MainContent
 MainContent --- Footer

Server Islandは遅延ロード、フォールバック表示可能

実装例

---
// src/components/UserProfile.astro
export const prerender = false; // Server Islandとして設定

import { getUser } from '../lib/auth';

const user = await getUser(Astro.cookies);
---

{user ? (
 <div class="user-profile">
 <img src={user.avatar} alt={user.name} />
 <span>{user.name}
 <a href="/logout">ログアウト</a>
 </div>
) : (
 <a href="/login" class="login-button">ログイン</a>
)}
---
// src/pages/blog/[slug].astro
import { getCollection, getEntry } from 'astro:content';
import UserProfile from '../../components/UserProfile.astro';
import CommentSection from '../../components/CommentSection.astro';

export const prerender = true; // 静的生成

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 post.render();
---

<html>
 <head>
 <title>{post.data.title}</title>
 </head>
 <body>
 <header>
 <!-- Server Island: 動的なユーザー情報 -->
 <UserProfile server:defer>
 <div slot="fallback">読み込み中...</div>
 </UserProfile>
 </header>

 <main>
 <article>
 <h1>{post.data.title}</h1>
 <Content />
 </article>

 <!-- Server Island: 動的なコメント -->
 <CommentSection server:defer postId={post.id}>
 <div slot="fallback">コメントを読み込み中...</div>
 </CommentSection>
 </main>
 </body>
</html>

astro:env モジュール

環境変数の型安全なアクセスを提供する新しいモジュールです。

// astro.config.mjs
import { defineConfig, envField } from 'astro/config';

export default defineConfig({
 env: {
 schema: {
 // パブリック変数(クライアントでも利用可能)
 PUBLIC_API_URL: envField.string({
 context: 'client',
 access: 'public',
 default: 'https://api.example.com',
 }),

 // シークレット変数(サーバーのみ)
 DATABASE_URL: envField.string({
 context: 'server',
 access: 'secret',
 }),

 // オプショナル変数
 ANALYTICS_ID: envField.string({
 context: 'client',
 access: 'public',
 optional: true,
 }),

 // 数値型
 CACHE_TTL: envField.number({
 context: 'server',
 access: 'public',
 default: 3600,
 }),

 // 列挙型
 NODE_ENV: envField.enum({
 values: ['development', 'production', 'test'],
 context: 'server',
 access: 'public',
 default: 'development',
 }),
 },
 },
});
// 使用例
import { PUBLIC_API_URL, ANALYTICS_ID } from 'astro:env/client';
import { DATABASE_URL, CACHE_TTL } from 'astro:env/server';

// 型安全にアクセス可能
const apiUrl: string = PUBLIC_API_URL;
const analyticsId: string | undefined = ANALYTICS_ID;
const dbUrl: string = DATABASE_URL; // サーバーでのみ利用可能

Vite 6 サポート

Astro 5.0はVite 6をデフォルトで採用し、ビルドパフォーマンスが向上しました。

ビルドパフォーマンス比較 (1000ページのサイト)

バージョンビルド時間メモリ使用開発サーバー起動
Astro 4.x (Vite 5)45秒512MB2.1秒
Astro 5.0 (Vite 6)32秒 (29% faster)380MB (26% reduction)1.4秒 (33% faster)

その他の新機能

改善されたTypeScript推論

// コレクションの型が自動推論される
import { getCollection } from 'astro:content';

const posts = await getCollection('blog');
// posts: Array<{ id: string; data: BlogSchema; ... }>

// フィルタリングも型安全
const publishedPosts = await getCollection('blog', ({ data }) => {
 return data.draft !== true; // data.draft は boolean | undefined
});

実験的機能

// astro.config.mjs
export default defineConfig({
 experimental: {
 // SVGコンポーネントサポート
 svg: true,

 // レスポンシブ画像の自動生成
 responsiveImages: true,

 // Content Intellisense
 contentIntellisense: true,
 },
});
---
// SVGコンポーネントとして使用
import Logo from '../assets/logo.svg';
---

<Logo class="w-32 h-32" fill="currentColor" />

マイグレーションガイド

v4からv5への移行

# Astro CLIでアップグレード
npx @astrojs/upgrade

主な破壊的変更

v4の機能v5での変更
src/content/config.tssrc/content.config.ts に移動
getCollection() の戻り値body プロパティが render() に移行
旧形式のコンテンツコレクションContent Layer APIへ移行推奨
Astro.glob()getCollection() を推奨
// v4: 旧方式
const { Content } = await entry.render();
const body = entry.body; // 直接アクセス

// v5: 新方式
const { Content } = await entry.render();
// body は render() 経由でのみアクセス

まとめ

このニュースは、今すぐ全員が対応すべき話か、学習や新規開発で前提を更新しておく話かを分けて読むことが重要です。まずは公式情報で対象バージョンと影響範囲を確認し、自分の環境に関係する部分から見直してください。

参考リソース

← 一覧に戻る
PR
PR
PR
PR