Next + MicroCMS + Netlify でプレビュー機能を作る

# この記事の目的
* MicroCMSのプレビュー機能が出来るようになること。
* プレビュー機能作成でつまづいたのでメモ

# 前提
* 既にnetlifyに対してデプロイを行なっている
* microCMSとnext.jsの連携も行なっている
* 基本的なページは完成している(react等で実装が終わっている)


# 環境
```package.json
{
  "name": "myProject",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "microcms-js-sdk": "^2.0.0",
    "next": "12.1.5",
    "react": "18.0.0",
    "react-dom": "18.0.0"
  },
  "devDependencies": {
    "@types/node": "17.0.26",
    "@types/react": "18.0.6",
    "@types/react-dom": "18.0.2",
    "eslint": "8.14.0",
    "eslint-config-next": "12.1.5",
    "typescript": "4.6.3"
  }
}

```

# 1. targetをserverlessにする
参考: https://www.netlify.com/blog/2020/10/27/preview-mode-for-next.js-now-fully-supported-on-netlify/
```next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  // ...
  target: 'serverless',
  // ...
}

module.exports = nextConfig

```

# 2. preview用のfunction実装
参考: https://nextjs-ja-translation-docs.vercel.app/docs/advanced-features/preview-mode
```src/pages/api/preview.ts
export default function handler(req: any, res: any) {
  // 後々に記述するが、これらのqueryの名前は自分で決める。contentTypeが今回はページのpathになっている
  // pathが /articles/articleId の構成のサイトなら、 contentType = articles, contentId = articleId となる
  const contentType = req.query?.contentType
  const contentId = req.query?.contentId
  // draftKeyは下書き用のkey。後々出てくる
  const draftKey = req.query?.draftkey
  if (!contentType || !contentId || !draftKey) {
    return res.status(401).json({ message: 'Invalid params' })
  }
  res.setPreviewData({
    contentId,
    draftKey,
  })
  // ここは、ページ設計によるが、next+netlifyで作っていれば大体こうなるはず。
  res.writeHead(302, {
    Location: `/${contentType}/${contentId}`,
  })
  return res.status(200).json({ message: 'success' })
}
```

# 3. page側実装
```src/pages/articles/[id].tsx
import { MicroCMSQueries } from 'microcms-js-sdk'
import { Article, getArticle } from '../../apis/microCms'

type Props = {
  res: Article
}

type Params = {
  id: string
}

type _PreviewData = {
  contentId: string
  draftKey: string
}


const ArticleDiv: NextPage<Props> = ({ res }) => {
  // この辺は本件とは関係ないので省略
  return (<div></div>)
}

export const getStaticPaths: GetStaticPaths<Params> = async () => {
  const queries: MicroCMSQueries = { fields: 'id', limit: 100 }
  const res = await getArticles(queries)
  return {
    paths: res.contents.map((article) => ({ params: { id: article.id } })),
    fallback: false,
  }
}

// contextに、preview.tsで取得したcontentIdとdraftKeyが格納されている
export const getStaticProps: GetStaticProps<Props, Params> = async (context) => {
  const previewData = context.previewData as _PreviewData
  const draftKey =
    String(context.params!.id) === String(previewData?.contentId) ? previewData?.draftKey : ''
  const res = await getArticle(context.params!.id, draftKey)
  return {
    props: {
      res,
    },
  }
}

export default ArticleDiv
```

```src/apis/microCms.ts
import { MicroCMSQueries } from 'microcms-js-sdk'
import { GetListDetailRequest, GetListRequest, MicroCMSListResponse } from 'microcms-js-sdk'

export type Article = {
  id: string
  title: string
}

export async function getArticles(queries?: MicroCMSQueries): Promise<MicroCMSListResponse<Article>> {
  const getListRequest: GetListRequest = {
    endpoint: 'articles',
  }
  if (queries) {
    getListRequest.queries = queries
  }
  const res = await cmsClient.getList(getListRequest)
  return res
}

export async function getArticle(id: string, draftKey?: string): Promise<Article> {
  const detailQueries: GetListDetailRequest = { endpoint: 'articles', contentId: id }
  if (draftKey) {
    detailQueries.queries = { draftKey }
  }
  const res = await cmsClient.getListDetail(detailQueries)
  return res
}
```

ここまで終わったら、netlifyにデプロイする

# 4. microCMSで設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153964/267a7e78-46dc-c0f3-a27f-a007e6a33547.png)

API設定画面より、
microCMSに従って、myprojectやcontentType部分を自分のプロジェクトに置き換えれば完了


# 5. プレビュー実行
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153964/722f69ce-cc59-7b2c-238f-073f89f038b9.png)

記事ページが下書き状態で、画面プレビューボタンを押せば画面が見られる

# おわりに

next.config.js 部分はもう少し知見が欲しいので、詳しい方いたらコメントお願いします