プレビューモード
注: この機能はDraft Modeによって置き換えられました。
例
- Agility CMS の例 (デモ)
- Builder.io の例 (デモ)
- ButterCMS の例 (デモ)
- Contentful の例 (デモ)
- Cosmic の例 (デモ)
- DatoCMS の例 (デモ)
- DotCMS の例 (デモ)
- Drupal の例 (デモ)
- Enterspeed の例 (デモ)
- GraphCMS の例 (デモ)
- Keystone の例 (デモ)
- Kontent.ai の例 (デモ)
- Makeswift の例 (デモ)
- Plasmic の例 (デモ)
- Prepr の例 (デモ)
- Prismic の例 (デモ)
- Sanity の例 (デモ)
- Sitecore XM Cloud の例 (デモ)
- Storyblok の例 (デモ)
- Strapi の例 (デモ)
- TakeShape の例 (デモ)
- Tina の例 (デモ)
- Umbraco の例 (デモ)
- Umbraco Heartcore の例 (デモ)
- Webiny の例 (デモ)
- WordPress の例 (デモ)
- ブログスターターの例 (デモ)
「Pages ドキュメント」と「Data Fetching ドキュメント」では、getStaticProps
と getStaticPaths
を使用してビルド時にページをプリレンダリングする方法(静的生成)について説明しました。
静的生成は、ページがヘッドレスCMSからデータをフェッチする場合に役立ちます。しかし、ヘッドレスCMSでドラフトを作成していて、そのドラフトをすぐにページでプレビューしたい場合には理想的ではありません。Next.jsには、ビルド時ではなくリクエスト時にこれらのページをレンダリングし、公開済みコンテンツの代わりにドラフトコンテンツをフェッチしてほしいと思うでしょう。この特定のケースでのみ、Next.jsが静的生成をバイパスするようにしたいと考えるでしょう。
Next.jsには、この問題を解決するプレビューモードという機能があります。その使用方法を説明します。
ステップ1: プレビューAPIルートの作成とアクセス
Next.jsのAPI Routesに馴染みがない場合は、まず「API Routes ドキュメント」をご覧ください。
まず、プレビューAPIルートを作成します。任意の名前を付けることができます。例:pages/api/preview.js
(TypeScriptを使用している場合は.ts
)。
このAPIルートでは、レスポンスオブジェクトでsetPreviewData
を呼び出す必要があります。setPreviewData
の引数はオブジェクトである必要があり、これはgetStaticProps
で使用できます(詳細はこの後説明します)。ここでは、{}
を使用します。
export default function handler(req, res) {
// ...
res.setPreviewData({})
// ...
}
res.setPreviewData
は、プレビューモードをオンにするためのクッキーをブラウザに設定します。これらのクッキーを含むNext.jsへのリクエストはすべてプレビューモードと見なされ、静的に生成されたページの動作が変更されます(詳細はこの後説明します)。
以下のようにAPIルートを作成し、ブラウザから手動でアクセスすることで、これを手動でテストできます。
// simple example for testing it manually from your browser.
export default function handler(req, res) {
res.setPreviewData({})
res.end('Preview mode enabled')
}
ブラウザの開発者ツールを開いて/api/preview
にアクセスすると、このリクエストで__prerender_bypass
と__next_preview_data
というクッキーが設定されていることに気づくでしょう。
ヘッドレスCMSから安全にアクセスする
実際には、このAPIルートをヘッドレスCMSから安全に呼び出したいと思うでしょう。具体的な手順は使用するヘッドレスCMSによって異なりますが、一般的な手順をいくつかご紹介します。
これらの手順は、使用しているヘッドレスCMSがカスタムプレビューURLの設定をサポートしていることを前提としています。サポートしていない場合でも、この方法でプレビューURLを保護することはできますが、プレビューURLを手動で構築してアクセスする必要があります。
まず、任意のトークンジェネレーターを使用して秘密トークン文字列を作成する必要があります。この秘密は、あなたのNext.jsアプリとヘッドレスCMSのみが知っているものになります。この秘密は、CMSへのアクセス権を持たない人がプレビューURLにアクセスするのを防ぎます。
次に、ヘッドレスCMSがカスタムプレビューURLの設定をサポートしている場合、プレビューURLとして以下を指定します。これは、プレビューAPIルートがpages/api/preview.js
に配置されていることを前提としています。
https://<your-site>/api/preview?secret=<token>&slug=<path>
<your-site>
はデプロイメントドメインである必要があります。<token>
は、生成した秘密トークンに置き換える必要があります。<path>
は、プレビューしたいページのパスである必要があります。/posts/foo
をプレビューしたい場合は、&slug=/posts/foo
を使用する必要があります。
ご利用のヘッドレスCMSによっては、プレビューURLに変数を追加できる場合があります。これにより、CMSのデータに基づいて<path>
を動的に設定できます(例: &slug=/posts/{entry.fields.slug}
)。
最後に、プレビューAPIルートで
- 秘密が一致し、
slug
パラメータが存在することを確認します(存在しない場合、リクエストは失敗するはずです)。 res.setPreviewData
を呼び出します。- その後、ブラウザを
slug
で指定されたパスにリダイレクトします。(以下の例では、307リダイレクトを使用しています)。
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 preview mode from being enabled
if (!post) {
return res.status(401).json({ message: 'Invalid slug' })
}
// Enable Preview Mode by setting the cookies
res.setPreviewData({})
// 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)
}
成功すると、ブラウザはプレビューモードのクッキーが設定された状態で、プレビューしたいパスにリダイレクトされます。
ステップ2: getStaticProps
を更新する
次のステップは、プレビューモードをサポートするようにgetStaticProps
を更新することです。
プレビューモードのクッキーが設定された(res.setPreviewData
経由で)getStaticProps
を持つページをリクエストすると、getStaticProps
はリクエスト時に(ビルド時ではなく)呼び出されます。
さらに、以下のcontext
オブジェクトで呼び出されます。
context.preview
はtrue
になります。context.previewData
は、setPreviewData
で使用された引数と同じになります。
export async function getStaticProps(context) {
// If you request this page with the preview mode cookies set:
//
// - context.preview will be true
// - context.previewData will be the same as
// the argument used for `setPreviewData`.
}
プレビューAPIルートではres.setPreviewData({})
を使用しましたので、context.previewData
は{}
になります。必要に応じて、これをプレビューAPIルートからgetStaticProps
にセッション情報を渡すために使用できます。
getStaticPaths
も使用している場合、context.params
も利用できます。
プレビューデータをフェッチする
context.preview
またはcontext.previewData
に基づいて異なるデータをフェッチするようにgetStaticProps
を更新できます。
例えば、ご利用のヘッドレスCMSには、ドラフト投稿用の異なるAPIエンドポイントがあるかもしれません。その場合、以下のようにcontext.preview
を使用してAPIエンドポイントURLを変更できます。
export async function getStaticProps(context) {
// If context.preview is true, append "/preview" to the API endpoint
// to request draft data instead of published data. This will vary
// based on which headless CMS you're using.
const res = await fetch(`https://.../${context.preview ? 'preview' : ''}`)
// ...
}
これで完了です!ヘッドレスCMSから、または手動で(secret
とslug
を使って)プレビューAPIルートにアクセスすると、プレビューコンテンツが表示されるはずです。そして、公開せずにドラフトを更新した場合でも、そのドラフトをプレビューできるようになります。
これをヘッドレスCMSのプレビューURLとして設定するか、手動でアクセスすると、プレビューが表示されるはずです。
https://<your-site>/api/preview?secret=<token>&slug=<path>
詳細
補足: レンダリング中、
next/router
はisPreview
フラグを公開します。詳細については「router オブジェクトのドキュメント」を参照してください。
プレビューモードの期間を指定する
setPreviewData
は、オプションの第2引数としてオプションオブジェクトを受け取ります。以下のキーを受け入れます。
maxAge
: プレビューセッションが持続する秒数を指定します。path
: クッキーが適用されるパスを指定します。デフォルトは/
で、すべてのパスでプレビューモードが有効になります。
setPreviewData(data, {
maxAge: 60 * 60, // The preview mode cookies expire in 1 hour
path: '/about', // The preview mode cookies apply to paths with /about
})
プレビューモードのクッキーをクリアする
デフォルトでは、プレビューモードのクッキーに有効期限は設定されていません。そのため、プレビューセッションはブラウザが閉じられると終了します。
プレビューモードのクッキーを手動でクリアするには、clearPreviewData()
を呼び出すAPIルートを作成します。
export default function handler(req, res) {
res.clearPreviewData({})
}
その後、/api/clear-preview-mode-cookies
にリクエストを送信してAPIルートを呼び出します。next/link
を使用してこのルートを呼び出す場合、リンクのプリフェッチ中にclearPreviewData
が呼び出されるのを防ぐために、prefetch={false}
を渡す必要があります。
setPreviewData
の呼び出しでパスが指定されていた場合、同じパスをclearPreviewData
に渡す必要があります。
export default function handler(req, res) {
const { path } = req.query
res.clearPreviewData({ path })
}
previewData
のサイズ制限
setPreviewData
にオブジェクトを渡し、それをgetStaticProps
で利用可能にすることができます。ただし、データはクッキーに保存されるため、サイズ制限があります。現在、プレビューデータは2KBに制限されています。
getServerSideProps
でも動作します
プレビューモードはgetServerSideProps
でも動作します。preview
とpreviewData
を含むcontext
オブジェクトでも利用可能になります。
補足: プレビューモードを使用している場合、
Cache-Control
ヘッダーを設定すべきではありません。これはバイパスできないためです。代わりに、ISRの使用をお勧めします。
API Routesでも動作します
API Routesは、リクエストオブジェクトの下にあるpreview
とpreviewData
にアクセスできます。例えば、
export default function myApiRoute(req, res) {
const isPreview = req.preview
const previewData = req.previewData
// ...
}
next build
ごとにユニーク
next build
が完了すると、バイパスクッキーの値とpreviewData
を暗号化するための秘密鍵の両方が変更されます。これにより、バイパスクッキーが推測されないようにします。
補足: HTTP経由でプレビューモードをローカルでテストするには、ブラウザでサードパーティクッキーとローカルストレージへのアクセスを許可する必要があります。
この情報は役に立ちましたか?