Next.js x microCMS で作る Jamstack なブログサイト

つい最近まではWordPressがCMSの覇権を圧倒的に握っていた感じはありましたが、最近はいろんな手法があって勉強になります。

当サイトのAnyushu BlogmicroCMSを使用しフロントはNext.jsで制作しているJamstackなブログです。

このサイトのGitHubリポジトリ

Jamstackってなに?

JavaScript、API、Markup(静的サイトジェネレータで生成)の略です。

なので事前に投稿情報をAPIで取得し静的なHTMLを生成(SG)するので、特徴としてはサーバーサイドの処理が基本的に発生しないのでとても高速になります。

なぜNext.jsにしたのか

とても個人的な理由です。

前提としてReactについて少し経験があったので、Next.jsとGatsby.jsの2択でした。

あとインフラの知見が乏しいのでVercelに任せる。なので「恩恵を最大限に受けるのはNext.jsかな?」といった感じです。

使用した技術

  • Next.js
    • TypeScript
    • Tailwind CSS
  • microCMS
    • microcms-js-sdk
  • Vercel

Next.js x microCMS で作る Jamstack なブログサイト

手順を大まかに書いていきます。

1. 事前準備

  1. microCMSの登録(マニュアル
  2. Next.jsプロジェクトの作成(自作のボイラープレートではじめました)

2. microCMSのAPIスキーマ設定

当サイトの場合ですが、内容は下記のようになっています。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 { "apiFields": [ { "fieldId": "title", "name": "タイトル", "kind": "text", "required": true, "isUnique": false }, { "fieldId": "thumbnail", "name": "アイキャッチ", "kind": "text", "isUnique": false }, { "fieldId": "category", "name": "カテゴリー", "kind": "select", "required": true, "selectItems": [ { "value": "others" }, { "value": "tech" }, { "value": "idea" }, { "value": "column" } ], "multipleSelect": false }, { "fieldId": "content", "name": "投稿内容", "kind": "richEditor", "required": true }, { "fieldId": "metaRobots", "name": "noindex", "kind": "boolean", "description": "チェックすると`noindex`にります" }, { "fieldId": "metaDescription", "name": "ディスクリプション", "kind": "textArea" } ] }

3. 必要なパッケージのインストール

  • microcms-js-sdk:microCMSのSDK(ドキュメント
  • microcms-typescript:APIスキーマから型生成(参考サイト:Zenn記事
1 2 yarn add microcms-js-sdk yarn add -D microcms-typescript

4. microcms-js-sdkを使い記事の取得まで

clientの初期化

1 2 3 4 5 6 import { createClient } from 'microcms-js-sdk' export const microcmsClient = createClient({   serviceDomain: process.env.MICRO_CMS_SERVICE_DOMAIN || '',   apiKey: process.env.MICRO_CMS_API_KEY || '', })

記事取得用の関数

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 import type { MicroCMSListResponse, MicroCMSQueries } from 'microcms-js-sdk' import { microcmsClient } from 'libs/microcms/api-client' import type { blog } from 'types/cms-types' export const END_POINT = 'blog' /** * ブログ一覧の取得 */ export const getBlogList = (limit?: number, offset?: number, keyword?: string) => { const queries: MicroCMSQueries = { limit: limit, offset: offset, q: keyword, orders: '-publishedAt', } return microcmsClient.getList<blog>({ endpoint: END_POINT, queries: queries, }) } /** * ブログ詳細の取得 */ export const getBlog = (slug: string) => { return microcmsClient.get<blog>({ endpoint: END_POINT, contentId: slug, }) }

5. 記事を表示

記事一覧

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import type { InferGetStaticPropsType, NextPage } from 'next' import { getBlogList } from 'libs/microcms/get-blog' type IndexProps = InferGetStaticPropsType<typeof getStaticProps> const BlogIndex: NextPage<IndexProps> = ({ blogs }) => {   return (     <>      {/* 記事一覧表示 */}     </>   ) } export default BlogIndex export const getStaticProps = async () => {   const data = await getBlogList(12)   return {     props: {       blogs: data,     },   } }

記事詳細

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 import type { GetStaticPropsContext, InferGetStaticPropsType, NextPage } from 'next' import { getBlogList, getBlog } from 'libs/microcms/get-blog' type BlogPostProps = InferGetStaticPropsType<typeof getStaticProps> const BlogPost: NextPage<BlogPostProps> = ({ blog }) => {   return (     <>      {/* 記事詳細表示 */}     </>   ) } export default BlogPost export const getStaticPaths = async () => {   const allPage = await getBlogList(9999)   const paths = allPage.contents.map((blog) => ({     params: {       slug: blog.id,     },   }))   return { paths, fallback: false } } export const getStaticProps = async ({ params }: GetStaticPropsContext<{ slug: string }>) => {   const data = await getBlog(params?.slug || '')   return {     props: {       blog: data,     },   } }

参考にさせていただいたサイト

📎Social Share