Astro + Cloudflare Pagesでブログを作ったら体験が良かった
Astro の存在は元々知っていたものの、「アイランドアーキテクチャってやつね(分かってない)」という感じで割とスルー気味でした。実際のところ、静的サイトを構築するような案件を最近やっていないので触れる機会がなかったという面が強いです。そのような訳で、ブログを作る形でしっかりと触ってみることにしました。
なぜ Astro なのか
そもそも Astro の独自性などはいくつかありますが、
- 構築が楽(ホスティングに上げやすい)
- Gatsby とか Next.js みたいな痛みがない(画像最適化・ビルド最適化のめんどくささ)
- React などの資産を再利用する選択肢が取れる
- Lighthouse などのスコアが上げやすい(SSG は必須)
この辺りで考えていると Astro 一択になると思います。むしろ、 SSG が流行ってから多くの反省を改善したのが Astro とも言えるかもしれません。
環境情報
- nvm: 0.40.1 (WSL 環境で初めて開発しましたが nvm で管理するのが快適です)
- node.js: v24.13.0
- npm: 11.6.2
- astro: 5.16.15
セットアップ
セットアップコマンドを実行し、ブログテンプレートを選択。一から CSS を書くのもしたくないので、とりあえず TailwindCSS も入れておきます。
npm create astro@latest
npx astro add tailwind --yes
Prettier も入れます。本当は Biome を入れたいですが、意外と面倒事が多いのでエコシステムに乗っかって楽したいときはやはり Prettier かなと最近は強く感じます。
npm install --save-dev prettier prettier-plugin-astro prettier-plugin-tailwindcss prettier-plugin-organize-imports
なお、インストールしただけでは各プラグインが息をしないので、リポジトリのルートに .prettierrc 等を置いて読み込ませておく必要があります。
記事ページ表示用に TailwindCSS の Typography も追加してから global.css を設定しておきます。その他、 Web フォントとかも入れておきたいところですが、モバイルの評価がだいぶ下がるので導入はしません。
npm install @tailwindcss/typography
@import 'tailwindcss';
@plugin '@tailwindcss/typography';
codeblock などのセットアップも最初からされているようで、ここまで記述してきたコードも言語指定でシンタックスハイライトがされるようになっています。あとは不要なテンプレートファイルなどを削除すればこの時点でブログのように利用できます。
Astro ブログテンプレートの良いところは content/ 配下でデータベースのように記事を管理できる点です。加えて content.config.ts で zod を使ったスキーマの定義ができます。
例えばブログを書く上で、タグの表記揺れみたいなのを抑えたいといったシーンで zod に検知させて型エラーにすることができます。もちろん他にも色々なことができるはずです。
content.config.ts のサンプル
import { glob } from 'astro/loaders';
import { defineCollection, z } from 'astro:content';
// 使いそうなタグを定義しておく
const MAIN_GENRES = ['Blog', 'Review', 'Programming', 'Study'] as const;
const LANGUAGES = ['TypeScript', 'Golang', 'Rust', 'Kotlin'] as const;
const TOOLS = ['Blender', 'Unity'] as const;
export const ALLOWED_TAGS = [...MAIN_GENRES, ...LANGUAGES, ...TOOLS] as const;
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(),
updatedDate: z.coerce.date().optional(),
heroImage: image().optional(),
tags: z.array(z.enum(ALLOWED_TAGS)).optional(), // 追加
}),
});
export const collections = { blog };例えば frontmatter に以下のようなタグを追記してみます。
---
title: 'hoge'
tags: ['Programming', 'TypeScript', 'fuga']
---
このようなときは、以下のようにエラーを出してくれます。
[ERROR] [InvalidContentEntryDataError] blog → create-astro-blog data does not match collection schema.
tags.2**: **tags.2: Invalid enum value. Expected 'Programming' | 'TypeScript' ...中略... , received 'fuga'
画像に関しても自動的に最適化してくれるので、もはや静的サイトを作るうえですでにやることがありません。本当にいい時代になったと思います。
ただし、デフォルトの画像最適化パッケージ(Sharp)は Cloudflare Pages (Workers) 上では動きません。そのため、本番ビルドの段階で最適化を済ませてしまうよう astro.config.mjs 側にアダプターの設定を入れておく必要があります。
// astro.config.mjs
import cloudflare from '@astrojs/cloudflare';
export default defineConfig({
// ...
adapter: cloudflare({
imageService: 'compile',
}),
});
これを書いておかないと Cloudflare デプロイ時にビルドエラーでコケてしまうので要注意です。これさえ設定しておけば、ビルド時にいい感じに画像を最適化してくれます。
Cloudflare 関連とデプロイ
Astro のプロジェクト内で以下のコマンドを実施し、 Cloudflare Adapter を追加します。特に手動で設定することはありません。
npx astro add cloudflare
続いて Cloudflare Pages のセットアップをすればデプロイ完了です。
- Github 上にリポジトリを作成しておく(ここまでの作業内容は push しておく)
- Cloudflare のダッシュボードに移動
- ビルド > コンピューティングと AI > Workers & Pages に移動
- 右上のアプリケーションを作成するボタンを押下
- Github を選択し、リポジトリを選択
- あとは画面に従って進める
Workers & Pages の自身のプロジェクトを開くと、以下のようにデプロイ状況が確認できます。デプロイが完了すると pages 用のドメインが発行されて、そこからアクセスが可能になります。
カスタムドメインに関しても、自身のプロジェクトから設定を開き、カスタムドメインを選択した後に Cloudflare 上で所持しているドメインを入力するだけです。
DNS レコードへ自動的に設定され、本当に何もやることがありません。すばらしいです。
さいごに
デザイン調整などを除けばほとんど作業することはありませんでした。万が一つまずいても、今の時代は GitHub Copilot などにいくらでもサポートしてもらえる環境なので安心ですね。
PageSpeed Insights も問題なく 100 点でした。
今回作成したプロジェクトは こちら です。もし興味があって困ったことがあったら参考にしてください。