はてなブログをやめて Astro 7 + Cloudflare Workers に移行した

このブログの話。2013年から使っていたはてなブログ「記録」をやめて、いま見ているこの自前サイトに移行した。移行作業自体が今日1日の出来事だったので、忘れないうちに書いておく。

構成

  • Astro 7 — コンテンツ主体のサイトでは現行のデファクト。zero-JS がデフォルトで、Markdown を置くだけでページになる
  • Cloudflare Workers(static assets) — 2026年の新規プロジェクトは Pages ではなく Workers が公式推奨になっている。純静的サイトならアダプタ不要で、wrangler.jsoncassets.directory: ./dist を書くだけ
  • pnpm / GitHub Actions(main に push すると自動デプロイ)
  • ドメインは Cloudflare Registrarnuresen.dev を取得。原価提供なので .dev が年 $10 ちょっと。取得からWorker への紐付けまで同じアカウント内で完結して、DNS も証明書も自動だった

記事の追加は src/content/posts/ に Markdown を置いて push するだけ。はてなの管理画面より手数が少ない。

過去記事20本の移植が一瞬だった話

移行でいちばん面倒なはずの過去記事の移植が、今回はほぼタダだった。

というのも、少し前から個人 wiki(LLM が維持する knowledge base)を運用していて、自分が公開の場に書いたものは全部 wiki の raw/ に frontmatter 付き Markdown で取り込み済みだった。はてなの20本も日付・カテゴリ・元 URL 付きでそこにあったので、変換スクリプトを1本書いて流すだけで済んだ。

過去の自分のデータを構造化して手元に置いておくと、こういうとき効く。

実装はほぼ AI エージェントがやった

自分がやったのは技術選定の承認・ドメイン取得・ブラウザでの認証くらいで、実装は Claude Code のサブエージェントに任せた。scaffold から過去記事の変換、RSS/sitemap/OGP、デプロイ設定、コミットまで全部そっち。

任せた結果として面白かったのが、エージェントが「Astro 6 と 7 でビルド出力を全記事 diff する」という検証を勝手にやって、はてな時代からあったバグを見つけたこと。昔の記事の地の文に生の <Provider> みたいな文字列があると、HTML タグとして解釈されて画面から消えていた。つまり、はてなで公開していた頃から一部の記事は壊れて表示されていて、誰も(自分も)気づいていなかった。移行時にエスケープ処理を入れて、13年越しに原文どおり表示されるようになった。

踏んだ罠

SmartyPants。 Markdown プロセッサが気を利かせて --state–state に、"$@"“$@” に変換してくる。技術記事では完全に有害なので無効化した。最初 markdown: { smartypants: false } と書いたら、それは Astro 7 では非推奨 API で、将来のメジャーで削除されると無言で記号変換が復活する仕掛けだった。プロセッサ側の features: { smartPunctuation: false } が正解。

pnpm 11 の postinstall ブロック。 esbuild や workerd のビルドスクリプトがデフォルトで拒否されて pnpm install が落ちる。しかも設定の書き方が最近変わっていて、package.jsonpnpm フィールドは読まれなくなっており、pnpm-workspace.yamlallowBuilds に書くのが現行の正解。警告メッセージをちゃんと読まないと古い情報のまま迷走する。

サブスクと従量の使い分け。 構築みたいな試行錯誤(=LLM の呼び出し回数が読めない作業)を従量課金の API でやるとお金が溶ける。構築は定額サブスクの Claude Code、運用は従量で、という分担が正解だった。これは前の記事に書いた話がそのまま当てはまった。

まとめ

はてなをやめた理由は不満というより、「書く→公開」の経路を自分のリポジトリに一本化したかったから。wiki に日々の詰まりが溜まり、そこから記事の下書きが生成でき、push すれば公開される。8年ブログが止まっていた身としては、書かない言い訳を潰す方向に環境を倒しておくのが一番効く気がしている。

はてなに残っていた過去記事はすべてこちらに移してある。旧ブログはそのうち閉じる予定。