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
新しいコンテンツ定義
// 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}</span>
<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秒 | 512MB | 2.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.ts | src/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() 経由でのみアクセス