Lang x Lang

︙

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 を行うことができます。

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 する場合、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 として設定するか、手動でアクセスすると、ドラフトを見ることができるはずです。

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