Sponsor
ChatHubChatHub Use GPT-4, Gemini, Claude 3.5 and more chatbots side-by-side
ここをクリック
Menu

ドラフトモード

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

静的生成は、ヘッドレス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
// ブラウザから手動でテストするための簡単な例
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: '無効なトークン' })
  }
 
  // 提供された`slug`が存在するかどうかを確認するためにヘッドレスCMSをフェッチ
  // 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をドラフトモードをサポートするように更新することです。

res.setDraftModeによってCookieが設定された状態でgetStaticPropsを持つページをリクエストすると、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とローカルストレージへのアクセスを許可する必要があります。