Astro + microCMSで画面プレビューを実装する方法は、これまでも以下の記事で解説してきましたが、
本記事では、VercelのDraft Modeを活用して、下書きコンテンツの画面プレビュー機能を実装する方法をご紹介します。
はじめに
ISRにおける画面プレビュー
Astroには、公式で提供されているVercelアダプター(@astrojs/vercel)があります。このアダプターを使うことで、Vercelにデプロイする際にISR(Incremental Static Regeneration)を簡単に設定することができます。
ISRとは、静的生成(SSG)と動的生成(SSR)のいいとこ取りのような仕組みで、一度生成されたページはCDNにキャッシュされつつ、一定時間後に自動で再生成されるという仕組みです。ヘッドレスCMSとの相性も良く、「一度表示したページを即座に返しつつ、最新データにも自動で追従できる」便利な手法です。
しかし、VercelにホスティングされたISRサイトは、公開されたコンテンツがCDNにキャッシュされるため、未公開の下書きコンテンツをプレビューすることはできません。
VercelのDraft Modeで解決
この問題を解決するために用意されているのが、VercelのDraft Modeです。
VercelのDraft Modeは、ヘッドレスCMSなどと連携してプレビュー機能を実装するための仕組みです。
ブラウザに特定のCookie(__prerender_bypass
)を付与することで、CDNキャッシュをバイパスし、最新の下書きコンテンツを取得・表示することができます。これにより、microCMSなどのヘッドレスCMSと組み合わせることで、下書き状態の記事を画面プレビューすることができます。
準備
利用サービス
1. microCMS
APIベースの日本製ヘッドレスCMSです。ブログのコンテンツ管理を担います。
2. Vercel
フロントエンド開発向けのプラットフォームで、サイト公開におけるインフラやCI/CDを担います。
ソフトウェアバージョン
下記のバージョンで開発を行っています。バージョンの差異によって若干機能が異なる可能性があります。
- Astro 5.5.4
- @astrojs/vercel 8.1.3
- microcms-js-sdk 3.2.0
手順
1. microCMSのセットアップ
APIの作成
API名「お知らせ」、エンドポイント「news」というAPIを作成します。APIの型はリスト形式を選択してください。
APIスキーマを定義
タイトルと本文用のフィールドを用意します。
コンテンツを登録
APIが用意できたら、後ほど動作確認をするために「公開中の記事」と「下書き中の記事」を作成しておきましょう。
画面プレビュー設定
API設定より、画面プレビューの遷移先URLを以下に設定します。https://yourdomain.com/draft?slug={CONTENT_ID}&dk={DRAFT_KEY}
※yourdomain.com
は環境に合わせて適宜変更してください
2. Astroプロジェクトのセットアップ
プロジェクトの作成
Astroのプロジェクトを作成します。
npm create astro@latest
以下ではastro-vercel-draftmode
というプロジェクト名で作成しておりますが、プロジェクト名や各種設定については任意の名前および設定で問題ありません。
作成したプロジェクトに移動し、microcms-js-sdk
と@astrojs/vercel
をインストールします。
npm install microcms-js-sdk@latest @astrojs/vercel@latest
envファイルの作成
ルート直下に.env
ファイルを作成し、下記の情報を入力します。
MICROCMS_API_KEY=xxxxxxxxxx
MICROCMS_SERVICE_DOMAIN=xxxxxxxxxx
MICROCMS_API_KEY
microCMS 管理画面の「サービス設定 > API キー」から確認することができます。
MICROCMS_SERVICE_DOMAIN
microCMS 管理画面の URL(https://xxxxxxxx.microcms.io)の xxxxxxxx の部分です。
3. 実装
astro.config.mjsの設定
ルートにあるastro.config.mjs
を次のように編集します。
// @ts-check
import { defineConfig } from 'astro/config';
import vercel from '@astrojs/vercel';
// https://astro.build/config
export default defineConfig({
output: 'server',
adapter: vercel({
isr: {
expiration: 60,
bypassToken: 'f3a13dad-b3d3-635a-94b7-eed969401a99',
exclude: ['/draft'],
},
}),
});
・最大60秒間キャッシュされ、それ以降のアクセス時に再生成が行われます
・bypassToken
の値は任意の文字列でOKですが、32文字以上である必要があります
・/draft
でキャッシュが返らないように除外しています(ISRの対象外となります)
SDK利用準備
src/libs/microcms.ts
を作成し、SDKの利用準備をしておきます。
// SDK利用準備
import { createClient } from 'microcms-js-sdk';
export const client = createClient({
serviceDomain: import.meta.env.MICROCMS_SERVICE_DOMAIN,
apiKey: import.meta.env.MICROCMS_API_KEY,
});
一覧ページの作成
src/pages/index.astro
を以下のように編集します。エンドポイントnews
から全ての記事データを取得しています。
---
import Layout from "../layouts/Layout.astro";
import { client } from "../libs/microcms";
// 型定義
type News = {
title: string;
body: string;
};
//エンドポイント "news" から全ての記事データを取得
const news = await client.getAllContents<News>({
endpoint: "news",
});
---
<Layout>
<main class="main">
<h1>お知らせ一覧</h1>
<ul>
{
news.map((content) => (
<li>
<a href={content.id}>{content.title}</a>
</li>
))
}
</ul>
</main>
</Layout>
<style>
.main {
margin: 0 auto;
max-width: 960px;
}
</style>
トップページにアクセスすると、公開済みの記事が一覧で表示されるようになっています。
詳細ページの作成
次に詳細ページを表示してみましょう。src/pages/[newsId].astro
を作成します。
---
import type { MicroCMSQueries } from 'microcms-js-sdk';
import Layout from "../layouts/Layout.astro";
import { client } from "../libs/microcms";
// 型定義
type News = {
title: string;
body: string;
};
// 指定されたcontentIdのデータを取得する関数
const getNewsDetail = async (
contentId: string,
queries?: MicroCMSQueries
) => {
return await client.getListDetail<News>({
endpoint: 'news',
contentId,
queries,
});
};
// パラメータからnewsIdを取得
const { newsId } = Astro.params;
// 該当ニュースのデータを取得
const news = await getNewsDetail(newsId as string);
---
<Layout>
<main class="main">
<h1>{news.title}</h1>
<div set:html={news.body}></div>
</main>
</Layout>
<style>
.main {
margin: 0 auto;
max-width: 960px;
}
</style>
詳細ページにアクセスすると、作成したコンテンツのタイトルと本文が表示されます。
画面プレビューの実装
それではいよいよ画面プレビューの実装をしていきましょう。src/pages/draft.astro
を作成します。
---
// パラメータから "dk"(draftKey)と "slug"(コンテンツID)を取得
const draftKey = Astro.url.searchParams.get("dk") ?? undefined;
const slug = Astro.url.searchParams.get("slug") ?? undefined;
// draftKeyとslugの両方が存在する場合にDraft Modeを有効化
if (draftKey && slug) {
Astro.cookies.set('__prerender_bypass', 'f3a13dad-b3d3-635a-94b7-eed969401a99');
Astro.cookies.set('__preview_slug', slug);
Astro.cookies.set('__preview_dk', draftKey);
}
// slugが存在する場合は該当記事ページへリダイレクト
return Astro.redirect(`/${slug}`);
---
・__prerender_bypass
はDraft Modeを有効化するためのCookieです。astro.config.mjs
にて設定した値を指定してください
・リダイレクト後に下書きコンテンツ取得のためのdraftKey
が必要なので、__previewdk
というCookieにセットしています
・該当記事のDraft Modeだということを後に検証するために、コンテンツIDも__preview_slug
というCookieにセットしています
詳細ページを変更
src/pages/[newsId].astro
を次のように変更します。
---
import type { MicroCMSQueries } from 'microcms-js-sdk';
import Layout from "../layouts/Layout.astro";
import { client } from "../libs/microcms";
type News = {
title: string;
body: string;
};
const getNewsDetail = async (
contentId: string,
queries?: MicroCMSQueries
) => {
return await client.getListDetail<News>({
endpoint: 'news',
contentId,
queries,
});
};
const { newsId } = Astro.params;
// Cookieから、プレビュー用のslugとdraftKeyを取得
const slug = Astro.cookies.get('__preview_slug');
const draftKey = Astro.cookies.get('__preview_dk');
// Cookieに保存されたslugとパラメータのnewsIdが一致しない場合、プレビュー終了(Cookie削除)
if (slug?.value !== newsId) {
Astro.cookies.delete('__prerender_bypass');
Astro.cookies.delete('__preview_slug');
Astro.cookies.delete('__preview_dk');
}
// 該当ニュースのデータを取得(draftKeyがあれば下書きを取得)
const news = await getNewsDetail(newsId as string, { draftKey: draftKey?.value });
---
// 略
・Cookieにあるslug
の値とnewsId
の値が異なる場合は想定しているプレビュー画面から移動していると見て、関連Cookieをすべて削除し、Draft Modeを終了させています。
・getNewsDetail
の第二引数はクエリパラメータを受けられるようになっているので、そこにdraftKey
を渡しています。
4. Vercelにデプロイする
Vercelにデプロイして、ページにアクセスしてみましょう。
Vercelへのデプロイ方法方法は以下の記事を参考にしてください。
microCMS + Next.jsでJamstackブログを作ってみよう(Next.js 15 ver.)
デプロイ後、microCMSの「画面プレビュー」をクリックし、下書きコンテンツが無事表示されれば成功となります。
下書き中のページが表示され、X-Vercel-Cache
がBYPASS
となっていることが確認できました。
💡注意
下書きモードが継続される
一度プレビュー用URLにアクセスしてCookieが付与されると、以降も同じブラウザでは常に下書き状態のページが表示され続けます。
そのため、必要に応じてプレビューモードを終了するためのCookie削除ボタンなどを用意しておくと安心です。
プレビューURLの共有
プレビュー用のURLを共有する場合は、必ず以下のような元のURL(リダイレクト前のURL)を共有してくださいhttps://yourdomain.com/draft?slug={CONTENT_ID}&dk={DRAFT_KEY}
リダイレクト後の表示URL(例:https://yourdomain.com/{CONTENT_ID}
)を共有しても、閲覧者のブラウザには必要なCookieが設定されていないため、下書きコンテンツは表示されません。
おわりに
今回は、VercelのDraft Modeを活用して、下書きコンテンツの画面プレビュー機能を実装する方法をご紹介しました。ISRサイトのホスティングにVercelを使用する場合は、ぜひ参考にしてみてください。
なお、この記事ではslug
とdraftKey
をCookieで直接渡す方法をご紹介しましたが、より良い実装方法があれば、ぜひ教えていただけると嬉しいです!