microCMSでJAMstackなブログを作った話

5 min read読了の目安(約5200字

microCMSのロゴ

一足遅れですがJAMstackというアーキテクチャが流行っていると聞いて調べてみて、学習欲が湧いてきたのでアウトプット場所も兼ねてJAMstackでブログを作ってみたお話しです。

技術スタックは下記です。

  • microCMS (ヘッドレスCMS)
  • Vercel (ホスティングサービス)
  • Next.js
  • Typescript

JAMstackとは

ホスティングサービスのNetlifyの人が提唱した Javascript, APIs, Markup の頭文字を取って名付けたアーキテクチャとのことです。

ザックリ説明するとクライアントはSSGで作った静的コンテンツをホスティングして、更にAPIを使って動的なアプリケーションを作るのがJAMstackらしいです。
特にNext.jsやGatsbyなどのSSGが可能なフレームワークとNetlifyCMSなどヘッドレスCMSとしてAPIだけを提供するようなサービスとを組み合わせたアーキテクチャを指しているようです。

microCMSを選んだ背景

ヘッドレスCMSの種類もいくつかあるようですが、簡単な受託案件などで利用できる非技術者でも触れるようなサービスを探していたところ、「microCMS」という和製で管理画面もみやすいサービスを見つけたので使ってみました。

APIを変更するユーザ用の画面を提供していて、APIのスキーマをユーザが自由に構築できてAPIの変更をフックにgithubからホスティングサービスにデプロイが行われる仕組みになっています。
スキーマさえ構築しておけば非技術者でも簡単に編集できるので、汎用設定的なスキーマを作ってサイト名やよく変わる文章なども編集してもらうことが可能になります。
(感動ポイントでした)

microCMSの管理画面

和製サービスなので、日本語で見やすくて日本の企業がカスタマーサポートしてくれるのもよさそうですね。

NetlifyCMSも使ってみましたが、下記のような仕組みになっていて便利ではありましたが、非技術者に扱ってもらえるようにカスタマイズするにはドキュメントが少なくて学習コストも高そうでした。

NetlifyにホスティングされたSSGの管理画面を動かして記事を入力・保存すると、githubなどのリポジトリにmarkdownとhtmlに変換された静的ファイルとして保存されて、その後Netlifyにデプロイされる

なお、導入の簡単さはフレームワークも選べてワンクリックなのでピカイチでした↓

参考記事

dev.classmethod.jp/articles/try-netlify-cms

導入方法について

microCMSの公式ブログでmicroCMS x Next.js x Vercelを利用したブログの作成方法について紹介されています。

blog.microcms.io/microcms-next-jamstack-blog

下記がハマりポイントでした。

  1. microCMSの入稿データ(リッチエディタ形式)がどのような工程を経てブログに表示されるのか
  2. Next.jsでSSGする仕組み
  3. シンタックスハイライトする仕組み

1. microCMSの入稿データ(リッチエディタ形式)がどのような工程を経てブログに表示されるのか

下記の流れです。

  • 文章や汎用設定などの動的データを取得できるAPIをmicroCMSで作成
  • WebフックでVercel上のSSG(Next.jsなどのFW)がmicroCMSのAPIから取得したデータをHTMLに変換した静的ページを作成
  • Vercelにデプロイ

「APIから動的データを取得して、SSGによって静的コンテンツを作る」という仕組みがとても画期的で、あまり馴染みがないアーキテクチャになります。

microCMSの管理画面からAPIのスキーマを編集する際、スキーマのフィールドにはデータ型を選択することができます。
「リッチエディタ」というデータ型を選ぶと、APIのレコードを作成する画面で該当のフィールドにリッチエディタが表示されて、リッチエディタで入力した文章がHTMLに変換されてレコードに保存されます。
(スキーマレスっぽいですがレコード・フィールドと勝手に呼びます)

注意点としては、2021/02/20時点ではリッチエディタに表やコードハイライトなど対応していない機能がある点です。
また、マークダウンにも完全に対応していないため最終的にはテキストエリア型など自由入力できる形式にして、レコードにHTMLではない生の文章データを作る形にしました。

つまり、リッチエディタ型で保存すればHTMLデータをそのまま加工せずに利用できますが、大抵のユースケースでは生の文章データとして保存してSSG側でHTMLに加工したデータでコンテンツを作るという流れになります。

なお、microCMSのリッチエディタにはコンテンツのスタイルを適用することができないため、正確なプレビューは結局別な手段を利用することになります。

SSGフレームワークでプレビュー用のAPI (function) を作り、ホスティング先のプレビュー用APIをmicroCMS上から叩いてドラフト版のデータをAPIがmicroCMSから取得して表示する..という少し複雑な手段で実現ができます。

公式ブログではNuxt.js版のプレビュー実装方法が紹介されています。

blog.microcms.io/nuxt-jamstack-preview

2. Next.jsでSSGする仕組み

Next.jsやNuxt.jsはルーティングにファイルシステムを利用しています。
対応関係は下記のような感じになります。

URL ディレクトリ
/ (root) pages/index.tsx
/about pages/about/index.tsx
/posts/1 pages/posts/[slug].tsx

ここで index.tsx にあたる単一ページは単純にmicroCMSから取得したデータを流し込んだHTMLファイルを作るんだなと想像に容易いですが [slug].tsx にあたる動的ページをHTMLファイルにする仕組みは直感的ではありません。

Next.jsでSSGを行う場合はpages/配下のコンポーネントに getStaticPropsgetStaticPaths という2つの関数を定義してexportします。

const MultiPagesComponent = (props) => {
  ...
}
export default MultiPagesComponent;

export const getStaticProps = async (context) => {
  const { slug } = context.params;
  ...
  const data = await fetch(`${apiUrl}/${slug}`).then(res => res.json());
  const { title, body } = data;
  return {
    props: {
      title,
      body
    }
  }
};

export const getStaticPaths = async () => {
  const data = await fetch(apiUrl).then(res => res.json());
  const paths = data.contents.map((post) => `/posts/${post.slug}`);

  return { paths, fallback: false };
};

getStaticProps はコンポーネントに与えるpropsを作る関数で、microCMSのAPIから取得したデータを加工して、コンポーネントに渡しています。
context 引数にはURLのパラメータなどを受け取ることができ、ここでは posts/slug としてアクセスがあった場合に slug 部分のパラメータをデータ特定のために利用しています。

getStaticPaths はこのコンポーネントがアクセスされうるURLを作る関数です。
ここではmicroCMSのAPIから記事一覧を取得して、記事の数だけ posts/slug というページを作成しています。

なお、プレビューの際はAPIのリクエストヘッダーに下書きステータスの記事データも取得できるようにする権限のキーを追加することによって、下書きステータスの記事データを取得しています。

3. シンタックスハイライトする仕組み

前述した通り、microCMSのリッチエディタではシンタックスハイライト機能などがサポートされていないため、SSG上でデータを加工する必要があります。
ここまでくるとjekyllやhugoなど従来のローカルで完結していたSSGのFWと同じ仕組みになります。

公式ブログでは cheerio, highlight.js を利用したシンタックスハイライトの付与方法を紹介しています。

blog.microcms.io/syntax-highlighting-on-server-side

記事で紹介されている方法はリッチエディタで入力されたHTMLデータを加工することを前提に紹介されていますが、マークダウンなどの生文章をテキストエリア型で入稿している場合は、「HTMLに変換->シンタックスハイライト付与」という流れになります。

cheerioでHTML文章の中から <pre><code>ここにコード</code></pre> にマッチする要素を見つけてきて、highlight.jsで下記のような感じに変換してくれます。

<pre><code class="language-python hljs">
  def hoge()
  <span class="hljs-keyword">return</span>
  <span class="hljs-symbol">"hoge"</span>
</code></pre>

自分が好きな配色を選んで、cssを読み込めばhighlight.jsで付与されたクラスなどにスタイルがつくという仕組みです。

最後に

このブログはpublicリポジトリにしているので、下記から確認することができます。

github.com/tkc310/microCMS_blog

この記事で紹介した内容以外にも、このブログではMarkdown文書内でJSXが書ける MDX などを導入していたりするので、コードを見ていただければと思います。

デザインもパクっていただいていいので、ご自由にお使いください〜