ドラフトモード
「Pages ドキュメント」と「Data Fetching ドキュメント」で、getStaticProps
と getStaticPaths
を使用してビルド時にページをプリレンダリング(Static Generation)する方法について説明しました。
Static Generation は、ページがヘッドレスCMSからデータを取得する場合に役立ちます。ただし、ヘッドレスCMSでドラフトを書き、そのドラフトをすぐにページで確認したい場合には理想的ではありません。Next.js には、これらのページをビルド時ではなくリクエスト時にレンダリングし、公開コンテンツの代わりにドラフトコンテンツを取得してほしいと思うでしょう。この特定のケースでのみ、Next.js に Static Generation をバイパスさせたいと考えるはずです。
Next.js には、この問題を解決するドラフトモードと呼ばれる機能があります。その使用方法を以下に示します。
ステップ1: APIルートを作成し、アクセスする
Next.js の API ルートに慣れていない場合は、まず「API ルート ドキュメント」をご覧ください。
まず、API ルートを作成します。これは任意の名前で構いません。例: pages/api/draft.ts
この API ルートで、レスポンスオブジェクトに対して setDraftMode
を呼び出す必要があります。
export default function handler(req, res) {
// ...
res.setDraftMode({ enable: true })
// ...
}
これにより、ドラフトモードを有効にするクッキーが設定されます。このクッキーを含む後続のリクエストは、ドラフトモードをトリガーし、静的に生成されたページの動作を変更します(これについては後述します)。
以下のように API ルートを作成し、ブラウザから手動でアクセスすることで、これを手動でテストできます。
// simple example for testing it manually from your browser.
export default function handler(req, res) {
res.setDraftMode({ enable: true })
res.end('Draft mode is enabled')
}
ブラウザの開発者ツールを開いて /api/draft
にアクセスすると、__prerender_bypass
という名前のクッキーを含む Set-Cookie
レスポンスヘッダーが表示されます。
ヘッドレスCMSから安全にアクセスする
実際には、ヘッドレスCMSからこの API ルートを安全に呼び出すことをお勧めします。具体的な手順は使用しているヘッドレスCMSによって異なりますが、一般的な手順をいくつか紹介します。
これらの手順は、使用しているヘッドレスCMSがカスタムドラフトURLの設定をサポートしていることを前提としています。サポートしていない場合でも、この方法でドラフトURLを保護できますが、ドラフトURLを手動で構築してアクセスする必要があります。
まず、任意のトークンジェネレーターを使用して秘密のトークン文字列を作成する必要があります。この秘密は、Next.js アプリとヘッドレスCMSのみが知っていることになります。この秘密により、CMSにアクセスできない人がドラフトURLにアクセスするのを防ぎます。
次に、ヘッドレスCMSがカスタムドラフトURLの設定をサポートしている場合は、以下のものをドラフトURLとして指定します。これは、ドラフトAPIルートが pages/api/draft.ts
にあることを前提としています。
https://<your-site>/api/draft?secret=<token>&slug=<path>
<your-site>
はデプロイメントドメインである必要があります。<token>
は、生成した秘密のトークンに置き換える必要があります。<path>
は、表示したいページのパスである必要があります。/posts/foo
を表示したい場合は、&slug=/posts/foo
を使用する必要があります。
ヘッドレスCMSによっては、ドラフトURLに変数を含めることができ、CMSのデータに基づいて <path>
を動的に設定できる場合があります。例: &slug=/posts/{entry.fields.slug}
最後に、ドラフトAPIルートで
- シークレットが一致すること、および
slug
パラメーターが存在することを確認します(存在しない場合、リクエストは失敗するはずです)。 res.setDraftMode
を呼び出します。- その後、ブラウザを
slug
で指定されたパスにリダイレクトします。(以下の例では、307リダイレクトを使用しています)。
export default async (req, res) => {
// Check the secret and next parameters
// This secret should only be known to this API route and the CMS
if (req.query.secret !== 'MY_SECRET_TOKEN' || !req.query.slug) {
return res.status(401).json({ message: 'Invalid token' })
}
// Fetch the headless CMS to check if the provided `slug` exists
// getPostBySlug would implement the required fetching logic to the headless CMS
const post = await getPostBySlug(req.query.slug)
// If the slug doesn't exist prevent draft mode from being enabled
if (!post) {
return res.status(401).json({ message: 'Invalid slug' })
}
// Enable Draft Mode by setting the cookie
res.setDraftMode({ enable: true })
// Redirect to the path from the fetched post
// We don't redirect to req.query.slug as that might lead to open redirect vulnerabilities
res.redirect(post.slug)
}
成功すると、ブラウザはドラフトモードのクッキーと共に、表示したいパスにリダイレクトされます。
ステップ2: getStaticProps
を更新する
次のステップは、ドラフトモードをサポートするように getStaticProps
を更新することです。
クッキーが設定された状態で(res.setDraftMode
を介して)getStaticProps
を持つページをリクエストすると、getStaticProps
はビルド時ではなくリクエスト時に呼び出されます。
さらに、context.draftMode
が true
となる context
オブジェクトと共に呼び出されます。
export async function getStaticProps(context) {
if (context.draftMode) {
// dynamic data
}
}
ドラフトAPIルートで res.setDraftMode
を使用したので、context.draftMode
は true
になります。
getStaticPaths
も使用している場合は、context.params
も利用可能になります。
ドラフトデータを取得する
context.draftMode
に基づいて異なるデータをフェッチするように getStaticProps
を更新できます。
例えば、あなたのヘッドレスCMSがドラフト投稿用に異なるAPIエンドポイントを持っているかもしれません。その場合、以下のようにAPIエンドポイントのURLを変更できます。
export async function getStaticProps(context) {
const url = context.draftMode
? 'https://draft.example.com'
: 'https://production.example.com'
const res = await fetch(url)
// ...
}
これで完了です!ヘッドレスCMSから、または手動でドラフトAPIルート(secret
と slug
を含む)にアクセスすると、ドラフトコンテンツが表示されるはずです。そして、公開せずにドラフトを更新した場合でも、ドラフトを表示できるはずです。
これをヘッドレスCMSのドラフトURLとして設定するか、手動でアクセスすると、ドラフトが表示されるはずです。
https://<your-site>/api/draft?secret=<token>&slug=<path>
詳細
ドラフトモードのCookieをクリアする
デフォルトでは、ドラフトモードのセッションはブラウザを閉じると終了します。
ドラフトモードのクッキーを手動でクリアするには、setDraftMode({ enable: false })
を呼び出す API ルートを作成します。
export default function handler(req, res) {
res.setDraftMode({ enable: false })
}
その後、/api/disable-draft
にリクエストを送信して API ルートを呼び出します。このルートを next/link
を使用して呼び出す場合、プリフェッチ時に誤ってクッキーが削除されるのを防ぐために prefetch={false}
を渡す必要があります。
getServerSideProps
と連携する
ドラフトモードは getServerSideProps
でも機能し、context
オブジェクトの draftMode
キーとして利用可能です。
豆知識: ドラフトモードを使用している場合、
Cache-Control
ヘッダーはバイパスできないため、設定すべきではありません。代わりに、ISR の使用をお勧めします。
APIルートと連携する
API ルートはリクエストオブジェクトで draftMode
にアクセスできます。例:
export default function myApiRoute(req, res) {
if (req.draftMode) {
// get draft data
}
}
next build
ごとにユニーク
next build
を実行するたびに、新しいバイパスクッキー値が生成されます。
これにより、バイパスクッキーが推測されるのを防ぎます。
豆知識: HTTP経由でローカルでドラフトモードをテストするには、ブラウザがサードパーティのクッキーとローカルストレージへのアクセスを許可する必要があります。
この情報は役立ちましたか?