microCMS SDK と Next.js で Vercel を使ったプレビューを実装したメモ

microCMSにはSDKが用意されており、さまざまなプラットフォームで GET API を手軽に扱えるようになっています。今日は microCMS JavaScript SDKを使い、ブログ記事のプレビュー機能を実装してみました。

実装にあたっては、下記の2つの記事がとても参考になりました。

とても詳しく丁寧に解説されているので、まず、上記2つの記事をご覧いただくことを強くお勧めします読んだ前提で書きます。
上記の記事の方法を用いればパーフェクトなのですが、これらの記事中ではSDKを使わない方法が紹介されているので、この記事ではSDKを使う場合の書き方を忘備録として残しておきます。

※すでに記事の公開機能は実装されており、プレビュー機能を追加で実装することを目的とした記事です

目次

プレビュー用の関数を作る

プレビュー用の関数を作成します。他のページ用のプレビューも後日作るかも、ということで名称はblogPreviewにしています。
/pages/api/blogPreview.jsx

import { client } from "@pages/api/microcms";
	

	export default async (req, res) => {
	  
	  // リクエストにスラッグがない場合は404エラーを表示
	  if (!req.query.slug) {
	    return res.status(404).end();
	  }
	  
	  // 記事が存在するか確かめる
	  const content = await client.get({
	    endpoint: 'blog',
	    contentId: req.query.slug,
	    queries: {draftKey: req.query.draftKey}
	  }).then().catch(error => console.error(error));
	  
	  // 記事が返ってこない場合は401エラーを表示する
	  if (!content) {
	    return res.status(401).json({ message: 'Invalid slug' });
	  }
	  
	  // 記事のIDとdraftKeyを渡して本来のパスにリダイレクトする
	  res.setPreviewData({
	    slug: content["id"],
	    draftKey: req.query.draftKey,
	  });
	  res.writeHead(307, { Location: `/blog/${content["id"]}` });
	  res.end('Preview mode enabled');
	};

記事ページにdraftKey処理を追加する

プレビュー用の関数からdraftKeyを渡されたときに、それをAPIに渡します。
通常の記事の取得コードにqueries: { draftKey: '●●●' }を加えれば、下書き状態の記事を取得できるようになります。

/pages/blog/[id].tsx(記事取得部分の抜粋)

export const getStaticProps = async (context) => {
	

	  // 記事IDを取得する
	  const slug = context.params.id;
	  
	  // draftKeyを取得し、クエリを作成する
	  const draftKey = context.previewData?.draftKey
	    ? { draftKey: context.previewData.draftKey }
	    : {};
	

	  // 記事を取得する
	  const blogPost = await client.get({
	    endpoint: 'blog',
	    contentId: slug,
	    queries: draftKey,
	  })
	

	  // 記事が存在しなければ404エラーを返す
	  if (!blogPost) {
	    return { notFound: true }
	  }
	

	  // 記事とdraftKeyをpropsに渡す
	  return {
	    props: {
	      blogPost,
	      ...draftKey
	    },
	  }
	}

プレビュー有効表示を追加する

今のままでは、果たしてプレビュー表示なのか本番表示なのかの区別がブラウザ画面上でつきませんので、プレビューが有効な場合の表示を追加します。あわせて、プレビュー機能をオフにするためのリンクも作成します。

/src/components/Pages/Post/Id/Component.tsx(抜粋)

export const Component: VFC<Props> = (props) => {
	  return (
	    <>
	      {props.draftKey && (
	        <p className={'bg-yellow-100 text-yellow-900 p-4 text-center'}>
	          プレビュー表示がONになっています。
	          <Link href={`/api/exitPreview`}>
	            <a className={"underline"}>プレビュー表示をOFFにする</a>
	          </Link>
	        </p>
	      )}
	      {/* 以下に記事内容を表示するコンポーネントが続く */}
	    </>
	  );
	};

※装飾としてTailwindのクラス名が入っています

プレビューオフ用の関数を用意する

プレビューをオフにするための関数を用意します。オフにした後はトップページにリダイレクトする仕様です。
/pages/api/exitPreview.tsx

export default (_req, res) => {
	  res.clearPreviewData();
	  res.writeHead(307, { Location: `/` });
	  res.end('Preview mode disabled');
	}

microCMS上でプレビューリンクを設定する

microCMSにログインし、[API設定]→[画面プレビュー]から、画面プレビュー用のURLを設定します。
https://あなたのドメイン/api/blogPreview?slug={CONTENT_ID}&draftKey={DRAFT_KEY}

これで、Vercel上で画面プレビューができるようになりました!
記事を下書き保存して、画面プレビューボタンを押してから約5秒でプレビューが表示されました。

プレビューであることが明記された記事ページが表示されている

余談

SDKのreadmeにグローバルドラフトキーの記載があり、記事ごとのdraftKeyの扱い方について記載がなかったことから「SDK使う時はグローバルドラフトキーしか使えないのかな??」と、私は大きな勘違いをしていました🥲しばらくハマってました。そんなワケがないのに。考えなくてもわかりそうなことを、なぜ…。
ドラフトキーはクエリにつけてあげる、これでOKです。
PHP版のプレビュー機能を作った時にもクエリパラメータとしてつけてたはずなのに、なぜこんな勘違いをしてしまったのか…)

余談すぎる余談

「Post/Id/Component.tsx」はもともと「Blog/Id/Component.tsx」だったのですが、なぜかVercel上にデプロイすると「そんなディレクトリはない」と言われるので、BlogからPostにディレクトリ名を変更したのでした。ローカルではBlogのままでも動くのに…謎…。

  1. 雑記
  2. microCMS SDK と Next.js で Vercel を使ったプレビューを実装したメモ