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

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

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

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

clientの初期化

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

記事取得用の関数

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

5. 記事を表示

記事一覧

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

記事詳細

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

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

📎Social Share