Draft Mode
Draft Mode を使用すると、Next.jsアプリケーションでヘッドレスCMSのドラフトコンテンツをプレビューできます。これは、ビルド時に生成される静的ページで役立ちます。サイト全体の再構築を行うことなく、動的レンダリングに切り替えてドラフトの変更を確認できます。
このページでは、Draft Modeの有効化と使用方法について説明します。
手順1:Route Handlerを作成する
Route Handler を作成します。任意の名前を付けることができます。例えば、app/api/draft/route.ts
です。
- TypeScript
- JavaScript
export async function GET(request: Request) {
return new Response('')
}
export async function GET() {
return new Response('')
}
その後、draftMode
関数をインポートし、enable()
メソッドを呼び出します。
- TypeScript
- JavaScript
import { draftMode } from 'next/headers'
export async function GET(request: Request) {
const draft = await draftMode()
draft.enable()
return new Response('Draft mode is enabled')
}
import { draftMode } from 'next/headers'
export async function GET(request) {
const draft = await draftMode()
draft.enable()
return new Response('Draft mode is enabled')
}
これにより、ドラフトモードを有効にするためのクッキーが設定されます。このクッキーを含む以降のリクエストはドラフトモードをトリガーし、静的に生成されたページの動作が変わります。
/api/draft
にアクセスし、ブラウザの開発者ツールを確認することで、手動でテストできます。クッキー名が__prerender_bypass
のSet-Cookie
レスポンスヘッダーが表示されます。
手順2:ヘッドレスCMSからRoute Handlerにアクセスする
これらの手順は、使用しているヘッドレスCMSがカスタムドラフトURLの設定をサポートしていることを前提としています。していない場合でも、この方法を使用してドラフトURLを保護できますが、手動でドラフトURLを構築しアクセスする必要があります。具体的なステップは使用するヘッドレスCMSによって異なります。
ヘッドレスCMSからRoute Handlerに安全にアクセスする手順:
- 好みのトークンジェネレーターを使用してシークレットトークン文字列を作成します。このシークレットはNext.jsアプリとヘッドレスCMSだけが知っています。
- ヘッドレスCMSがカスタムドラフトURLの設定をサポートしている場合、ドラフトURLを指定します(これはあなたのRoute Handlerが
app/api/draft/route.ts
にあると仮定しています)。例えば:
https://<your-site>/api/draft?secret=<token>&slug=<path>
<your-site>
はあなたのデプロイメントドメインであるべきです。<token>
はあなたが生成したシークレットトークンに置き換える必要があります。<path>
は閲覧したいページのパスである必要があります。/posts/one
を閲覧したい場合、&slug=/posts/one
を使用します。あなたのヘッドレスCMSは、CMSのデータに基づいて
<path>
を動的に設定できるように、ドラフトURLに変数を含めることを許可するかもしれません。例:&slug=/posts/{entry.fields.slug}
- Route Handlerでシークレットが一致し、
slug
パラメータが存在することを確認します(もし存在しない場合、リクエストは失敗するべきです)。draftMode.enable()
を呼び出してクッキーをセットします。その後、slug
で指定されたパスにブラウザをリダイレクトします:
- TypeScript
- JavaScript
import { draftMode } from 'next/headers'
import { redirect } from 'next/navigation'
export async function GET(request: Request) {
// クエリ文字列パラメータを解析する
const { searchParams } = new URL(request.url)
const secret = searchParams.get('secret')
const slug = searchParams.get('slug')
// シークレットと次のパラメータを確認する
// このシークレットはこのRoute HandlerとCMSだけが知っているべきです
if (secret !== 'MY_SECRET_TOKEN' || !slug) {
return new Response('Invalid token', { status: 401 })
}
// 提供された`slug`が存在するかを確認するためにヘッドレスCMSをフェッチする
// getPostBySlugはヘッドレスCMSへのフェッチロジックを実装します
const post = await getPostBySlug(slug)
// slugが存在しない場合、ドラフトモードを有効にしない
if (!post) {
return new Response('Invalid slug', { status: 401 })
}
// クッキーをセットしてDraft Modeを有効にする
const draft = await draftMode()
draft.enable()
// フェッチした投稿のパスにリダイレクトする
// searchParams.slug にリダイレクトしないのは、オープンリダイレクトの脆弱性につながる可能性があるためです
redirect(post.slug)
}
import { draftMode } from 'next/headers'
import { redirect } from 'next/navigation'
export async function GET(request) {
// クエリ文字列パラメータを解析する
const { searchParams } = new URL(request.url)
const secret = searchParams.get('secret')
const slug = searchParams.get('slug')
// シークレットと次のパラメータを確認する
// このシークレットはこのRoute HandlerとCMSだけが知っているべきです
if (secret !== 'MY_SECRET_TOKEN' || !slug) {
return new Response('Invalid token', { status: 401 })
}
// 提供された`slug`が存在するかを確認するためにヘッドレスCMSをフェッチする
// getPostBySlugはヘッドレスCMSへのフェッチロジックを実装します
const post = await getPostBySlug(slug)
// slugが存在しない場合、ドラフトモードを有効にしない
if (!post) {
return new Response('Invalid slug', { status: 401 })
}
// クッキーをセットしてDraft Modeを有効にする
const draft = await draftMode()
draft.enable()
// フェッチした投稿のパスにリダイレクトする
// searchParams.slug にリダイレクトしないのは、オープンリダイレクトの脆弱性につながる可能性があるためです
redirect(post.slug)
}
成功すれば、ブラウザがドラフトモードのクッキーと共に表示したいパスにリダイレクトされます。
手順3:ドラフトコンテンツをプレビューする
次は、ページを更新してdraftMode().isEnabled
の値を確認する必要があります。
クッキーが設定されたページをリクエストすると、データはリクエスト時にフェッチされます(ビルド時ではなく)。
さらに、isEnabled
の値はtrue
になります。
- TypeScript
- JavaScript
// データをフェッチするページ
import { draftMode } from 'next/headers'
async function getData() {
const { isEnabled } = await draftMode()
const url = isEnabled
? 'https://draft.example.com'
: 'https://production.example.com'
const res = await fetch(url)
return res.json()
}
export default async function Page() {
const { title, desc } = await getData()
return (
<main>
<h1>{title}</h1>
<p>{desc}</p>
</main>
)
}
// データをフェッチするページ
import { draftMode } from 'next/headers'
async function getData() {
const { isEnabled } = await draftMode()
const url = isEnabled
? 'https://draft.example.com'
: 'https://production.example.com'
const res = await fetch(url)
return res.json()
}
export default async function Page() {
const { title, desc } = await getData()
return (
<main>
<h1>{title}</h1>
<p>{desc}</p>
</main>
)
}
ヘッドレスCMSから、またはURLを使用して手動でドラフトRoute Handler(secret
とslug
を含む)にアクセスすると、ドラフトコンテンツを確認できるようになります。ドラフトを公開せずに更新した場合でも、ドラフトを見ることができます。