Menu

ドラフトモード

ドラフトモードを使用すると、Next.jsアプリケーション内のヘッドレスCMSからドラフトコンテンツをプレビューできます。これは、ビルド時に生成される静的ページに便利で、サイト全体を再ビルドすることなく、動的レンダリングに切り替えてドラフトの変更を確認できます。

このページでは、ドラフトモードの有効化と使用方法を説明します。

ステップ1: ルートハンドラの作成

ルートハンドラを作成します。名前は任意で、例えばapp/api/draft/route.tsなどとします。

app/api/draft/route.ts
export async function GET(request: Request) {
  return new Response('')
}
app/api/draft/route.js
export async function GET() {
  return new Response('')
}

次に、draftMode関数をインポートし、enable()メソッドを呼び出します。

app/api/draft/route.ts
import { draftMode } from 'next/headers'
 
export async function GET(request: Request) {
  const draft = await draftMode()
  draft.enable()
  return new Response('ドラフトモードが有効になりました')
}
app/api/draft/route.js
import { draftMode } from 'next/headers'
 
export async function GET(request) {
  const draft = await draftMode()
  draft.enable()
  return new Response('ドラフトモードが有効になりました')
}

これにより、ドラフトモードを有効にするためのCookieが設定されます。このCookieを含む後続のリクエストは、ドラフトモードをトリガーし、静的に生成されたページの動作を変更します。

ブラウザの開発者ツールで/api/draftにアクセスし、Set-Cookieレスポンスヘッダーに__prerender_bypassという名前のCookieがあることを確認して、手動でテストできます。

ステップ2:ヘッドレスCMSからルートハンドラにアクセスする

これらの手順は、使用しているヘッドレスCMSがカスタムドラフトURLの設定をサポートしていることを前提としています。サポートしていない場合でも、このメソッドでドラフトURLを保護できますが、ドラフトURLを手動で構築およびアクセスする必要があります。具体的な手順は、使用しているヘッドレスCMSによって異なります。

ヘッドレスCMSからルートハンドラに安全にアクセスするには:

  1. 任意のトークンジェネレーターを使用して、シークレットトークン文字列を作成します。このシークレットは、Next.jsアプリとヘッドレスCMS間でのみ知られます。
  2. ヘッドレスCMSがカスタムドラフトURLの設定をサポートする場合、ドラフトURLを指定します(これは、ルートハンドラがapp/api/draft/route.tsに配置されていることを前提としています)。例:
Terminal
https://<your-site>/api/draft?secret=<token>&slug=<path>
  • <your-site>は、デプロイメントドメインに置き換えてください。
  • <token>は、生成したシークレットトークンに置き換えてください。
  • <path>は、表示したいページのパスです。/posts/oneを表示する場合、&slug=/posts/oneを使用します。

ヘッドレスCMSによっては、ドラフトURLに変数を含めることができ、<path>をCMSのデータに基づいて動的に設定できます:&slug=/posts/{entry.fields.slug}

  1. ルートハンドラで、シークレットが一致し、slugパラメータが存在することを確認し(存在しない場合、リクエストは失敗)、draftMode.enable()を呼び出してCookieを設定します。次に、ブラウザをslugで指定されたパスにリダイレクトします:
app/api/draft/route.ts
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')
 
  // シークレットパラメータとnextパラメータを確認
  // このシークレットは、このルートハンドラとCMSのみが知っているべきです
  if (secret !== 'MY_SECRET_TOKEN' || !slug) {
    return new Response('Invalid token', { status: 401 })
  }
 
  // ヘッドレスCMSをフェッチして、指定された`slug`が存在するか確認
  // getPostBySlugは、ヘッドレスCMSへのフェッチロジックを実装する必要があります
  const post = await getPostBySlug(slug)
 
  // slugが存在しない場合、ドラフトモードの有効化を防ぐ
  if (!post) {
    return new Response('Invalid slug', { status: 401 })
  }
 
  // Cookieを設定してドラフトモードを有効化
  const draft = await draftMode()
  draft.enable()
 
  // フェッチしたポストのパスにリダイレクト
  // オープンリダイレクトの脆弱性を避けるため、searchParams.slugにリダイレクトしません
  redirect(post.slug)
}
app/api/draft/route.js
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')
 
  // シークレットパラメータとnextパラメータを確認
  // このシークレットは、このルートハンドラとCMSのみが知っているべきです
  if (secret !== 'MY_SECRET_TOKEN' || !slug) {
    return new Response('Invalid token', { status: 401 })
  }
 
  // ヘッドレスCMSをフェッチして、指定された`slug`が存在するか確認
  // getPostBySlugは、ヘッドレスCMSへのフェッチロジックを実装する必要があります
  const post = await getPostBySlug(slug)
 
  // slugが存在しない場合、ドラフトモードの有効化を防ぐ
  if (!post) {
    return new Response('Invalid slug', { status: 401 })
  }
 
  // Cookieを設定してドラフトモードを有効化
  const draft = await draftMode()
  draft.enable()
 
  // フェッチしたポストのパスにリダイレクト
  // オープンリダイレクトの脆弱性を避けるため、searchParams.slugにリダイレクトしません
  redirect(post.slug)
}

成功すると、ブラウザはドラフトモードCookieと共に表示したいパスにリダイレクトされます。

ステップ3:ドラフトコンテンツのプレビュー

次のステップは、draftMode().isEnabledの値をチェックするようページを更新することです。

Cookieが設定されているページをリクエストすると、データはリクエスト時(ビルド時ではなく)にフェッチされます。

さらに、isEnabledの値はtrueになります。

app/page.tsx
TypeScript
// データをフェッチするページ
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を使用してドラフトルートハンドラ(secretslug付き)にアクセスすると、ドラフトコンテンツを表示できるはずです。また、ドラフトを公開せずに更新した場合も、ドラフトを表示できるはずです。

次のステップ

ドラフトモードの使用方法についての詳細は、APIリファレンスを参照してください。