Menu

ドラフトモード

Pagesドキュメントデータフェッチングドキュメントで、getStaticPropsgetStaticPathsを使用してビルド時にページをプリレンダリングする方法(静的生成)について説明しました。

静的生成は、ヘッドレスCMSからデータをフェッチするページに有用です。しかし、ヘッドレスCMSでドラフトを作成し、すぐにページでプレビューしたい場合は理想的ではありません。Next.jsにビルド時ではなくリクエスト時にページをレンダリングし、公開コンテンツではなくドラフトコンテンツをフェッチしてほしいでしょう。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
// ブラウザから手動でテストするための簡単な例。
export default function handler(req, res) {
  res.setDraftMode({ enable: true })
  res.end('ドラフトモードが有効になりました')
}

ブラウザの開発者ツールで/api/draftにアクセスすると、__prerender_bypassという名前のCookieを含むSet-Cookieレスポンスヘッダーに気づくでしょう。

ヘッドレスCMSから安全にアクセスする

実際には、ヘッドレスCMSから_安全に_このAPIルートを呼び出したいでしょう。具体的な手順は使用しているヘッドレスCMSによって異なりますが、以下は一般的な手順です。

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

まず、任意のトークンジェネレーターを使用してシークレットトークン文字列を作成します。このシークレットは、Next.jsアプリとヘッドレスCMS間でのみ知られます。このシークレットにより、CMSにアクセスできない人がドラフトURLにアクセスするのを防ぎます。

次に、ヘッドレスCMSがカスタムドラフトURLの設定をサポートしている場合、以下をドラフトURLとして指定します。これは、ドラフトAPIルートがpages/api/draft.tsに配置されていることを前提としています。

Terminal
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ルートで:

  • シークレットが一致し、slugパラメータが存在することを確認します(存在しない場合、リクエストは失敗する必要があります)。
  • res.setDraftModeを呼び出します。
  • ブラウザをslugで指定されたパスにリダイレクトします。(次の例では307リダイレクトを使用しています)。
export default async (req, res) => {
  // シークレットとnextパラメータを確認
  // このシークレットはこのAPIルートとCMSのみが知っているべきです
  if (req.query.secret !== 'MY_SECRET_TOKEN' || !req.query.slug) {
    return res.status(401).json({ message: '無効なトークン' })
  }
 
  // ヘッドレスCMSをフェッチし、提供された`slug`が存在するか確認
  // getPostBySlugはヘッドレスCMSへの必要なフェッチロジックを実装します
  const post = await getPostBySlug(req.query.slug)
 
  // slugが存在しない場合、ドラフトモードの有効化を防ぐ
  if (!post) {
    return res.status(401).json({ message: '無効なslug' })
  }
 
  // ドラフトモードをCookieの設定により有効化
  res.setDraftMode({ enable: true })
 
  // フェッチしたポストのパスにリダイレクト
  // オープンリダイレクトの脆弱性を避けるため、req.query.slugにはリダイレクトしません
  res.redirect(post.slug)
}

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

ステップ2:getStaticPropsの更新

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

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

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

export async function getStaticProps(context) {
  if (context.draftMode) {
    // 動的データ
  }
}

ドラフト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を設定するか、手動でアクセスすれば、ドラフトを表示できます。

Terminal
https://<your-site>/api/draft?secret=<token>&slug=<path>

さらに詳しく

ドラフトモードCookieのクリア

デフォルトでは、ドラフトモードセッションはブラウザを閉じると終了します。

ドラフトモードCookieを手動でクリアするには、setDraftMode({ enable: false })を呼び出すAPIルートを作成します:

pages/api/disable-draft.ts
export default function handler(req, res) {
  res.setDraftMode({ enable: false })
}

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

getServerSidePropsで動作

ドラフトモードはgetServerSidePropsで動作し、contextオブジェクトのdraftModeキーとして利用可能です。

補足: ドラフトモード使用時はCache-Controlヘッダーを設定しないでください。代わりにISRの使用をお勧めします。

APIルートで動作

APIルートは、リクエストオブジェクトのdraftModeにアクセスできます。例:

export default function myApiRoute(req, res) {
  if (req.draftMode) {
    // ドラフトデータを取得
  }
}

next buildごとにユニーク

next buildを実行するたびに、新しいバイパスCookieの値が生成されます。

これにより、バイパスCookieを推測できないことを保証します。

補足: HTTPでドラフトモードをローカルでテストするには、ブラウザでサードパーティCookieとローカルストレージへのアクセスを許可する必要があります。