このドキュメントは、Next.jsバージョン9.3以上を対象としています。Next.jsの古いバージョンを使用している場合は、 以前のドキュメント を参照してください。
ページのドキュメントとデータ取得のドキュメントで、getStaticProps
と getStaticPaths
を使って、ビルド時にページをプリレンダリングする静的生成について説明しました。
静的生成はヘッドレス CMS からページにデータを取得するときに役立ちます。しかし、ヘッドレス CMS で下書きをしていて、すぐにページでプレビューをしたいときには理想的ではありません。Next.js がビルド時ではなくリクエスト時にこれらのページをレンダリングし、公開されたコンテンツではなく下書きのコンテンツを取得するようにしたいでしょう。このような特定のケースにおいて、Next.js に静的生成をして欲しくない場合があります。
Next.js にはこの問題を解決するためのプレビューモードと呼ばれる機能があります。ここではその使い方について説明します。
Next.jsのAPIルートに慣れていない場合は、まず最初に APIルートのドキュメント を参照してください。
まず、プレビューAPI ルートを作成します。pages/api/preview.js
(TypeScript を使用している場合は .ts
) などの任意の名前をつけることが出来ます。
この API ルートでは、レスポンスオブジェクトから setPreviewData
を呼び出す必要があります。 setPreviewData
の引数はオブジェクトである必要があり、 getStatciProps
(これについては後ほど詳しく説明します)によって使用することが出来ます。ここでは {}
を使用します。
export default function handler(req, res) => {
// ...
res.setPreviewData({})
// ...
}
res.setPreviewData
はプレビューモードを実行するブラウザにいくつかの Cookie を設定します。これらの Cookie を含む Next.js へのリクエストはpreview modeと判断され、静的に生成されたページの動作が変更されます(これについては後ほど詳しく説明します)。
以下のような API ルートを作成し、ブラウザから手動でアクセスすることによって、これを手動でテストすることが出来ます:
// ブラウザから手動でテストするための簡単なサンプルです。
// もしこのファイルがpages/api/preview.jsに置かれているならば、
// ブラウザで、 /api/preview を開いてください。
export default function handler(req, res) => {
res.setPreviewData({})
res.end('Preview mode enabled')
}
ブラウザのデベロッパーツールを使用すると、 __prerender_bypass
と __next_preview_data
という Cookie がリクエストに設定されていることに気づくでしょう。
実際には、この 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 に変数を含めることも出来るので、これにより &slug=/posts/{entry.fields.slug}
のように、CMS のデータに基づいて動的に <path>
を設定できるようになります。
最後に、プレビューAPI ルートで以下の処理を行います:
slug
パラメータが存在することを確認してください(存在しない場合、リクエストは失敗するはずです)。res.setPreviewData
を呼び出してください.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: 'Invalid token' })
}
// 提供された `slug` が存在しているかどうか確認するため、ヘッドレスCMSをフェッチします。
// getPostBySlugはヘッドレスCMSへの必要なフェッチロジックを実装します。
const post = await getPostBySlug(req.query.slug)
// slugが存在しない場合、プレビューモードを有効にしないようにしましょう。
if (!post) {
return res.status(401).json({ message: 'Invalid slug' })
}
// Cookiesを設定し、プレビューモードを有効にします。
res.setPreviewData({})
// フェッチされた投稿にパスをリダイレクトします。
// オープンリダイレクトの脆弱性につながる可能性があるため、req.query.slugにリダイレクトしません。
res.redirect(post.slug)
}
成功すると、ブラウザはプレビューモードの Cookie が設定された状態で、プレビューするパスにリダイレクトされます。
getStaticProps
を更新次のステップはプレビューモードをサポートするように getStaticProps
を更新することです。
( res.setPreviewData
を経由して)プレビューモードの Cookie が設定されている getStaticProps
を含むページをリクエストすると、 getStaticProps
が(ビルド時ではなく)リクエスト時に呼び出されます。
さらに、次のような context
オブジェクトを引数に getStaticProps が呼ばれます:
context.preview
は true
になります。context.previewData
は setPreviewData
で使用されている引数と同じになります。export async function getStaticProps(context) {
// Cookieが設定されたプレビューモードのページをリクエストした場合:
//
// - context.previewはtrueになります。
// - context.previewDataは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) {
// context.previewがtrueの場合、"/preview" をAPIエンドポイントに追加します
// 公開されたデータの代わりに下書きデータをリクエストします。
// これは使用しているヘッドレスCMSによって異なります。
const res = await fetch(`https://.../${context.preview ? 'preview' : ''}`)
// ...
}
以上です!ヘッドレス CMS から、または手動で、( secret
と slug
を使用して)プレビューAPI ルートにアクセスすると、プレビューコンテンツを表示することが出来ます。また公開せずに下書きを更新すると、下書きをプレビューすることが出来るはずです。
# これをヘッドレスCMSのプレビューURLとして設定するか、手動でアクセスすることで、
# プレビューを見ることが出来るようになります。
https://<your-site>/api/preview?secret=<token>&slug=<path>
デフォルトでは、プレビューモードの Cookien には有効期限が設定されていないため、ブラウザを閉じるとプレビューモードが終了します。
手動でプレビューの Cookie を削除するには、 clearPreviewData
を呼ぶ API ルートを作成し、この API ルートにアクセスします。
export default function handler(req, res) => {
// プレビューモードのCookieを削除します。
// この関数は引数を受け取りません。
res.clearPreviewData()
// ...
}
注意:
Link
コンポーネントを用いてこのルートを呼び出す場合には、prefetch={false}
を渡してclearPreviewData
がプリフェッチ中に実行されることを防ぐ必要があります。
setPreviewData
はオプションで 2 番目のパラメータを指定でき、これが設定に関するオブジェクトになります。次のキーを受け取ります:
maxAge
: プレビューセッションの継続時間を指定します。setPreviewData(data, {
maxAge: 60 * 60, // プレビューモードのCookieの期限が1時間になります。
})
previewData
のサイズ制限オブジェクトを setPreviewData
に渡して、 getStaticProps
で利用可能にすることが出来ます。しかし、データは Cookie に保存されるため、サイズに制限があります。現在、プレビューデータは 2KB に制限されています。
getServerSideProps
の動作プレビューモードは getServerSideProps
でも同様に機能します。 preview
や previewData
を含む context
オブジェクトも利用可能です。
API ルートはリクエストオブジェクトの元にある preview
と previewData
へアクセスできます。例:
export default function myApiRoute(req, res) {
const isPreview = req.preview
const previewData = req.previewData
// ...
}
next build
ごとに単一next build
を実行するたびに、バイパス Cookie の値と暗号化された previewData
の秘密鍵が変更されます。これにより、バイパス Cookie を推測出来ないようにします。
注意: HTTP においてプレビューモードをローカルでテストするには、あなたのブラウザでサードパーティのクッキーとローカルストレージへのアクセスを許可する必要があります。
次のページも役に立つでしょう。