ドラフトモード
Pagesドキュメントとデータフェッチングドキュメントで、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ルートを作成します:
// ブラウザから手動でテストするための簡単な例
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
に配置されていることを前提としています。
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.draftMode
がtrue
であるcontext
オブジェクトと共に呼び出されます。
export async function getStaticProps(context) {
if (context.draftMode) {
// 動的データ
}
}
ドラフトAPIルートでres.setDraftMode
を使用したため、context.draftMode
はtrue
になります。
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ルート(secret
とslug
付き)にアクセスすると、ドラフトコンテンツを表示できるはずです。ドラフトを公開せずに更新しても、ドラフトを表示できるはずです。
ヘッドレスCMSでドラフトURLとして設定するか、手動でアクセスすると、ドラフトを表示できます。
https://<your-site>/api/draft?secret=<token>&slug=<path>
その他の詳細
ドラフトモードCookieのクリア
デフォルトでは、ドラフトモードセッションはブラウザを閉じると終了します。
ドラフトモードCookieを手動でクリアするには、setDraftMode({ enable: false })
を呼び出すAPIルートを作成します:
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とローカルストレージへのアクセスを許可する必要があります。