ドラフトモード
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 })
// ...
}
これにより、ドラフトモードを有効にするクッキーが設定されます。このクッキーを含む後続のリクエストはドラフトモードをトリガーし、静的に生成されたページの動作を変更します(詳細は後述)。
以下のようなAPIルートを作成し、ブラウザから手動でアクセスすることでテストできます:
// ブラウザから手動でテストするための簡単な例
export default function handler(req, res) {
res.setDraftMode({ enable: true })
res.end('ドラフトモードが有効です')
}
ブラウザの開発者ツールを開いて/api/draft
にアクセスすると、__prerender_bypass
という名前のクッキーを持つ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) => {
// 秘密トークンと次のパラメータを確認
// この秘密はこの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です' })
}
// クッキーを設定してドラフトモードを有効化
res.setDraftMode({ enable: true })
// 取得した投稿のパスにリダイレクト
// req.query.slugにはリダイレクトしない(オープンリダイレクト脆弱性につながる可能性があるため)
res.redirect(post.slug)
}
成功すると、ブラウザはドラフトモードクッキーとともに確認したいパスにリダイレクトされます。
ステップ2: getStaticProps
の更新
次のステップは、getStaticProps
を更新してドラフトモードをサポートすることです。
getStaticProps
を持つページにクッキーが設定された状態(res.setDraftMode
経由)でリクエストすると、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>
詳細情報
ドラフトモードクッキーのクリア
デフォルトでは、ドラフトモードセッションはブラウザを閉じると終了します。
ドラフトモードクッキーを手動でクリアするには、setDraftMode({ enable: false })
を呼び出すAPIルートを作成します:
export default function handler(req, res) {
res.setDraftMode({ enable: false })
}
その後、APIルートを呼び出すために/api/disable-draft
にリクエストを送信します。next/link
を使用してこのルートを呼び出す場合、プリフェッチ時に誤ってクッキーを削除しないように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
を実行するたびに、新しいバイパスクッキー値が生成されます。
これにより、バイパスクッキーが推測されるのを防ぎます。
知っておくと良い: HTTP経由でローカルでドラフトモードをテストするには、ブラウザでサードパーティクッキーとローカルストレージへのアクセスを許可する必要があります。