Draft Mode
Pages ドキュメントとData Fetching ドキュメントで、getStaticProps
と getStaticPaths
を使って、ページを build 時点で事前にレンダリングする方法(静的生成)について話しました。
あなたのページがヘッドレス CMS から fetch データするとき、スタティックジェネレーションは役立ちます。ただし、あなたがヘッドレス CMS でドラフトを作成し、そのドラフトをすぐにページで見たいときには最適ではありません。あなたは Next.js にこれらのページをrequest timeに render し、build time ではなく、公開されたコンテンツではなくドラフトのコンテンツを fetch するようにしたいと思うでしょう。この特定のケースについてだけ、あなたは Next.js にスタティックジェネレーションを回避してもらいたいと思うでしょう。
Next.js にはドラフトモードと呼ばれる機能があり、この問題を解決します。以下にその使用方法を説明します。
Step 1: Create and access the API route
あなたが Next.js API Routes に馴染みがない場合、まずはAPI Routes のドキュメンテーションをご覧ください。
まず、API routeを作成します。それは任意の名前を持つことができます - 例えば pages/api/draft.ts
この API route では、setDraftMode
を response object 上で呼び出す必要があります。
export default function handler(req, res) {
// ...
res.setDraftMode({ enable: true });
// ...
}
これによりcookieが設定され、ドラフトモードが有効になります。このクッキーを含む後続のリクエストはドラフトモードをトリガーし、静的に生成されたページの挙動が変更されます(詳細は後ほど)。
あなたは手動で以下のような API route を作成し、手動でブラウザからアクセスすることで、test を行うことができます。
// simple example for testing it manually from your browser.
export default function handler(req, res) {
res.setDraftMode({ enable: true })
res.end('Draft mode is enabled')
}
ブラウザの開発者ツールを開き、/api/draft
にアクセスすると、Set-Cookie
という response header と、__prerender_bypass
という名前の cookie が表示されることに気づくでしょう。
Securely accessing it from your Headless CMS
実際には、この API route をheadless CMSから安全に呼び出したいと思うでしょう。具体的な手順は使用する headless CMS により異なりますが、以下にいくつかの一般的な手順を示します。
これらの手順は、使用しているヘッドレス CMS がカスタムドラフト URLの設定をサポートしていることを前提としています。サポートされていない場合でも、この方法を使用してドラフト URL を保護することはできますが、ドラフト URL を手動で構築してアクセスする必要があります。
まず、選択したトークンジェネレーターを使用してシークレットトークン文字列を作成する必要があります。このシークレットは、あなたの Next.js アプリとヘッドレス CMS のみが知っています。このシークレットは、CMS にアクセスできない人がドラフト URL にアクセスするのを防ぎます。
次に、ヘッドレス CMS がカスタムドラフト URL の設定をサポートしている場合は、ドラフトの URL として以下を指定します。これは、ドラフトの API route が pages/api/draft.ts
に位置していることを前提としています。
https://<your-site>/api/draft?secret=<token>&slug=<path>
<your-site>
はデプロイメントドメインであるべきです。<token>
は生成したシークレットトークンに置き換えるべきです。<path>
は閲覧したいページの path であるべきです。/posts/foo
を閲覧したい場合は、&slug=/posts/foo
を使用すべきです。
あなたのヘッドレス CMS は、ドラフト URL に変数を含めることを許可するかもしれません。そのため、CMS のデータに基づいて動的に<path>
を設定できるようになります。例えば、&slug=/posts/{entry.fields.slug}
のようにします。
最終的に、ドラフトの API route では:
slug
パラメーターが存在するかどうか(存在しない場合、 request が失敗するはずです)と、 secret が一致していることを確認してください。-res.setDraftMode
を呼び出す。- その後、
slug
で指定された path にブラウザを redirect します。(次の例では307 redirect を使用しています)。
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 draft mode from being enabled
if (!post) {
return res.status(401).json({ message: "Invalid slug" });
}
// Enable Draft Mode by setting the cookie
res.setDraftMode({ enable: true });
// 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);
};
成功すると、ブラウザはドラフトモードのクッキーを使用して閲覧したいパスにリダイレクトされます。
Step 2: Update getStaticProps
次のステップは、ドラフトモードをサポートするようにgetStaticProps
を更新することです。
getStaticProps
が設定された(res.setDraftMode
を介して)ページを request する場合、getStaticProps
はrequest timeで呼び出されます(build time の代わりに)。
さらに、context
object として呼び出され、context.draftMode
はtrue
になります。
export async function getStaticProps(context) {
if (context.draftMode) {
// dynamic data
}
}
私たちはドラフトの API route でres.setDraftMode
を使用したので、context.draftMode
はtrue
になります。
あなたがgetStaticPaths
も使用している場合、context.params
も利用可能になります。
Fetch ドラフトデータ
getStaticProps
を更新して、context.draftMode
に基づいて異なるデータを fetch することができます。
例えば、あなたのヘッドレス 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 route(secret
とslug
付き)にアクセスすれば、ドラフトのコンテンツを見ることができるはずです。そして、公開せずにドラフトを更新すれば、ドラフトを見ることができるはずです。
これをヘッドレス CMS のドラフト URL として設定するか、手動でアクセスすると、ドラフトを見ることができるはずです。
https://<your-site>/api/draft?secret=<token>&slug=<path>
More Details
Clear the Draft Mode cookie
Default では、ドラフトモードのセッションはブラウザが閉じられると終了します。
ドラフトモードの cookie を手動でクリアするには、setDraftMode({ enable: false })
を呼び出す API route を作成します。
export default function handler(req, res) {
res.setDraftMode({ enable: false })
}
それから、/api/disable-draft
に request を送信して API Route を呼び出します。next/link
を使用してこの route を呼び出す場合、prefetch で誤って cookie を削除しないようにprefetch={false}
を渡す必要があります。
getServerSideProps
と連携します
ドラフトモードはgetServerSideProps
と連携して動作し、context
の object にdraftMode
キーとして利用できます。
Good to know: 下書きモードを使用する場合、バイパスできないため
Cache-Control
header を設定しないでください。代わりに、ISRの使用をお勧めします。
API Routes と連携
API Routes は、request object 上のdraftMode
にアクセスできます。例えば:
export default function myApiRoute(req, res) {
if (req.draftMode) {
// get draft data
}
}
Unique per next build
新しいバイパスクッキーの値は、next build
を実行するたびに生成されます。
これにより、バイパスクッキーが推測されることがないようにします。
Good to know: ドラフトモードをローカルで HTTP 上でテストするには、ブラウザがサードパーティのクッキーとローカルストレージアクセスを許可する必要があります。