プレビューモード
注意: この機能はドラフトモードに置き換えられています。
例
- 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 のドキュメントとデータフェッチングのドキュメントで、getStaticProps
と getStaticPaths
を使用してビルド時にページを事前レンダリングする方法(静的生成)について説明しました。
静的生成は、ヘッドレスCMSからデータをフェッチするページに役立ちます。しかし、ヘッドレスCMS上で下書きを作成し、そのドラフトをすぐにページでプレビューしたい場合は理想的ではありません。ユーザーは、Next.jsにビルド時ではなくリクエスト時にページをレンダリングし、公開されたコンテンツではなくドラフトコンテンツをフェッチしてほしいと考えます。Next.jsに、この特定のケースでのみ静的生成をバイパスしてほしいのです。
Next.jsには、この問題を解決するプレビューモードという機能があります。以下にその使用方法を説明します。
ステップ1:プレビューAPIルートの作成とアクセス
Next.jsのAPIルートに慣れていない場合は、まずAPIルートのドキュメントを確認してください。
まず、プレビューAPIルートを作成します。名前は任意です。例えば、pages/api/preview.js
(TypeScriptを使用する場合は.ts
)です。
このAPIルートでは、レスポンスオブジェクトでsetPreviewData
を呼び出す必要があります。setPreviewData
の引数はオブジェクトである必要があり、これはgetStaticProps
で使用できます(詳細は後述)。今のところ、{}
を使用します。
export default function handler(req, res) {
// ...
res.setPreviewData({})
// ...
}
res.setPreviewData
は、ブラウザにCookieを設定し、プレビューモードをオンにします。これらのCookieを含むNext.jsへのリクエストは、プレビューモードと見なされ、静的に生成されたページの動作が変更されます(詳細は後述)。
以下のようなAPIルートを作成し、ブラウザから手動でアクセスすることで、手動でテストできます:
// ブラウザから手動でテストするための簡単な例。
export default function handler(req, res) {
res.setPreviewData({})
res.end('プレビューモードが有効になりました')
}
ブラウザの開発者ツールで /api/preview
にアクセスすると、このリクエストで __prerender_bypass
と __next_preview_data
のCookieが設定されることに気づくでしょう。
ヘッドレスCMSから安全にアクセスする
実際には、ヘッドレスCMSから_安全に_このAPIルートを呼び出したいと思うでしょう。具体的な手順は使用しているヘッドレス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に変数を含めることができ、<path>
をCMSのデータに基づいて動的に設定できます:&slug=/posts/{entry.fields.slug}
最後に、プレビューAPIルートで以下を行います:
- シークレットが一致し、
slug
パラメータが存在することを確認します(存在しない場合、リクエストは失敗する必要があります)。 res.setPreviewData
を呼び出します。- ブラウザを
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: '無効なトークン' })
}
// ヘッドレスCMSをフェッチし、提供された`slug`が存在するか確認
// getPostBySlugは、ヘッドレスCMSへの必要なフェッチロジックを実装します
const post = await getPostBySlug(req.query.slug)
// slugが存在しない場合、プレビューモードの有効化を防ぐ
if (!post) {
return res.status(401).json({ message: '無効なslug' })
}
// プレビューモードをCookieの設定によって有効化
res.setPreviewData({})
// フェッチしたポストのパスにリダイレクト
// オープンリダイレクトの脆弱性を避けるため、req.query.slugにリダイレクトしません
res.redirect(post.slug)
}
成功した場合、ブラウザはプレビューモードのCookieが設定された、プレビューしたいパスにリダイレクトされます。
ステップ2:getStaticProps
の更新
次のステップは、プレビューモードをサポートするためにgetStaticProps
を更新することです。
プレビューモードのCookie(res.setPreviewData
経由)が設定された状態でページをリクエストすると、getStaticProps
は(ビルド時ではなく)リクエスト時に呼び出されます。
さらに、以下のcontext
オブジェクトと共に呼び出されます:
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 の場合、APIエンドポイントに "/preview" を追加し、
// 公開されたデータではなく下書きデータをリクエストします。
// これは使用しているヘッドレスCMSによって異なります。
const res = await fetch(`https://.../${context.preview ? 'preview' : ''}`)
// ...
}
これで完了です!ヘッドレスCMSから、または手動でプレビューAPIルート(secret
と slug
付き)にアクセスすると、プレビューコンテンツを表示できるはずです。下書きを更新して公開しない場合、下書きをプレビューできるはずです。
ヘッドレスCMSでプレビューURLを設定するか、手動でアクセスし、プレビューを表示してください。
https://<your-site>/api/preview?secret=<token>&slug=<path>
さらに詳しく
補足: レンダリング中、
next/router
はisPreview
フラグを公開します。詳細はルーターオブジェクトのドキュメントを参照してください。
プレビューモードの期間を指定
setPreviewData
は、オプションのセカンドパラメータとしてオプションオブジェクトを受け取ります。以下のキーを受け入れます:
maxAge
: プレビューセッションの継続時間(秒単位)を指定します。path
: Cookieを適用するパスを指定します。デフォルトは/
で、すべてのパスでプレビューモードを有効にします。
setPreviewData(data, {
maxAge: 60 * 60, // プレビューモードのCookieは1時間で期限切れ
path: '/about', // プレビューモードのCookieは /about のパスに適用されます
})
### プレビューモードのクッキーをクリア
デフォルトでは、プレビューモードのクッキーには有効期限が設定されていないため、ブラウザを閉じるとプレビューセッションが終了します。
プレビューモードのクッキーを手動でクリアするには、`clearPreviewData()`を呼び出すAPIルートを作成します:
```js filename="pages/api/clear-preview-mode-cookies.js"
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
を含むコンテキストオブジェクトでも利用可能です。
補足: プレビューモードを使用する際は、バイパスできないため
Cache-Control
ヘッダーを設定しないでください。代わりに、ISRの使用をお勧めします。
APIルートで動作
APIルートは、リクエストオブジェクト下のpreview
とpreviewData
にアクセスできます。例:
export default function myApiRoute(req, res) {
const isPreview = req.preview
const previewData = req.previewData
// ...
}
next build
ごとにユニーク
バイパスクッキーの値とpreviewData
を暗号化するプライベートキーは、next build
が完了するたびに変更されます。
これにより、バイパスクッキーを推測できないようにします。
補足: HTTPでプレビューモードをローカルでテストするには、ブラウザでサードパーティのクッキーとローカルストレージへのアクセスを許可する必要があります。