ざきの学習帳(旧 zackey推し )

日々の学びを書きます

APIベース・日本語UIで使いやすい microCMS を Gridsome で使う

実家サイトにお知らせ欄を追加。自分を介さず、オーナーや店舗スタッフがお知らせ等を更新できるようにしたい。

上記機能を実現するため、microCMSを導入することを検討している。

この記事では、別リポジトリにて、microCMSをGridsomeへ導入する素振りを行なった際の手順をまとめる。

microCMSとは?


ざっくりした特徴は以下。

  • 日本製のヘッドレスCMS*1
  • 管理画面が日本語
  • APIベースでコンテンツ取得が可能

管理画面が日本語のため、ITリテラシーが高くない方でも操作の抵抗が低くなると考えている。

また、無料プランでも、

  • API2つまで作成可能
  • コンテンツは無制限

と、現個人サイトを運用するくらいなら、問題なく運用できると考えている。*2

手順

以下PR、タグでmicroCMSを導入した際の手順メモを記載する。

概要 URL
タグ GitHub - zakizaki-ri9/javascript-sandbox at micro-cms-sample
ディレクト javascript-sandbox/gridsome-micro-cms-sample
PR Feature/2020/04/19/micro cms sample by zakizaki-ri9 · Pull Request #9 · zakizaki-ri9/javascript-sandbox · GitHub

microCMSからコンテンツを登録

microCMSのアカウントを作成、以下のようなレスポンスを返すようなコンテンツを登録する。

{
    "contents": [
        {
            "id": "hogehoge3",
            "createdAt": "2020-04-19T02:54:51.125Z",
            "updatedAt": "2020-04-19T02:54:51.125Z",
            "datetime": "2020-04-08T15:00:00.000Z",
            "title": "3記事目",
            "content": "<p>3記事目</p>"
        },
        {
            "id": "hogehoge2",
            "createdAt": "2020-04-19T00:50:28.497Z",
            "updatedAt": "2020-04-19T00:50:28.497Z",
            "datetime": "2020-04-07T15:00:00.000Z",
            "title": "つぎの記事",
            "content": "<p>テスト</p>"
        },
        {
            "id": "hogehoge1",
            "createdAt": "2020-04-19T00:49:49.434Z",
            "updatedAt": "2020-04-19T00:49:49.434Z",
            "datetime": "2020-03-31T15:00:00.000Z",
            "title": "最初の記事",
            "content": "<h1 id=\"hlZ8GwDr6gN\">見出し1</h1><h2 id=\"hm17JxGvXjg\">見出し2</h2><h3 id=\"hn2GKy8wJkj\">見出し3</h3><h4 id=\"ho3ALz7xJlk\"><span style=\"background-color:#ffffff\">見出し4</span></h4><h5 id=\"hp49MA7yVml\"><span style=\"background-color:#ffffff\">見出し5</span></h5><p><br></p><pre><code>&lt;p&gt;test&lt;&#x2F;p&gt;</code></pre><p><br></p><ul><li>あいうえお</li><li><strong>かきくけこ</strong></li><li><span style=\"background-color:#e795a0\">さしすせそ</span></li></ul><p><br><a href=\"https://kic-yuuki.hatenablog.com\" target=\"_blank\">zackey推し</a><br><br>画像<br><img src=\"https://images.microcms-assets.io/protected/ap-northeast-1:1d4fc114-673b-41a5-8571-d64f487c3071/service/zakizaki-content/media/zaki.jpg\" alt><br></p><blockquote>これは引用です</blockquote><p><br></p>"
        }
    ],
    "totalCount": 3,
    "offset": 0,
    "limit": 10
}

"id": "hogehoge1"は以下のようなイメージで登録。

f:id:kic-yuuki:20200419172332p:plain

Gridsome側の実装

Gridsomeを用いた実装手順を記載する。

セットアップ

Default starterを使ってセットアップ後、
必要なライブラリをインストールする。

# gridsome-cliのインストールとセットアップ
npm i -g @gridsome/cli
gridsome create gridsome-micro-cms-sample

# 必要なライブラリをインストール
npm i -D axios dayjs

microCMSのAPIからコンテンツ取得

API情報はdotenvで参照するため、以下.envを作成する。

// javascript-sandbox/gridsome-micro-cms-sample/.env
MICROCMS_URL=https://hogehoge.microcms.io/api/v1/hogehoge
MICROCMS_API_KEY=hogehoge

microCMSに登録したコンテンツをAPIから取得する処理を実装。

APIから一度に取得できるコンテンツ数は、デフォルト10件。

APIリファレンスに最大件数の記載がない。念のため、パラメータoffsetを利用したページング(繰り返し取得)処理を実装。

// https://github.com/zakizaki-ri9/javascript-sandbox/blob/ed0429ce65a35bbf8376b44ae07ecbd20384b9b1/gridsome-micro-cms-sample/server/microcms.js#L38-L43
// から抜粋↓
  let { contents, totalCount } = await contentsFetch()
  while (contents.length < totalCount) {
    // 2回目以降の取得
    const data = await contentsFetch(contents.length)
    contents = contents.concat(data.contents)
  }

コレクション追加・ページ生成処理の実装

上記APIを利用し、gridsome.server.jsにコレクション追加・ページ生成処理を実装する。

// https://github.com/zakizaki-ri9/javascript-sandbox/blob/micro-cms-sample/gridsome-micro-cms-sample/gridsome.server.js
const { microCmsContentsAllFetch } = require('./server/microcms.js')

module.exports = (api) => {
  api.loadSource(async (actions) => {
    const contents = await microCmsContentsAllFetch()

    // GraphQLのスキーマ追加
    const collection = actions.addCollection('microCms')
    for (const content of contents) {
      collection.addNode(content)
    }
  })

  api.createPages(async ({ createPage }) => {
    const contents = await microCmsContentsAllFetch()

    // MicroCmsから取得した内容を元にページ生成
    for (const content of contents) {
      createPage({
        path: content.path,
        component: './src/templates/Post.vue',
        context: content
      })
    }
  })
}

コンテンツ一覧ページの実装

コレクション情報を<page-query>で取得、コンテンツ一覧ページ(javascript-sandbox/gridsome-micro-cms-sample/src/pages/Posts.vue)を実装する。

// https://github.com/zakizaki-ri9/javascript-sandbox/blob/micro-cms-sample/gridsome-micro-cms-sample/src/pages/Posts.vue
<template>
  <Layout>
    <h1>Posts</h1>
    <ul>
      <li v-for="edge in $page.posts.edges" :key="edge.node.id">
        <g-link :to="edge.node.path">{{
          `${edge.node.date} - ${edge.node.title}`
        }}</g-link>
      </li>
    </ul>
  </Layout>
</template>

<script>
export default {}
</script>

<page-query>
  query {
    posts: allMicroCms {
      edges {
        node {
          path
          date
          title
        }
      }
    }
  }
</page-query>
</script>

コンテンツ表示ページの実装

gridsome.server.jsでページ生成時に参照する、コンテンツ表示ページ(javascript-sandbox/gridsome-micro-cms-sample/src/templates/Post.vue)を実装する。

// https://github.com/zakizaki-ri9/javascript-sandbox/blob/micro-cms-sample/gridsome-micro-cms-sample/src/templates/Post.vue
<template>
  <Layout>
    <small>投稿日時:{{ $context.date }}</small>
    <h1>{{ $context.title }}</h1>
    <hr />
    <!-- eslint-disable-next-line vue/no-v-html -->
    <div v-html="$context.content"></div>
  </Layout>
</template>

<script>
export default {
  metaInfo() {
    return {
      title: `${this.$context.title}`
    }
  }
}
</script>

動作確認

npm run developを実行。

以下のように、microCMSから取得したコンテンツが表示されたことを確認。

コンテンツ一覧(/posts/)

f:id:kic-yuuki:20200419183927p:plain

コンテンツ「2020-04-01 - 最初の記事」(/post/20200401/)

f:id:kic-yuuki:20200419184047p:plain

所感

microCMSのコンテンツ登録〜Gridsomeへの導入含めて1日以内で行えた。

他のヘッドレスCMSをあまり使ったことがないため、比較はできないが、microCMSは以下の点が使いやすいと感じた。

  • 管理画面が日本語
  • APIリファレンスが見やすく、管理画面で実行結果(JSON)を見ることが可能
  • コンテンツの物理名・論理名指定が可能

webhookを用いた、
microCMSの更新 → GitHubActions実行 → ビルド・デプロイ
も可能な様子のため、次は上記ワークフローを組んでみたいと思う。

*1:日本以外で有名なのは、contentfulstoryblok

*2:2020/04/19時の情報のため、改訂される可能性あり