📘

microCMSブログのNext.js版を作成した

2021/05/05に公開約6,300字4件のコメント

はじめに

microCMS 様が自社ブログのソースコードを github にあげてくださっています。

https://github.com/wantainc/microcms-blog
https://blog.microcms.io/

本家 microCMS 様のブログは Nuxt.js×Netlify という構成です。
最近は Next.js×Vercel という構成をよく見るため、せっかくなので勉強がてら Next.js×Vercel 構成のブログを頑張って作ってみました。
デモサイト →
ソースコード →

また私と同じ試みをされている方がいらっしゃいます。

https://zenn.dev/d_suke/articles/5bd7b2da4de87c22368e
https://github.com/dc7290/nextjs-microcms-blog

こちらのソースコードでは、私の方では利用していないaspidapathpidauseSWR等を使用されています。
他にも私のとは違った書き方・技術構成となっていますので、ぜひご参考になさってください。

microCMS とは

microCMS はクラウド型のヘッドレス CMS です。
コンテンツ管理のためのサーバ管理は一切不要で、サインアップするだけですぐにサービスを利用開始できます。

詳しくは、下記リンクをチェック

https://blog.microcms.io/getting-started/

方針

デザイン、コンポーネント、コンテンツ、機能は microCMS ブログとほぼ同様のものにする。

技術構成

  • Next.js (SSG + SSR)
  • TypeScript
  • CSS Modules
  • microCMS (コンテンツ)
  • Vercel (Hosting, API)

機能の比較

microCMS ブログと同じ機能にしようと頑張りましたが、すべての機能を作成しませんでした。
差分で赤くなっている項目は今回は含めていません。

記事一覧
カテゴリー別記事一覧
人気の記事一覧
最新の記事一覧
検索
パンくずリスト
記事詳細
目次
著者
SNSシェアボタン
下書きプレビュー
関連記事
サイトマップ
バナー
Google Analytics
RSS
- PWA

microCMS の API スキーマ設定

API スキーマ設定

ブログ

endpoint: blog
type: リスト形式

フィールド ID 表示名 種類
title タイトル テキストフィールド
category カテゴリー コンテンツ参照 - カテゴリー
toc_visible 目次 真偽値
body 本文 リッチエディタ
description 概要 テキストフィールド
ogimage OGP 画像 画像
writer 著者 コンテンツ参照 - 著者
partner パートナー コンテンツ参照 - パートナー
related_blogs 関連記事 複数コンテンツ参照 - ブログ

著者

endpoint: authors
type: リスト形式

フィールド ID 表示名 種類
name 名前 テキストフィールド
text 自己紹介 テキストエリア
image 画像 画像

カテゴリー

endpoint: categories
type: リスト形式

フィールド ID 表示名 種類
name 名前 テキストフィールド

パートナー

endpoint: partners
type: リスト形式

フィールド ID 表示名 種類
company 会社名 テキストフィールド
url 会社 URL テキストフィールド
description 説明文 テキストエリア
logo ロゴ 画像

人気の記事

endpoint: popular-articles
type: オブジェクト形式

フィールド ID 表示名 種類
articles 人気の記事 複数コンテンツ参照 - ブログ

バナー

endpoint: banner
type: オブジェクト形式

フィールド ID 表示名 種類
image 画像 画像
url リンク先 URL テキストフィールド
alt 代替テキスト テキストフィールド

コンテンツ更新時の自動ビルド設定

SSG にしているので、再ビルドしないと最新のコンテンツが更新されません。
なので、microCMS のコンテンツ更新時に Vercel の自動ビルドされるようにします。

Vercel 側の設定

Settings タブ -> Git -> Deploy Hooks にHook Nameとデプロイ対象のGIt Branch Nameを入力する。
その後生成される URL をコピーする。

microCMS 側の設定

対象の API を選択し、「API 設定」に遷移。
WebHook -> カスタム通知 を選択。
Webhook の名前、上記でコピーした URL、通知タイミングを選択し、設定ボタンを押下。

下書きプレビューについて

下書き中のコンテンツの取得方法

microCMS ではコンテンツが下書き状態のとき、draftKeyが発行されます。
コンテンツ取得のリクエスト時にクエリパラメータにdraftKeyを付与することで下書き中のコンテンツを取得することができます。

プレビューー機能

microCMS にはプレビュー機能があり、「画面プレビュー」ボタンを押下した際の遷移先 URL を指定することができます。
API 設定 -> 画面プレビュー

実装方法

下書きコンテンツの取得の流れは以下のようになります。

  1. microCMS の管理画面から「画面プレビュー」を押下し、プレビュー画面を表示する。
  2. クライアント側がコンテンツのiddraftKeyを受け取り、API へリクエスト。
  3. 取得データをレンダリング

プレビュー用ページの追加

まずはプレビュー用のページを用意します(/draft)
プレビューページはビルド時ではなく URL からアクセスされたタイミングでクライアント側から API リクエストを行います。
また、クライアント側から直接 microCMS の API を叩くと APIKey が見えてしまうので、Next.js の API Routes を利用します。

/pages/draft/index.tsx
const Draft = (props) => {
  const router = useRouter();
  const [data, setData] = useState<IDraftResponse>(null);
  const [isLoading, setLoading] = useState<boolean>(true);

  const fetcher = async () => {
    const query = router.query;
    const data = await axios.get(`${config.baseUrl}/api/draft?id=${id}&draftKey=${draftKey}`); // 下書き状態のコンテンツ取得
    setData(data);
    setLoading(false);
  };

  useEffect(() => {
    // router.queryが最初のレンダリングでは取得できないため、
    // 二回目のレンダリングからリクエストを送るようにする
    if (router.isReady) {
      fetcher();
    }
  }, [router.isReady]);

  return (
      // 省略
  )
}

下書きコンテンツ取得用 API を作成

上記で述べたように API Routes を利用するので、/pages/api/draft.tsxを作成します。

/pages/api/draft.tsx
export default async (req: NextApiRequest, res: NextApiResponse) => {
  const id = req.query.id;
  const draftKey = req.query.draftKey;

  if (!id || !draftKey) {
    res.status(400).json({ error: `missing queryparamaeter` });
  }

  return axios
    .get<IBlog>(
      `https://${config.serviceId}.microcms.io/api/v1/blog/${id}?draftKey=${draftKey}&depth=2`,
      {
        headers: { 'X-MICROCMS-API-KEY': config.apiKey },
      },
    )
    .then(({ data }) => {
      // 目次の生成やHTMLへの変換もやってしまう
      const toc = convertToToc(data.body);
      const body = convertToHtml(data.body);
      res.status(200).json({ blog: data, toc: toc, body: body });
    })
};

プレビュー画面遷移用の URL を設定

API 設定 -> 画面プレビューを開き
https://yourdomain.com/draft?id={CONTENT_ID}&draftKey={DRAFT_KEY}」を設定する

追加していきたいこと

  • PWA

最後に

間違ってる点や改善点が多々あると思いますが、ご活用いただければ幸いです。

https://github.com/wattanx/microcms-blog-with-next
https://microcms-blog-with-next-wattanx.vercel.app/
GitHubで編集を提案

Discussion

ご参考になる記事ありがとうございます。
Githubも確認させて頂いた上で、Googleアナリティクスの導入についてお聞きしたいことがあります。
上記の導入において、gtag.ts, _documents.tsx, next-env-d.tsの三箇所が主な変更点かなと思っております。
しかしネット上の様々な記事を拝見したところ、_app.tsxにPV数を測るイベントを導入していることが多いです。
wattanxさんの現状のコードでも無事にPV数の測定は可能となっていますでしょうか?
お手隙の際に、ご回答いただけたら幸いです。

ご報告ありがとうございます!
おっしゃる通り_app.tsxにPV数を測定するイベントを設定する必要がありました。
(完全に忘れておりました...)
修正して反映しております。
Googleアナリティクスの導入での変更点は、gtag.ts,_document.tsx,next-env-d.ts, _app.tsxになります。

また、導入にあたり私が参考にしたのは下記の記事とNext.js公式のソースコードです。

https://panda-program.com/posts/nextjs-google-analytics
https://github.com/vercel/next.js/tree/canary/examples/with-google-analytics

wattanxさんご回答、参考記事まで追記ありがとうございます。

導入において、改めてお聞きしたことがあります。
pageViewメソッド発火時に、gtag.tsのwindow.gtag('config'~~~~~)は正常通りに実行されましたでしょうか?
原因は謎なのですが、私の実行環境ではwindow.gtag is not functionと怒られてしまって...
また、googleAnalyticsは最新のGA4(測定ID)、旧バージョンのユニバーサル(トラッキングID)どちらで設定していらっしゃいますでしょうか?

もしよろしければご回答いただけると幸いです。。

私はGA4のほうで設定してます!
もしかしたら下記の<script>タグがないとかですかね...
私のソースコード上で変な動きしているところがあれば、またお時間のあるときにgithubのissue投げちゃってください!

<script
    dangerouslySetInnerHTML={{
      __html: `
        window.dataLayer = window.dataLayer || [];
        function gtag(){dataLayer.push(arguments);}
        gtag('js', new Date());
        gtag('config', '${GA_TRACKING_ID}', {
        page_path: window.location.pathname,
      });`,
   }}
/>

ログインするとコメントできます