Astro + Cloudflare Workers でブログをゼロから構築した
訂正 (2026-08-09) — この記事の公開時のタイトルは「Astro + Cloudflare Pages でブログをゼロから構築した」でしたが、実際に使っていたのは Cloudflare Pages ではなく Workers の静的アセット (Static Assets) でした。タイトルと説明文を訂正しています。本文は当時のまま残し、該当箇所に注記を足しました。取り違えの経緯と両者の見分け方は「Cloudflare Pages でブログを作った」と書いていましたが、実体は Workers でした(2026-08-09 公開)に書いています。
なぜブログを作り直したのか
もともと techikoma.com で WordPress のブログをやっていたんですが、中身がだいぶ古くなっていて。ドメインだけ活かして、最近やっている個人開発の話を書ける場所が欲しくなりました。
旧コンテンツは全部破棄して完全に新規スタートです。技術の話だけじゃなく、いろいろ書いていくつもりです。
技術スタックの選定
選んだのはこの組み合わせです。
- Astro 6 — 静的サイトジェネレータ。Content Collections で Markdown の記事管理が楽
- Tailwind CSS v4 — CSS変数ベースのテーマ設定。
@custom-variantでダークモード対応 - Cloudflare Pages — ホスティング。GitHub 連携で push したら自動デプロイ
Astro を選んだ理由はシンプルで、ブログに必要な機能が標準で揃っているからですね。Content Collections で frontmatter のスキーマ定義ができて、RSS フィードも @astrojs/rss を入れるだけで済みます。自分は JS/TS メインの開発者なので、Hugo のテンプレート記法より Astro のほうが馴染みます。Next.js はブログにはちょっとオーバースペックですかね。
記事は Markdown で書いて Git 管理しています。ブラウザからも書けるように Decap CMS(旧 Netlify CMS)も入れてあります。
デザイン: Stitch でプロトタイプ
デザインは Google の Stitch を使いました。テキストでイメージを伝えると UI 画面を生成してくれるツールで、モバイル版と PC 版の画面をそれぞれ作成しています。
Stitch が出力したデザインシステムのポイントはこんな感じです。
- Material Design 3 ベースのカラーシステム。エメラルドグリーン (
#006947) をアクセントに - フォント: Plus Jakarta Sans(見出し)+ Manrope(本文)+ Noto Sans JP(日本語)
- ボーダーを使わない: セクションの区切りは背景色のシフトで表現
- グラスモーフィズム: ナビバーは半透明 + backdrop-blur
出力された HTML をそのまま使うのではなく、カラートークンやレイアウトパターンを抽出して Astro のコンポーネントに落とし込みました。
実装: Claude Code で一気に構築
実装は Claude Code で進めました。いい時代になったね。プロジェクト作成からデザイン適用、デプロイ設定まで 1 セッションでやっています。
主にやったことはこのあたりです。
- Content Collections の定義 —
src/content.config.tsで記事スキーマを定義。タイトル、説明、公開日、タグ、下書きフラグ - セマンティックデザイントークン —
--ds-bg、--ds-text、--ds-accentのような CSS 変数を:rootと.darkで切り替える仕組みです。コンポーネントでは[color:var(--ds-text)]のように書くだけで、ダークモードの分岐が不要になります - レイアウト構成 — BaseLayout → BlogPost / ページ。Header(グラスモーフィズムのナビ)と Footer は全ページ共通
- RSS / タグページ —
@astrojs/rssでフィード生成、タグごとの記事一覧ページも自動生成
ちなみに Tailwind v4 ではクラスベースのダークモードを使うには @custom-variant dark (&:where(.dark, .dark *)); が必要でした。これがないと dark: プレフィックスが動かないんですよね。見落としやすいハマりポイントです。
ホスティング: なぜ Cloudflare Pages にしたか
注記 (2026-08-09) — この節を含め、以下で「Cloudflare Pages」と書いている箇所はすべて Workers の静的アセットの誤りです。AWS ではなく Cloudflare を選んだという判断そのものは変わりません。実際、下に貼っている
wrangler.tomlの例は[assets]で始まっていて、これは Workers の書き方です。詳しくは実体は Workers でした(2026-08-09 公開)を参照してください。
最初は AWS(S3 + CloudFront)で考えていました。ただコスト比較してみた結果、Cloudflare Pages に変更しています。
| AWS (S3 + CloudFront) | Cloudflare Pages | |
|---|---|---|
| 帯域 | 1TB/月 無料 (Always Free) | 無制限 |
| ストレージ | 5GB 無料 (12ヶ月限定) | 20,000ファイルまで |
| SSL | 無料 (ACM) | 無料 |
| CI/CD | GitHub Actions 自前構築 | ビルトイン |
| 月額 | $0(Route 53 使わなければ) | $0 |
AWS は「注意して運用すれば $0」で、Cloudflare Pages は「何も考えなくても $0」なんですよね。S3 のストレージ無料枠は 12ヶ月限定なので、長期運用だとその点も気にする必要があります。個人ブログなら Cloudflare のほうが楽です。
GitHub 連携するだけで push → 自動デプロイが完結するので、GitHub Actions のワークフローも不要になりました。
なお、2026年4月現在では Cloudflare Workers と Pages は統合が進んでいて、ダッシュボード上は同じ画面から設定します。デプロイ設定は wrangler.toml に数行書くだけです。
name = "my-blog"
compatibility_date = "2026-04-12"
[assets]
directory = "./dist"
not_found_handling = "404-page"
html_handling = "auto-trailing-slash"
ドメインの設定は、レジストラ側のネームサーバーを Cloudflare 指定のものに変更して、Cloudflare 側でカスタムドメインを追加するだけです。SSL 証明書も自動発行されます。
自動化: ブログネタ自動抽出 hook
Claude Code には hooks という機能があります。特定のイベント(ツール使用前後、セッション終了時など)にシェルスクリプトを実行できる仕組みです。
これを使って、Claude Code のセッションが終わるたびに「ブログネタになりそうな内容」を自動抽出する hook を作りました。
仕組みはシンプルで、こんな流れです。
- Stop hook でセッションの transcript を受け取る
- アシスタントの応答テキストを抽出(短いセッションはスキップ)
- バックグラウンドで
claude -pに渡して分析 - ブログネタがあれば drafts ディレクトリに Markdown で保存
設定は ~/.claude/settings.json に追加するだけです。
{
"hooks": {
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "/path/to/your-blog/scripts/extract-blog-idea.sh",
"timeout": 60
}
]
}
]
}
}
開発作業をしていれば勝手にネタが溜まっていきます。あとは drafts を眺めて、良さそうなものを記事に仕上げるだけですね。