p4ni.

比較

Astro × Cloudflare の CMS 選び: Git ベースか、ヘッドレスか、そもそも無しか

· 読了まで約11分

目次

「cloudflare astro cms」で検索すると、出てくるのはリスト記事です。ヘッドレス CMS が15個、ロゴと料金表つきで並び、結論は「用途によります」。そうしたリストが飛ばしている、選択を実際に決める問いがあります。静的な Astro サイトにおいて、コンテンツはどこに住み、変更されたとき何が再ビルドを起動するのか。

このブログは検索クエリそのままの構成で動いています。Astro で静的にプリレンダリングし、Cloudflare Workers の静的アセットから配信する。そして CMS は一切使っていません。これは後で理由を述べる意図的な選択です。

一方、同じ構成で動く拙作のディレクトリテーマ Almanac は、コンテンツの一部について逆の判断をして、リスティングを D1 に置いています。この両極のあいだに、世間で議論される Git ベース CMS とホステッド型ヘッドレス CMS が挟まっています。今日選ぶならどう比較するかを書きます。

結論だけ先に

状況選ぶもの
書き手が自分(開発者)だけCMS なし。content collections を git で管理
開発者が書くが、快適なエディタや非開発者によるたまの編集が欲しいGit ベース CMS(Keystatic、Decap/Sveltia、Tina)
非エンジニアの編集者がコンテンツを持つ、または編集者が多数ホステッド型ヘッドレス CMS(Sanity、Contentful、Storyblok)
「コンテンツ」の実体がデータ(リスティング・投稿受付)D1 + 自作管理画面、または静的/動的のハイブリッド

どの行を選んでも、行き着く先は同じです。dist/ にプリレンダリングされたファイルの束ができ、Cloudflare の CDN から無料で配信される。CMS の問いは純粋に入力側の問題です。

すべてを決める制約: CMS は配信係ではなくビルドの餌やり係

Workers 上の静的 Astro サイトには、リクエスト時にページを描画するサーバーがありません。コンテンツが HTML になるのはビルド時の一度きりです。つまりこの構成における CMS は「コンテンツを配信するソフトウェア」ではなく「ビルドに材料を渡すソフトウェア」であり、ここから2つの帰結が出ます。

第一に、どの選択肢にもビルドトリガーが要ります。コンテンツが変わったら、何かが astro build を走らせて再デプロイしなければならない。git 管理なら普段の CI がそのままトリガーです。ホステッド CMS なら、webhook をデプロイフックに向けます。難しい配線ではありませんが、忘れるとサイトは古いページを黙って配信し続けます。ヘッドレス CMS の古典的な事故です。

第二に、CMS は本番に一切触れません。何を選ぼうと、それが遅かろうと落ちていようとレート制限されていようと、公開中のサイトには影響しない。効いてくるのはビルド時だけです。これは静的構成の最大の贅沢であり、だからこそ、実行時依存の要らないコンテンツにまでそれを持ち込む選択肢には抵抗したほうがいい。

なお出力側のホスティングをまだ迷っているなら、Pages と Workers の比較を別記事に書きました。要点だけ言えば、新規プロジェクトは Workers です。

選択肢1: CMS を使わず content collections を git で持つ

Astro には content collections というコンテンツ層が最初から付いていて、開発者が書くサイトなら正直これで十分以上です。記事はリポジトリ内の MDX ファイル。src/content.config.ts のスキーマがビルド時に全 frontmatter を型チェックするので、日付を打ち間違えればページが壊れる代わりにビルドが落ちます。

記事内でコンポーネントが使え、レビューはプルリクエスト、履歴は git log、バックアップはリモート、検索は grep です。

「これは CMS がないと無理だろう」と思われがちな機能の大半が、実際には要りません。

  • 予約公開は、frontmatter の日付とビルド時フィルタ、それに日次デプロイがあれば成立します。仕組みの全体はこちらに書きました。Cron トリガーとコード4行です
  • 多言語対応は、コレクション内の locale サブフォルダと、翻訳ペアを繋ぐ slug の一致だけ。プラグインも CMS のローカライズ機能も要らないやり方を記事にしています
  • 下書きは、draft: true フィールドと、同じビルド時フィルタで済みます

正直な限界は執筆体験です。書くとは、ファイルを編集してコミットを push することです。私にとってはこれ自体が利点でも(使い慣れたエディタ、整形ツール、git のワークフロー)、Word で原稿を書くクライアントには受け入れられません。「Markdown は簡単ですよ」といくら布教しても変わらない。2年目に実際にコンテンツを触るのは誰か、自分に正直になって見積もるべきです。

選択肢2: Git ベース CMS で同じファイルの上に編集 UI を載せる

Git ベースの CMS は、選択肢1の性質を全部残します。コンテンツはリポジトリに、ビルドは CI から、実行時依存はなし。そこにブラウザベースの編集 UI が加わり、書き手の代わりにコミットしてくれる。ファイルの置き場所は変わらず、ワークフローだけが変わります。

Astro で選ぶならまず Keystatic を検討します。TypeScript ファーストで、設定の形が content collections のスキーマとよく似ており、ローカルのファイルシステム相手にも動くので、ホステッドな部品を一切足さずに「既存 MDX の快適なエディタ」として導入できます。

Decap(旧 Netlify CMS)は古参で、設定ファイル1枚と成熟したウィジェット群が強み。年季は主に UI に出ます。Sveltia は Decap 互換の現代的な書き直しで、設定フォーマットが同じまま劇的に軽い。Decap の流儀で始めておけばリスクの低い乗り換え先になります。

Tina はビジュアル編集まで踏み込んだ「本物の CMS」寄りで、その代償として認証用のバックエンドと独自のデータ層を持ちます(Tina Cloud に任せるか、auth と DB を自前で用意してセルフホストするか)。

Cloudflare 特有の引っかかりは認証です。Decap や Sveltia が編集者の代わりに GitHub へコミットするには OAuth フローが必要で、歴史的な答えだった「Netlify の OAuth サービスを使う」は、Cloudflare でホストしているなら明らかに筋が悪い。

幸い OAuth プロキシは小さなコードで、Worker はその置き場所として最適です。メンテナンスされている decap-proxy 系の Worker 実装がいくつかありますし、自作しても半日仕事です。可動部品は1つ増えますが、すでに使っているプラットフォームの上で、無料で動きます。

これが合うのは、開発者が運営するサイトに「リポジトリを clone せずに編集したい誰か」がいる場合です。共著者、クライアント、あるいは iPad しか手元にない未来の自分。該当者がいないなら UI は純粋なオーバーヘッドなので、現れるまで選択肢1に留まるのが正解です。

選択肢3: ホステッド型ヘッドレス CMS で API の向こうにコンテンツを置く

Sanity、Contentful、Storyblok の類は、コンテンツを自社サーバーに保存し、編集者にちゃんとした執筆アプリケーションを与え、ビルドには API 経由でコンテンツを渡します。Astro 側の統合は Content Layer のおかげできれいに書けます。loader が外部コンテンツをローカルファイルと同じ collections API に取り込むので、テンプレートはエントリの出どころを気にしません。

公開すると webhook が飛び、webhook がデプロイフックを叩き、Cloudflare が再ビルドします。ただし Workers Builds の git 連携でビルドしている場合、トリガーはあくまでコミットです。コンテンツだけの変更にはデプロイフックの配線が別途要ります。忘れると CMS 上の編集が永遠に反映されません。

対価として買っているものを具体的に挙げると、権限とロール、編集ワークフロー(下書き→レビュー→公開)、画像パイプラインつきのアセット管理、ローカライズ支援、そして1つのサイトに縛られない構造化コンテンツです。コンテンツチームを抱えるマーケティングサイトなら、このリストは料金を正当化します。とくに Storyblok のビジュアルエディタは、クライアントへのデモで抜群に映えます。

支払うものはサブスクリプション料金だけではありません。コンテンツは他社のデータベースに、他社のスキーマ形式で住むことになります。無料枠はブログには十分でも、席数やロケールを足した瞬間に蒸発します。無料から最初の有料プランへのジャンプは、サイト本体の Cloudflare 代より一桁大きいのが常です。

外への移行は可能ですが苦行です。さらにビルドがネットワーク依存を持ちます。CMS の API 障害でサイトは落ちませんが、復旧までデプロイは止まります。

名指ししておきたい罠がひとつ。編集者が自分ひとりなのに選択肢3を選ぶ開発者です。書くのも編集するのも自分だけなら、手持ちのエディタで Markdown を書けば済むところに、サブスクリプションとスキーマと webhook を足したことになる。構造化コンテンツの売り文句は本物ですが、あれはチームのためのものです。

選択肢4: コンテンツの実体がデータであるとき

「CMS の問題」に見えて、コンテンツの問題ではないものがあります。カテゴリと検索と投稿受付を備えた500件のディレクトリは、500個の MDX ファイルになりたがっていません。なりたいのはデータベースです。

Almanac はそう作ってあります。閲覧ページは普通の Astro サイトと同じく静的にプリレンダリングし、検索と投稿受付だけが同じデプロイ内の薄い Worker ルート経由で D1 に当たる。静的な半分はアセット配信で無料、動的な半分はコード数行の距離にあり、2つ目のホスティングは要りません。このハイブリッドが Cloudflare だと異様に安く組めます。アーキテクチャの組み立て方は Almanac のブログに書きました。

見分けるテストはこうです。frontmatter のフィールドを設計しているつもりが実質は外部キーだったり、Markdown に対してクエリ言語が欲しくなったりしたら、それはコンテンツからデータへ越境しています。アーキテクチャも一緒に越境させてください。

このサイトはどう決めたか

書き手は1人、ロケールは2つ、執筆はすべてコードエディタ。選択肢1で、後悔はありません。content collections と MDX を CI から wrangler でデプロイし、予約公開は日次の cron デプロイが面倒を見ています。アップグレード経路は全部開いたままです。Keystatic は明日にでもこのファイル群にそのまま被せられますし、将来のプロジェクトに編集チームが付くなら、Content Layer の loader が同じテンプレートにホステッド API から餌をやれます。

「Astro × Cloudflare でどの CMS か」への本当の答えは、機能リストからではなく編集者から始めることです。content collections で困るまでは CMS なし。2人目の手が現れたら Git ベースの UI。チームが来たらホステッド型。コンテンツが散文でなくなったらデータベース。土台の Workers 静的配信はこの4つを全部許容するだけでなく、あとから気が変わってもプラットフォームを替えずに済ませてくれます。