microCMS

microCMS + Next.jsでJamstackブログを作ってみよう

かみむら

microCMSとNext.jsを組み合わせて、Jamstackなブログを作成することができるチュートリアルです。

前提

利用サービス

本記事では以下の2つのウェブサービスを利用します。どちらのサービスも個人開発においては無料の範囲で十分な機能を備えており、実績豊富なサービスです。最初にそれぞれのサイトトップより登録を済ませておきましょう。

  • microCMS:特に日本市場において広く利用されているヘッドレスCMSです。ブログのコンテンツ管理を担います。
  • Vercel:フロントエンド開発向けのプラットフォームです。サイト公開におけるインフラやCI/CDを担います。


ソフトウェアバージョン

下記のバージョンで開発を行なっています。バージョンの差異によって若干機能が異なる可能性があります。

  • Next 13.1.1
  • react 18.2.0
  • react-dom 18.2.0
  • microcms-js-sdk 2.3.2

1. Next.jsプロジェクトを用意する

まずは、Next.jsのプロジェクトを作成していきます。プロジェクトの雛形を作成するCLIがあるので、コマンドを入力して作成していきましょう。

$ npx create-next-app microcms-next-jamstack-blog

※ create-next-appでプロジェクトを作成した場合、カナリアリリースのバージョンがインストールされるため、上記バージョンと異なる可能性があります。ご注意ください。

そして、作成したプロジェクトに移動して開発サーバーを立ち上げます。

$ cd microcms-next-jamstack-blog
$ npm run dev

localhost:3000にアクセスすると下記の画像のように、アプリケーションが立ち上がります。

2. microCMSを用意する

次に、microCMSでAPIを作成していきます。登録〜APIの作成に関してご不明点があればmicroCMSのドキュメントを参照してください。

それではブログ用のAPIを作成していきます。API作成画面から自分で決めるをクリックしましょう。API名にブログ、エンドポイントにblogを入力してください。そして、次へをクリックしてください。

そして、リスト形式を選択します。次へをクリックしてください。


タイトルと本文のフィールドを用意します。APIスキーマは以下の通りです。最後に完了をクリックして作成を終えましょう。

コンテンツの作成

適当に内容を入力し、公開します。
コンテンツ一覧画面に戻り、画面右上のAPIプレビューをクリックします。
取得ボタンをクリックし、入力内容がAPI経由で取得できるか確認してください(レスポンスJSONが表示されます)。

3. APIキーをenvファイルで保護

microCMSではリクエストにAPIキーを含める事で特定のデータを取得できます。
このAPIキーは、GitHubのパブリックで公開されてしまうのはセキュリティー面でよくありません。
なので、envファイルなどで保護してあげましょう。
.env.development.localファイルを作成します。.localをつけるとローカル環境で使うことができます。
また、.developmentをつけると開発環境で使えます。

API_KEY=xxxxxxxxxxxx

プロジェクト内でAPIキーを参照することができます。

process.env.API_KEY

Next.jsのenvファイルの取り扱いはドキュメントを参照してください。
https://nextjs.org/docs/basic-features/environment-variables

4.microcms-js-sdkの準備

公式で提供しているmicrocms-js-sdkをインストールしましょう。microcms-js-sdkはオープンソースで公開されています。
https://github.com/microcmsio/microcms-js-sdk

$ npm install --save microcms-js-sdk

そして、libsフォルダ -> client.jsを作成してSDKの初期化を行います。service-domain api-Keyを設定してください。serviceDomainXXXX.microcms.ioの場合、XXXXの部分になります。apiKeyは環境変数を参照してください。

// libs/client.js
import { createClient } from 'microcms-js-sdk';

export const client = createClient({
  serviceDomain: 'service-domain',
  apiKey: process.env.API_KEY,
});

5. ブログの一覧を表示する

それでは、実際にmicroCMSのデータを取得したページを作成してみましょう。
Next.jsでは、pages/以下に作成したファイルに基づいて自動的にルーティングされる仕組みになっています。

  • pages/index.js → 記事一覧
  • pages/about.js → Aboutページ


pages/index.jsの内容を変更してみましょう。

// pages/index.js
import Link from "next/link";
import { client } from "../libs/client";

export default function Home({ blog }) {
  return (
    <div>
      <ul>
        {blog.map((blog) => (
          <li key={blog.id}>
            <Link href={`/blog/${blog.id}`}>{blog.title}</Link>
          </li>
        ))}
      </ul>
    </div>
  );
}

// データをテンプレートに受け渡す部分の処理を記述します
export const getStaticProps = async () => {
  const data = await client.get({ endpoint: "blog" });

  return {
    props: {
      blog: data.contents,
    },
  };
};

ここで注目してもらいたいのは、getStaticPropsを使ってmicroCMSのデータを取得しているところです。
これは、ビルド時にサーバー側で呼ばれる関数です。この部分の処理は最終的にバンドルJSに含まれません。
ビルド時にデータを取得し、静的なHTMLを出力するために必要です。

また、デフォルトではstyles/globals.cssにてグローバルCSSに背景グラデーションが効いてしまっているので、該当箇所をコメントアウトしておきましょう。

:root {
  --max-width: 1100px;
  --border-radius: 12px;
  --font-mono: ui-monospace, Menlo, Monaco, 'Cascadia Mono', 'Segoe UI Mono',
    'Roboto Mono', 'Oxygen Mono', 'Ubuntu Monospace', 'Source Code Pro',
    'Fira Mono', 'Droid Sans Mono', 'Courier New', monospace;

  --foreground-rgb: 0, 0, 0;
  /* --background-start-rgb: 214, 219, 220;
  --background-end-rgb: 255, 255, 255; */

/* 以下略 */

それでは、再度アプリケーションを立ち上げてみましょう。microCMSのコンテンツがリスト形式で表示できています。

もしエラーが表示される場合は再度npm run devで起動し直してみましょう。

6. ブログの詳細を表示する

次に、ブログ記事の詳細画面を作っていきます。
記事の詳細画面のような動的なページは、ファイル名に[] (ブラケット)をつけます。

  • pages/blog/[id].js → 記事の詳細


それでは、pages/ディレクトリ内にblog/ディレクトリを作成して、その中に [id].jsを作成します。

// pages/blog/[id].js
import { client } from "../../libs/client";

export default function BlogId({ blog }) {
  return (
    <main>
      <h1>{blog.title}</h1>
      <p>{blog.publishedAt}</p>
      <div
        dangerouslySetInnerHTML={{
          __html: `${blog.body}`,
        }}
      />
    </main>
  );
}

// 静的生成のためのパスを指定します
export const getStaticPaths = async () => {
  const data = await client.get({ endpoint: "blog" });

  const paths = data.contents.map((content) => `/blog/${content.id}`);
  return { paths, fallback: false };
};

// データをテンプレートに受け渡す部分の処理を記述します
export const getStaticProps = async (context) => {
  const id = context.params.id;
  const data = await client.get({ endpoint: "blog", contentId: id });

  return {
    props: {
      blog: data,
    },
  };
};

dangerouslySetInnerHTMLはXSSを引き起こす可能性があるため非推奨とされています。
今回の構成においては、入力はmicroCMSのリッチエディタからのみであり、ユーザーからの自由入力箇所ではないため安全であるとして利用しています。

ここではgetStaticPathsという関数を確認します。
Next.js側ではブログのidを知り得ないため、事前に生成するべきHTMLのパスが分かりません。
そこでこの関数内でデータを取得し、パスを定義してあげる必要があります。
ここでのパスはmicroCMSのコンテンツIDです。

またfallbackをfalseにしています。これで、getStaticPathsで返されないパスをすべて404ページで返します。

ブラウザで確認してみましょう。詳細ページを作成することができました。

ついでに404ページも作成してみましょう。pages/以下に404.jsを作成すると、静的な404ページを作成することができます。

  • pages/404.js → 404ページ
export default function Custom404() {
  return (
    <main className="main">
      <p>ページがありません。</p>
    </main>
  );
}

パスがないURLにアクセスすると、404ページが表示されることが確認できます。

7. CSSで見た目を装飾する

microCMSのリッチエディタで記述した内容はHTML形式で取得することができます。
しかし、HTML内にclassを付与することが現状できないので、本文を囲うdivにclassを付与し、タグ指定でcssを書いていきます。

Scssで記述するために、sassをインストールします。

$ npm install --save sass

ここではグローバルレベルのスタイルと、CSS Moduleを使ったコンポーネントレベルのスタイリングを説明していきます。

グローバルスタイルは_app.jsに読み込みます。今回のプロジェクトではすでにスタイルが読み込まれてることが確認できます。

// pages/_app.js
import '../styles/globals.css'

function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />
}

export default MyApp

そして、CSS Modulesを使ったコンポーネントのレベルのスタイリングです。
CSS Modulesを使うことによって、ローカルのCSSにスコープを効かせることができます。
ファイル名は[name].module.cssのようにmoduleをつけます。

こちらが簡単なスタイリング例です。

.text {
  color: red
}

こちらがスタイルの指定方法です。

<p className={styles.text}>これはテキストです</p>

それではスタイリングしていきましょう。
styles/Home.module.cssのファイル名をHome.module.scssに変更して、Scssに対応します。
そして、下記の内容を入力してください。

.main {
  width: 960px;
  margin: 0 auto;
}

.title {
  margin-bottom: 20px;
}

.publishedAt {
  margin-bottom: 40px;
}

.post {
  & > h1 {
    font-size: 30px;
    font-weight: bold;
    margin: 40px 0 20px;
    background-color: #eee;
    padding: 10px 20px;
    border-radius: 5px;
  }

  & > h2 {
    font-size: 24px;
    font-weight: bold;
    margin: 40px 0 16px;
    border-bottom: 1px solid #ddd;
  }

  & > p {
    line-height: 1.8;
    letter-spacing: 0.2px;
  }

  & > ol {
    list-style-type: decimal;
    list-style-position: inside;
  }
}

そして記事詳細ページはこのようにスタイルを当てていきます。/pages/blog/[id].jsを編集してください。

import { client } from '../../libs/client';
import styles from '../../styles/Home.module.scss';

export default function BlogId({ blog }) {
  return (
    <main className={styles.main}>
      <h1 className={styles.title}>{blog.title}</h1>
      <p className={styles.publishedAt}>{blog.publishedAt}</p>
      <div
        dangerouslySetInnerHTML={{
          __html: `${blog.body}`,
        }}
        className={styles.post}
      />
    </main>
  );
}
// more


すると、記事詳細ページを確認するとこのような見た目になっています。

8. ビルドして静的ファイルを生成してみる

試しに一度ローカル環境でビルドしてみましょう。
ビルドするために必要な.env.localファイルを作成します。内容は.env.development.localと同じです。

API_KEY=xxxxxxxxxxxx

そして、ビルドしてみましょう。

$ npm run build

すると、ビルドログを確認することができます。/blog/[id] を確認すると動的なページも出力できていることが確認できます。

9. ファイルをホスティングする

Next.jsの開発元でもあるVercel社が運営しているホスティングサービスを使用します。事前にログインを済ませておいてください。
https://vercel.com

まずは、GitHubリポジトリを作成します。

$ git add .
$ git commit -m 'first commit'
$ git remote add origin your-repository  // 自分のリポジトリを入力
$ git push -u origin main


Vercelで先ほど作成したリポジトリと連携をしていきます。
ダッシュボード上のNew Projectをクリックします。そして、今回作成したリポジトリを選択して、Import Git Repositoryimportをクリックしてください。


GitHubにVercelがインストールされていない場合はインストールする必要があります。

自分のアカウントを選択します。

そして、今回作成したリポジトリを選択します。

インポートしたプロジェクトの情報が表示されます。

Build and Output Settings はそのままでOKです。
Environment VariablesにAPI_KEYを入れてVALUEにはmicroCMSのAPIキーを入れてAddをクリックしてください。そしてDeployをクリックしましょう。

デプロイが成功すると下記の画面に移ります。ホスティングに成功しているか確認してみましょう。

10.microCMSとVercelを連携する

現在の設定では、microCMSで記事を更新しても本番環境WEBサイトには反映されません。
なぜなら、静的なサイトでは再度ビルドを行わないと、実際の環境には反映されないからです。
なのでWebhookを利用して、記事の更新時にビルドを走らせる設定にします。

Vercelのダッシュボードで、先ほどデプロイしたプロジェクトのsettingsからGit > Deploy HooksでWebhookを作成します。Hook NameはmicroCMS(ここはお好きな名前で大丈夫です)、Git Branch Nameにはmain(またはmaster)ブランチを指定しましょう。そして、Create Hookをクリックすると、Web HookのURLが発行されます。

発行されたWebhookをmicroCMSの管理画面で設定します。先ほど作成したブログのAPI設定から、カスタム通知を選択して、WebhookのURLを入力してください。

これで、記事を更新するとVercelのビルド開始されて本番環境に内容が反映されます。

11.カテゴリーを追加する

最後に、既存のブログAPIにカテゴリーを追加してみましょう。API名にカテゴリー、エンドポイントにcategoriesを入力してください。
カテゴリーを紐付けるにはコンテンツ参照機能を用います。

先ほどと同じ、リスト形式を選択します。

カテゴリー名のフィールドを用意します。APIスキーマは以下の通りです。最後に完了をクリックして作成を終えましょう。


試しにいくつかカテゴリーコンテンツを入稿してみましょう。



次に、ブログの API設定 > APIスキーマ に新しくカテゴリーフィールドを追加します。
種類はコンテンツ参照で、カテゴリーAPIを指定します。


カテゴリが追加できたらブログのコンテンツ詳細を開き、追加した「カテゴリー」の項目を編集して公開します。


そして、記事の詳細ページにカテゴリーを追加してみましょう。

// pages/blog/[id].js
export default function BlogId({ blog }) {
  return (
    <main className={styles.main}>
      <h1 className={styles.title}>{blog.title}</h1>
      <p className={styles.publishedAt}>{blog.publishedAt}</p>
      <p>{blog.category && blog.category.name}</p>
      <div
        dangerouslySetInnerHTML={{
          __html: `${blog.body}`,
        }}
        className={styles.post}
      />
    </main>
  );
}

これでカテゴリーとして設定した「JavaScript」が、ページにも反映されました!

おわりに

今回はmicroCMSとNext.jsを組み合わせてJamstackアーキテクチャーを利用したブログを作成しました。
ブログを公開したら #microCMS をつけてぜひツイートで教えてください。運営メンバーが楽しく拝見させてもらいます。

また、ブログに機能を追加するうえで参考になる記事もありますのでよければ読んでみてください。


-----

microCMSは日々改善を進めています。
ご意見・ご要望は管理画面右下のチャット、公式Twitterメールからお気軽にご連絡ください!
引き続きmicroCMSをよろしくお願いいたします!

まずは、無料で試してみましょう。

APIベースの日本製ヘッドレスCMS「microCMS」を使えば、 ものの数分でAPIの作成ができます。

microCMSを無料で始める

microCMSについてお問い合わせ

初期費用無料・14日間の無料トライアル付き。ご不明な点はお気軽にお問い合わせください。

お問い合わせ

microCMS公式アカウント

microCMSは各公式アカウントで最新情報をお届けしています。
フォローよろしくお願いします。

  • X
  • Discord
  • github

ABOUT ME

かみむら
フロントエンドエンジニア。テックブロガーでもあります。JAMstackアーキテクチャーやSPA(React、Vue)技術が好きです。