コンテンツにスキップ

ドラフトモード

ページのドキュメントデータフェッチのドキュメントでは、`getStaticProps`と`getStaticPaths`を使用してビルド時にページを事前レンダリングする方法(**静的生成**)について説明しました。

静的生成は、ページがヘッドレスCMSからデータを取得する場合に役立ちます。ただし、ヘッドレスCMSで下書きを書いていて、すぐにページに下書きを表示したい場合は、理想的ではありません。Next.jsに、この特定のケースについてのみ静的生成をバイパスして、**リクエスト時**にこれらのページをレンダリングし、公開されたコンテンツではなく下書きコンテンツを取得させたい場合があります。

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 })
  // ...
}

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

以下のようにAPIルートを作成し、ブラウザから手動でアクセスすることで、手動でテストできます。

pages/api/draft.ts
// 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`という名前のCookieを含む`Set-Cookie`レスポンスヘッダーが表示されます。

ヘッドレスCMSから安全にアクセスする
ターミナル
https://<your-site>/api/draft?secret=<token>&slug=<path>

  • `<your-site>`は、デプロイドメインにする必要があります。
  • `<token>`は、生成したシークレットトークンに置き換える必要があります。
  • `<path>`は、表示するページのパスにする必要があります。`/posts/foo`を表示する場合は、`&slug=/posts/foo`を使用する必要があります。

ヘッドレスCMSでは、ドラフトURLに変数を埋め込むことができる場合があります。そのため、`<path>`は、CMSのデータに基づいて`&slug=/posts/{entry.fields.slug}`のように動的に設定できます。

**最後に**、ドラフトAPIルートで

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)
}

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

ステップ 2: getStaticProps を更新する

次のステップは、ドラフトモードをサポートするために getStaticProps を更新することです。

res.setDraftMode を介してCookieが設定された getStaticProps を持つページをリクエストすると、getStaticProps は(ビルド時ではなく)**リクエスト時**に呼び出されます。

さらに、context.draftModetrue になる context オブジェクトと共に呼び出されます。

export async function getStaticProps(context) {
  if (context.draftMode) {
    // dynamic data
  }
}

ドラフトAPIルートで res.setDraftMode を使用したので、context.draftModetrue になります。

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ルート(secretslug を使用)にアクセスすると、ドラフトコンテンツが表示されるようになります。公開せずにドラフトを更新すると、ドラフトを表示できます。

これをヘッドレスCMSのドラフトURLとして設定するか、手動でアクセスすると、ドラフトが表示されます。

ターミナル
https://<your-site>/api/draft?secret=<token>&slug=<path>

詳細

次に、/api/disable-draft にリクエストを送信してAPIルートを呼び出します。 next/link を使用してこのルートを呼び出す場合は、プリフェッチで誤ってCookieを削除しないように、prefetch={false} を渡す必要があります。

getServerSideProps で動作する context オブジェクトの draftMode キーとして使用できます。

**知っておくべきこと**: ドラフトモードを使用しているときは、`Cache-Control`ヘッダーを設定しないでください。バイパスできないためです。代わりに、ISRを使用することをお勧めします。

APIルートで動作する
export default function myApiRoute(req, res) {
  if (req.draftMode) {
    // get draft data
  }
}

next build ごとに一意

**知っておくべきこと**: HTTP経由でローカルでドラフトモードをテストするには、ブラウザでサードパーティCookieとローカルストレージアクセスを許可する必要があります。