Next.js + microCMS + Vercelの構成でプレビュー機能を実装する方法についてです。
Next.jsのPreview Mode+Vercelでプレビュー機能を実現する
まずはAPI設定→画面プレビューから遷移先URLを設定します。
URLは以下のようにします。
https://www.your-domain.com/api/preview?slug={CONTENT_ID}&draftKey={DRAFT_KEY}
microCMSで記事を書いている際に、画面プレビュー
リンクを押すと、こちらのURLが表示されます。
次にpages→api配下にpreview.tsを作成します。
/* pages/api/preview.ts */
import { NextApiRequest, NextApiResponse } from 'next'
import { client } from 'libs/client'
const preview = async (req: NextApiRequest, res: NextApiResponse) => {
const { draftKey, slug } = req.query
if (typeof draftKey !== 'string' || typeof slug !== 'string') {
res.status(404).end()
return
}
const data = await client.get({
endpoint: 'post',
contentId: slug,
queries: {
draftKey,
},
})
if (!data) {
return res.status(401).json({ message: 'Invalid slug' })
}
res.setPreviewData({
slug: data.id,
draftKey: req.query.draftKey,
});
res.writeHead(307, { Location: `/post/${data.id}` })
res.end('Preview mode enabled')
}
export default preview
preview用のURLに遷移した際に、{CONTENTID}と{DRAFTKEY}を渡して記事詳細URLにリダイレクトさせる、という処理になります。
次に記事詳細ページの編集をします。まずはgetStaticProps関数です。
/* pages/post/[slug].tsx */
export const getStaticProps: GetStaticProps = async (context) => {
const { params, previewData } = context
if (!params?.slug) {
throw new Error('Error: ID not found')
}
/* draftKeyの存在チェック関数 */
type Draft = {
draftKey: string
}
const isDraft = (arg: any): arg is Draft => {
if (!arg?.draftKey) {
return false
}
return typeof arg.draftKey === 'string'
}
const slug = String(params.slug);
/* requestのクエリパラメータを生成*/
const draftKey = isDraft(previewData)
? { draftKey: previewData.draftKey }
: {}
/* draftKeyを付与してリクエストを投げる */
try {
const data = await client.getListDetail<Post>({
endpoint: "post",
contentId: slug,
queries: draftKey
});
return {
props: {
post: data,
...draftKey,
},
};
} catch (e) {
/* 失敗したら404 */
return { notFound: true }
}
};
リダイレクトした際のパラメータからdraftKeyを取得し、存在する場合は付与してリクエストを投げる…ということをやっています。
次にgetStaticPath関数のfallbackをtrue
にします。
export const getStaticPaths: GetStaticPaths = async () => {
...
return { paths, fallback: true };
};
後はhtmlを自身の環境に合わせて編集します。
export default function Article({ post, draftKey }: Props) {
return post ? (
<>
{/* プレビューモードであるという表示 */}
{draftKey && (
<div>
現在プレビューモードで閲覧中です。
</div>
)}
{/* 記事本文 */}
<PostDetailContent post={post} />
</ >
) : (
<div>no content</div>
)
}
開発環境を起動させて以下のURLにアクセスしてみましょう。
http://localhost:3000/api/preview?slug=your-slug&draftKey=your-draft-key
draftKeyは下書き中の記事の左上の方にあります。
記事詳細ページにリダイレクトされることを確認します。
自分の場合、開発環境では表示されたものの、肝心の本番環境で表示されない事象がありました。
Vercelのデプロイログを見てみると、以下のような警告が出ていました。
warn - Statically exporting a Next.js application via `next export` disables API routes.
build時にnext exportするとAPI routeが働かないみたいです。
package.jsonのbuildコマンドがこうなっていたのが原因です。
"build": "next build && next export && next-sitemap --config sitemap.config.js",
next exportを取り除くと正常に動きました。
"build": "next build && next-sitemap --config sitemap.config.js",