EmDashとAstro単体はどう違い、どちらを選べばいいですか?
開発者がコードで更新を完結させるAstro単体と、ブラウザの管理画面から記事を編集できるEmDashでは、想定する運用の役割がはっきり分かれます。
Astro単体だと記事はMarkdownしか使えない、と思われがちです。実際には、ローカルファイルのほかにCMSやデータベース、APIからも記事を取得でき、取得のタイミングもビルド時とリクエスト時から選べます。標準では静的ページを生成しますが、アダプターを追加すれば一部または全部のページをリクエスト時に作れます。静的HTML専用というわけでもありません。
AstroのContent Collectionsを使えば、更新頻度の少ない記事はビルド時に効率よく処理し、頻繁に変わるデータはライブコレクションで取得できます。もっとも、ライブコレクションは再ビルドなしで新しいデータを取れますが、リクエストのたびに取りに行く分、表示側に負担がかかります。
一方のEmDashは、Astroの統合機能(integration)として動作するCMSです。管理画面、ユーザー認証、メディア管理が最初から備わっており、非開発者でも管理画面からコンテンツを更新できます。コンテンツの種類はコードではなくデータベース側で定義するため、管理画面上でコレクションを増やす操作も可能です。データベースもCloudflare D1に限らず、SQLiteやTurso、PostgreSQLなどを用途に合わせて選べます。
選ぶときは、誰が記事を更新するか、管理画面が要るか、更新のたびに再ビルドを待てるか、の3点を見てください。更新するのが開発者だけで、公開まで待てるならAstro単体で足ります。Studioのように画面から記事を直したい人がいるなら、EmDashのほうが今の運用に近いですね。
StudioのCMS記事をEmDashへ移す手順は?
Studioで公開してきたCMS記事を、どのような流れでEmDashへ移せばよいでしょうか。Studioのデータ書き出し仕様ではCMSデータやデザイン、ページ情報のエクスポート機能が用意されていません。そのため、公開中のページから記事を集め、EmDash側で登録し直します。大まかな流れは次のとおりです。
- Studioのダッシュボードの設定から一般を開き、サイトマップファイルをオンにする
- /sitemap.xmlから記事のURLを集める
- npm create emdash@latestでEmDashのプロジェクトを作る(Blogテンプレートもあります)
- 管理画面で、Studioのモデルに合わせたコレクションを作る
- 記事と画像を登録し、表示を確かめる
ただし、このファイルにはモーダルやnoindexを指定したページが含まれないため、除外された記事がないか別途見落としを確かめましょう。非公開のサイトでサイトマップをオンにした場合、URLが有効になるのは公開したときです。
記事数が多いなら、EmDashのMCPサーバーを使った登録も選べます。記事を作るcontent_createにはcontent:write、画像などを上げるmedia_uploadにはmedia:writeのスコープが必要で、認証トークンとユーザー権限も用意しましょう。登録の前にschema_get_collectionを使えば、項目名、型、制約、検証ルールを確かめられます。media_uploadが受け取るのはBase64形式のデータで、画像URLを渡すだけでは登録できません。ファイルサイズとMIMEタイプの制限もかかります。
あわせて、EmDashはCloudflareのD1・R2・Workersでも、SQLiteを使うNode.jsサーバーでも動きます。どちらに置くかは、手順3の前に決めてください。
Cloudflare上のEmDashはD1やR2をどう使うのですか?
Workers上で動くEmDashでは、記事テキストをサーバーレスSQLデータベースのD1に収め、アイキャッチなどの画像をオブジェクトストレージのR2へ預ける構成が標準的です。設定例ではD1への接続バインディング名を「DB」、R2への接続名を「MEDIA」として指定します。Cloudflare向けテンプレートを使っていれば、設定ファイルにリソース名を記述してビルド後にpnpm wrangler deployを実行した際、該当するD1やR2が未作成であればWranglerが初期リソースを立ち上げます。
ちなみに、R2に保存した画像を外部へ配信する際は、publicUrlで公開用ドメインを割り当てましょう。ただし、管理画面から日次JSONバックアップを有効にして同じバケットに保存する場合、backups/という接頭辞のフォルダに保存されるため、バケット全体を不用意に公開するとバックアップファイルまで閲覧される恐れがあります。画像メディア専用の公開経路を用意するか、非公開バケットを適切に設定してください。
データベースの更新では、通常はWorkerへの初回アクセス時にコア移行が動きます。しかし、大量のデータを投入する大規模な移行では事前にemdash migrateコマンドを完了させておく必要があり、完了前は503エラーが返されます。
もうひとつ、日次のJSONバックアップは管理画面で有効にし、保持数を1〜30ファイルから選びましょう。Cloudflareでは定期実行用のCron Triggerも必要です。ただ、このJSONバックアップからは復元できません。移行に失敗したときの戻り先には、D1の時点復元を使います。D1のTime Travelで戻せる期間は、Workers Freeで過去7日、Workers Paidで過去30日です。移行の前に、復元位置を示すブックマークを記録しておきます。
EmDashのテーマやデザインをAstroで自作するには?
Studioで作り込んだ独自のデザインを、EmDashで再現するには何から手をつければよいでしょうか。Studioのデザインを自動で変換する方法はないため、公開中のサイトを見ながらAstroで組み直しましょう。自作テーマはAstroプロジェクトとして構築します。ページのテンプレート、共通ヘッダーやフッターのレイアウト、CSSのスタイリングに加え、記事の入力項目を定義するseedファイルを用意して組み立てていきます。
ゼロから書くのが大変なときは、EmDashのテーマ作成ガイドでも触れられているBlogやMarketing、Portfolioといった公式テンプレートを出発点に選ぶとスムーズです。特にBlogテンプレートにはタグやカテゴリ、サイト内検索、RSS出力の機能が最初から備わっています。だから、Studioのブログを移すなら、ここから手を入れていくと早いでしょう。
テンプレート内でのデータ取得には、EmDash専用の関数を呼び出します。記事の一覧はgetEmDashCollection、個別記事のデータはgetEmDashEntryで読み込み、本文のブロックデータはPortableTextコンポーネントを使ってHTMLへ変換します。現行のテンプレートはサーバー出力形式となっており、アクセスがあるたびに最新のコンテンツを取得して描画する動きです。通常の記事ページにgetStaticPathsを足す必要はありません。
Cloudflare Workers上でD1を接続する場合、astro.config.mjsの統合設定にemdash({ database: d1({ binding: "DB" }) })と記述し、wrangler.jsoncで割り当てたD1のバインディング名と合わせます。
ところで、デザインを作るときは、管理者があとで変える文言と固定の文言を分けておきます。変える値は設定、コンテンツ、メニュー、ウィジェットに持たせ、変えないデザイン上の文言はAstroファイルに書いたままで構いません。
最後に、依存関係をインストールしてビルドと型チェックを行い、空のデータベースで初期設定を試します。サンプル記事の有無、空のコレクションの表示、管理画面での変更が反映されるかも確認します。初期化済みのデータベースには、再ビルドしてもseedは入り直しません。
EmDashのフォームにreCAPTCHAやCloudflare Turnstileを付けられますか?
問い合わせフォームを運用していると、迷惑メールや自動送信スパムへの対策が欠かせない場面に出くわします。Studioでは管理画面のAppsメニューからGoogle reCAPTCHA v3を連携し、サイトキーやシークレットキー、判定のしきい値を入力するだけでスパム対策を設定できました。EmDashへ移るときも同じ守りを付けたいところですね。
EmDashには@emdash-cms/plugin-formsというフォーム用のプラグインがあり、独自のバージョン番号と、必要なEmDashの最低バージョンが決まっています。CAPTCHAに標準で対応しているかは、入れる前にプラグイン側の説明で確かめ、対応していなければ自分で組み込みます。
自分で組み込む場合、画面に部品を置くだけでは足りません。Turnstileのサーバー検証に関する説明の通り、フォーム送信時に届いたトークンをサーバー側でSiteverify APIに送り、判定結果が合格であることを確認してから送信処理を受け付ける処理が必要です。Google reCAPTCHA v3を採用する場合も同様で、フロント側で生成したトークンをバックエンドへ引き渡し、APIレスポンスのaction名が想定したフォーム送信と一致しているかを確かめる設計にします。Studioのように画面操作だけで完結する仕組みとは異なり、サーバー側での検証処理を忘れずに組み込んでおきましょう。