Lang x Lang

Draft Mode

Pages ドキュメントData Fetching ドキュメントで、getStaticPropsgetStaticPaths を使って、ページを 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 を行うことができます。

pages/api/draft.ts
// 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 に位置していることを前提としています。

Terminal
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 する場合、getStaticPropsrequest timeで呼び出されます(build time の代わりに)。

さらに、context object として呼び出され、context.draftModetrueになります。

export async function getStaticProps(context) {
  if (context.draftMode) {
    // dynamic data
  }
}

私たちはドラフトの API route でres.setDraftModeを使用したので、context.draftModetrueになります。

あなたが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(secretslug付き)にアクセスすれば、ドラフトのコンテンツを見ることができるはずです。そして、公開せずにドラフトを更新すれば、ドラフトを見ることができるはずです。

これをヘッドレス CMS のドラフト URL として設定するか、手動でアクセスすると、ドラフトを見ることができるはずです。

Terminal
https://<your-site>/api/draft?secret=<token>&slug=<path>

More Details

Default では、ドラフトモードのセッションはブラウザが閉じられると終了します。

ドラフトモードの cookie を手動でクリアするには、setDraftMode({ enable: false })を呼び出す API route を作成します。

pages/api/disable-draft.ts
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 上でテストするには、ブラウザがサードパーティのクッキーとローカルストレージアクセスを許可する必要があります。

当社サイトでは、Cookie を使用しています。各規約をご確認の上ご利用ください:
Cookie Policy, Privacy Policy および Terms of Use