プレビューモード
注: この機能はドラフトモードに置き換えられました。
例
- WordPress の例 (デモ)
- DatoCMS の例 (デモ)
- TakeShape の例 (デモ)
- Sanity の例 (デモ)
- Prismicの例 (デモ)
- Contentfulの例 (デモ)
- Strapiの例 (デモ)
- Preprの例 (デモ)
- Agility CMSの例 (デモ)
- Cosmicの例 (デモ)
- ButterCMSの例 (デモ)
- Storyblokの例 (デモ)
- GraphCMSの例 (デモ)
- Kontentの例 (デモ)
- Umbraco Heartcoreの例 (デモ)
- Plasmicの例 (デモ)
- Enterspeedの例 (デモ)
- Makeswiftの例 (デモ)
Pagesドキュメントとデータフェッチングドキュメントで、getStaticProps
とgetStaticPaths
を使って、ビルド時にページをプリレンダリング(**静的生成**)する方法について説明しました。
静的生成は、ページがヘッドレスCMSからデータを取得する場合に便利です。しかし、ヘッドレスCMSで下書きを作成し、その下書きをページ上で即座に**プレビュー**したい場合には理想的ではありません。Next.jsには、ビルド時ではなく**リクエスト時**にこれらのページをレンダリングし、公開されたコンテンツの代わりに下書きコンテンツを取得してほしいでしょう。Next.jsに、この特定のケースでのみ静的生成をバイパスさせたいでしょう。
Next.jsには、この問題を解決する**プレビューモード**という機能があります。以下にその使用方法を説明します。
ステップ 1: プレビュー API ルートの作成とアクセス
Next.js API Routes に慣れていない場合は、まずAPI ルートのドキュメントをご覧ください。
まず、プレビュー 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
のクッキーが設定されていることがわかります。
Headless CMS から安全にアクセスする
実際には、headless CMS からこの API ルートを安全に呼び出す必要があります。具体的な手順は、使用している headless CMS によって異なりますが、一般的な手順をいくつかご紹介します。
これらの手順は、使用している headless CMS がカスタムプレビュー URLの設定をサポートしていることを前提としています。サポートしていない場合でも、この方法でプレビュー URL を保護できますが、プレビュー URL を手動で作成してアクセスする必要があります。
まず、任意のトークンジェネレーターを使用してシークレットトークン文字列を作成する必要があります。このシークレットは、Next.js アプリと headless CMS のみが知っています。このシークレットは、CMS にアクセスできないユーザーがプレビュー URL にアクセスするのを防ぎます。
次に、headless 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
を使用する必要があります。
headless CMS では、プレビュー URL に変数を組み込んで、<path>
を CMS のデータに基づいて動的に設定できるようにすることができます。例: &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
を更新できます。
たとえば、headless 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' : ''}`)
// ...
}
以上です! headless CMS から、または手動でプレビュー API ルート(secret
と slug
を使用)にアクセスすると、プレビューコンテンツが表示されるはずです。また、公開せずにドラフトを更新すると、ドラフトをプレビューできます。
これを headless CMS のプレビュー URL として設定するか、手動でアクセスすると、プレビューが表示されるはずです。
https://<your-site>/api/preview?secret=<token>&slug=<path>
詳細
知っておくと便利: レンダリング中に
next/router
はisPreview
フラグを公開します。詳細については、ルーターオブジェクトのドキュメントを参照してください。
プレビューモードの期間を指定する
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ルートで動作します
APIルートは、リクエストオブジェクトの下でpreview
とpreviewData
にアクセスできます。例えば
export default function myApiRoute(req, res) {
const isPreview = req.preview
const previewData = req.previewData
// ...
}
next build
ごとに固有です
next build
が完了すると、バイパスクッキーの値とpreviewData
を暗号化するための秘密鍵の両方が変更されます。これにより、バイパスクッキーが推測できないようにします。
知っておくと良いこと:HTTP経由でローカルでプレビューモードをテストするには、ブラウザでサードパーティCookieとローカルストレージへのアクセスを許可する必要があります。
これは役に立ちましたか?