Next.jsのPreview modeでページのプレビューを表示する

Next.js v9.3でpreview modeが追加されました

CMSっぽいの作ろうと思ってるので、ちょっと試してみました

めちゃシンプルで簡単にPreviewできたのでメモ

ドキュメントは↓ nextjs.org

サンプルコードは↓ github.com

Preview modeのAPIを用意する

ヘッドレスCMDなどからプレビューページを表示するためのエンドポイントを作成します

ぼくのサンプルコードではこんな感じ

// /pages/api/preview.ts

export default (req, res) => {
  const id = req.query.id;

  res.setPreviewData({});
  res.writeHead(307, { Location: `/posts/${id}` });
  res.end();
};

クエリパラメータのidで対象のURLへリダイレクトしているだけです

setPreviewDataには任意のデータを渡せますが、cookieで保持しているのでサイズには上限があります

previewDataのリミットは2KBだそうです

Pagesでpreview mdoeの振る舞いを記述する

Preview modeだとgetStaticPropsのpropsにpreview: truepreviewDataL {}が渡ってきます

ぼくのサンプルコードではpreviewをcomponentに渡してラベルを表示するようにしました

// /pages/posts/[id].tsx

import { useRouter } from 'next/router';

export const getStaticPaths = async () => {
  return {
    paths: [{ params: { id: '1' } }],
    fallback: true,
  };
};

export const getStaticProps = async ({ params, preview }) => {
  const isPreview = preview || false;
  return { props: { id: params.id, previewMode: isPreview } };
};

const Post = ({ id, previewMode }) => {
  const router = useRouter();

  if (router.isFallback) {
    return <div>Loading...</div>;
  }

  return (
    <>
      {previewMode ? 'Preview mode' : ''}
      <h1>{`Page's ID is ${id}`}</h1>
    </>
  );
};

export default Post;

これだけです!

http://localhost:3000/api/preview?id=1にアクセスすると/pages/1にリダイレクトされて、Preview modeのラベルが表示されるはずです

f:id:murajun1978:20200525020216p:plain

Previewモードを解除する

Preview modeを解除するには、cookieをクリアしてあげればOKです

解除用のエンドポイントを作成します

// /pages/api/preview-disable.ts

export default (req, res) => {
  const location = req.headers.referer || '/';

  res.clearPreviewData();
  res.writeHead(307, { Location: location });
  res.end();
};

pageにも解除用のリンクを追加します

// /pages/posts/[id].tsx

import { useRouter } from 'next/router';

export const getStaticPaths = async () => {
  return {
    paths: [{ params: { id: '1' } }],
    fallback: true,
  };
};

export const getStaticProps = async ({ params, preview }) => {
  const isPreview = preview || false;
  return { props: { id: params.id, previewMode: isPreview } };
};

const Post = ({ id, previewMode }) => {
  const router = useRouter();

  if (router.isFallback) {
    return <div>Loading...</div>;
  }

  return (
    <>
      {previewMode ? 'Preview mode' : ''}
      <h1>{`Page's ID is ${id}`}</h1>
      {previewMode ? (
        <a href="/api/preview-disable">Disable preview mode</a>
      ) : null} // リンクを追加
    </>
  );
};

export default Post;

f:id:murajun1978:20200525020707p:plain

このリンクをクリックすると、posts/1にリダイレクトしてPreview modeのラベルやリンクが表示されないはずです

まとめ

すごくシンプルで簡単にPreviewを実装できました

実際の運用では、previewのデータを取得する実装が必要になりますね

公開されているデータを取得するclinetとPreviewのデータを取得するclientを作って、getStaticPropsで切り替えるとかね

Enjoy Next.js ヘ(^o^)ノ