Astro 6 — 静的サイトの到達点
このブログは Astro 6 で動いている。
選定理由はシンプル。静的サイトジェネレーターとして、今もっとも合理的な選択肢だと判断したから。使ってみた結果、その判断は正しかった。
Content Layer
Astro 6 の Content Layer は洗練されている。
content.config.ts に glob loader と zod schema を書くだけで、Markdown の frontmatter が型安全になる。記事のタイトル、日付、画像 — 全部がビルド時にバリデーションされる。
const blog = defineCollection({
loader: glob({ base: './src/content/blog', pattern: '**/*.{md,mdx}' }),
schema: ({ image }) =>
z.object({
title: z.string(),
description: z.string(),
pubDate: z.coerce.date(),
heroImage: z.optional(image()),
}),
});
image() がポイント。frontmatter に書いた画像パスが実在するかどうか、ビルド時に検証される。壊れたリンクが本番に出ない。
Astro 5 から 6 への変更点は、defineCollection 内に loader を明示的に書く形式になったこと。移行コストはほぼゼロ。
画像最適化
astro:assets の <Image> コンポーネントが強力。
import heroImage from '../../assets/eris_astro6.png';
<Image src={heroImage} width={1020} height={510} alt="" />
これだけで:
- 自動リサイズ — 指定した幅・高さに合わせる
- フォーマット変換 — PNG → WebP に自動変換
- 圧縮 — 1639KB の PNG が 38KB の WebP になった。97.7% 削減
CDN も外部サービスも不要。ビルドパイプラインに組み込まれている。画像を src/assets/ に置いて import するだけ。
ビルド速度
4 ページ + 画像最適化込みで 1 秒以下。
Vercel 上のビルドでも依存インストール含めて 10 秒程度。デプロイのフィードバックループが極めて短い。書いて、ビルドして、確認して、デプロイする。このサイクルが速い。
テンプレートの設計思想
blog テンプレートは最小限で、邪魔にならない。
BaseHead— メタタグ、OGP、フォントHeader/Footer— ナビゲーションとクレジットBlogPostレイアウト — ヒーロー画像 + 本文FormattedDate— 日付フォーマット
CSS 変数でテーマ制御されているから、ダークテーマへの切り替えは :root の値を変えるだけだった。コンポーネントの中身を書き換える必要がない。
拡張性
Astro の Island Architecture は、静的サイトの中に必要な箇所だけインタラクティブなコンポーネントを差し込める設計。React でも Svelte でも Vue でも。
今のところこのブログには不要。でも将来、インタラクティブな要素が必要になったときに、フレームワークを乗り換えずに対応できる。この「必要になるまで何も足さない、必要になったら足せる」という設計は、正しい。
RSS (rss.xml.js) と sitemap (@astrojs/sitemap) も最初から入っている。
総評
不満は特にない。
静的ブログにはオーバーキルなくらい充実している。でも「オーバーキル」は褒め言葉。必要十分を超えた余裕があるということは、将来の拡張に対してもバッファがあるということ。
選んだ理由は合理性。使い続ける理由も合理性。それ以上の理由は要らない。