ブログをmicroCMSに移行したときの話

投稿日 2023-05-28
最終更新日 2023-11-18

一週間ほど前にブログをmicroCMSに移行したので、その時のことを書こうと思います。

microCMSって?

microCMSは一言で言えば、「ヘッドレスCMS」のうちの一つになります。

では、そもそもヘッドレスCMSとは何かということから説明していきます。
まず、CMS(Content Management System)は名前の通り、Webサイトのコンテンツを管理するためのシステムのことです。個人ブログの場合、Webサイトに使用する、ブログ本文、画像、ヘッダータグなどを一括で管理し、公開まで行います。WordPressが代表的な例です。
全てを管理するため、フロントエンド部分もこのシステム内で構築します。
一方で、ヘッドレスCMSはCMSのうちのバックエンド部分のみをAPIとして返すシステムのことです。このため、フロントエンドを好きなフレームワークで自前で構築でき、拡張性に優れています。また、データ取得がビルド時の一回だけで良いStatic Generationと非常に相性がいいです。

microCMSは、日本製のヘッドレスCMSであり、公式ドキュメントやチュートリアルが充実していることが特徴です。また、個人ブログ程度であれば無料プランでも十分に動作することがメリットです。

ちなみに、海外ではContentfulというヘッドレスCMSが有名らしいです。


なぜ移行しようと思ったか

これまでは、マークダウンファイルをNext.jsプロジェクトの所定のフォルダに格納して、それを読み込むスタイルで実施していました。(Next.jsのチュートリアルと同じやり方です。)
実際には以下のフォルダ構成になっていました。(かなり抽象化してあります。)

.
├── components
│   ├── (Reactコンポーネント一式)
├── lib
│   ├── (TypeScriptでの処理一式)
├── pages
│   ├── (Next.js関連のコード一式)
├── posts
│   ├── (ブログ記事1)
│   ├── (ブログ記事2)
├── public
│   ├── blog_images
│   │   ├── (ブログで使う画像1)
│   │   └── (ブログで使う画像2)
│   ├── favicons
│   └── images
├── styles
├── types
(以下略)

Next.jsプロジェクトのposts にブログ記事一式を、public/blog_images にブログで使用する画像を格納していました。
これでも問題なく動作はしていましたが、いくつか執筆で面倒なことがありました。

ヘッダーの管理が面倒

マークダウンファイルのヘッダーとして、以下のような記述を毎回する必要がありました。

---
title: "タイトル"
date: "202x-xx-xx"
latestUpdate : "202x-xx-xx"
tags : ["タグ1", "タグ2", "タグ3"]
---


この記述を毎回する必要があるのが少々面倒でした。途中から、以前の記事からコピペするようになりましたが日付などの変更を忘れてしまうことがよくありました。また、タグに関しても、以前つけたタグと同義語の別の言葉を付与していないかを確認する作業が必要で、面倒でした。

画像ファイルの扱いが面倒

上記の通り、ブログの画像は、/public/blog_image に格納するルールになっていましたため、毎回必要な画像をこのディレクトリに保存し、マークダウンファイル内でそのリンクを明示してやる必要がありました。これが結構時間がかかっていました。
さらに、Next.jsでは、/public フォルダ内で指定したファイルは省略形で記載することができます。

![画像1](/blog_images/画像1.png) 


便利な機能なのですが、これによってVSCodeのマークダウンプレビュー機能で画像が正しく読み込まれなかったため、事前チェックが面倒でした。

移行してよかったこと

ここからは実際に移行してよかったことについて書いていきます。

画像ファイルの貼り付けが面倒でなくなった

画像ファイルの貼り付けで様々な問題が発生したことは先ほども述べた通りですが、microCMSを使用することで、この部分が改善されました。
microCMSではリッチエディタ上に、そのまま画像をコピペすることができます。実際にはコピペした時点で、microCMS独自のストレージに格納されているようです。このため、画像を利用する手間が減りました。

ソースコードがシンプルになった

これまでは、ブログ記事のidと本文を取得するのに以下のように書いていました。

import fs from "fs";
import matter from "gray-matter";
import remark from "remark";
import html from "remark-html";

const fullPath = path.join(postsDirectory, `${id}.md`);
const fileContent = fs.readFileSync(fullPath, "utf8");
const matterResult = matter(fileContent);	
const blogContent = await remark().use(html).process(matterResult.content);
const blogContentHTML = blogContent.toString();

return {
    id,
    blogContentHTML,
    ...matterResult.data,
};


具体的な処理の流れは以下になります。

  1. ファイル名から「.md」を取り除いたものをidとする。
  2. マークダウンファイルを読み込み、gray-matterでタイトル・投稿日・更新日・本文を取得する。
  3. remarkで本文をHTML化する。
  4. id、HTML化された本文、その他の内部データ(タイトル・投稿日・更新日)をオブジェクト化して返す。


一方でこれをmicroCMSに変換すると以下のようになりました。

const data = await client.get({ endpoint: "xxx" });
const blogData = data.contents.filter(
    (content: PostData) => content.blogId === id)[0];
return {
    ...blogData
};


具体的な処理の流れは以下になります。

  1. 特定のエンドポイントのデータを取得する。
  2. データからidが特定のものであるデータを取得する。
  3. そのデータ一式をオブジェクトに再展開して返す。


microCMSでidの情報まで管理できるため、returnするものがシンプルになっています。
また、リッチエディタがAPI呼び出し時にHTMLとして返してくれるので、こちら側での変換処理をしなくてもいいようになっています。
そのおかげで、かなりシンプルになったと思います。

移行で苦労したこと

このブログを移行する際にいくつか工夫する必要があったところを共有します。

タグ一覧をフィールドとして与える方法

microCMS上でリスト型の文字列を指定する方法がなく、タグの指定方法で戸惑いました。
実際には、公式ドキュメントに明記されていました。
リンク : https://help.microcms.io/ja/knowledge/categories-and-tabs
タグ専用のコンテンツを作成し、「コンテンツ参照」フィールドを利用して呼び出せば良いようです。

移行前の記事の投稿日を表示する方法

記事更新日、公開日等の基本情報はmicroCMS上で内部フィールド値として与えられているため、こちら側で明示的に指定する必要はありません。一方でこれまで書いた記事を移行すると、投稿日が移行を実施した日になってしまいます。
そのため、以下のように「移行前記事の投稿日」というフィールドを作成し、空文字でない場合はここから投稿日を取得する処理を追記しました。


投稿日を処理するコード

export const selectDate = (content: PostData) => {
  // 「移行前記事の投稿日」フィールドが空でなかったら
  if (
    content.previousPostDate === undefined ||
    content.previousPostDate.trim() === ""
  ) {
    // 内部フィールドの値を返す。
    return dayjs(content.publishedAt).format("YYYY-MM-DD");
  } else {
    // そうでない場合、「移行前記事の投稿日」フィールドを返す。
    return content.previousPostDate;
  }
};


もう少しスマートな方法があれば教えてください。

(6/10修正)
内部タグのpublishedAtは編集可能でした。


上記の箇所から変更可能なので、上のような煩わしいやり方は不要でした。

デフォルトの状態では11個目の記事が消えてしまう。

ちょうどこのブログが10記事目の時に移行しましたが、その次の投稿時に最初の記事が消えてしまう問題が発生しました。
これは、microCMSのAPIで取得件数のデフォルト値が10であることが原因でした。
参考 : https://document.microcms.io/content-api/get-list-contents
このため、応急処置として、この値を20としました。

const clientInfo = { endpoint: "xxxx", queries: { limit: 20 } };
const data = await client.get(clientInfo);


ただし、ここを増やすと、記事が増えるたびにビルド時の時間が長くなってしまうということになるため、いずれ根本的な修正が必要かと思います。
その方法として、ページング機能の追加を検討しています。
幸いにもNext.jsでページング機能を追加する公式チュートリアルが用意されているため、こちらを見ながらやっていこうと思います。
参考 : Next.js(SSG)でページネーションを実装してみよう

なお、これらはあくまで移行作業時のことであり、執筆中に苦労したことは今のところないです。

今回は以上になります。
実は、移行中にmicroCMSの新しいリッチエディタが正式版になっていました。
今回は昔のリッチエディタで実装してしまいましたが、機会があれば移行したいと思っています。