Waka blog.

microCMSで記事追加後に自動的にsitemap.xmlを更新しデプロイする

やりたいこと

microCMSに記事を追加した際、公開中のブログのsitemap.xmlに記事追加を反映したい。

前提

  1. Cloudflare Pagesにブログを公開している
  2. Githubと連携し、リポジトリへのpushをトリガーにデプロイしている

やったこと

  1. sitemap.xmlを生成するスクリプトを実装
  2. Github actionsに 1. のスクリプトを実行し、生成したsitemap.xmlをpushするworkflowを登録
  3. microCMSに記事を追加した際、 1. のGithub actionを起動するwebhookを設定

sitemap.xmlを生成するスクリプトを実装

sitemapの生成にはsitemapを使用しました。また、microCMSのコンテンツ取得にはmicrocms-js-sdkを使用しています。

それぞれ、事前にinstallしておきます。

import { createWriteStream } from "fs";
import { createClient } from "microcms-js-sdk";
import process from "process";
import { SitemapStream, streamToPromise } from "sitemap";

export const client = createClient({
  serviceDomain: process.env.MICROCMS_SERVER_DOMAIN,
  apiKey: process.env.MICROCMS_API_KEY,
});

// カテゴリを取得
const getCategories = async () => {
  const data = await client.getList({
    endpoint: "categories",
  });
  return data.contents;
};

// blog記事を取得
const getPosts = async () => {
  const limit = 20;
  let results = [];
  let offset = 0;
  let hasNext = true;

  while (hasNext) {
    const data = await client.getList({
      endpoint: "blog",
      queries: {
        orders: "-updatedAt",
        offset: offset,
        limit: limit,
      },
    });
    results = results.concat(data.contents);
    hasNext = data.totalCount > offset;
    offset += limit;
  }

  return results;
};

const createSitemap = async () => {
  console.log(`Start generating sitemap.`);
  const sitemapStream = new SitemapStream({
    hostname: process.env.MY_HOST_NAME,
    encoding: "UTF-8",
    xmlns: {
      xhtml: "http://www.w3.org/1999/xhtml",
    },
  });

  console.log(`Start getting categories.`);
  const categories = await getCategories();
  categories.map((category) => {
    category.updatedAt;
    const route = { url: `/categories/${category.id}`, changefreq: "monthly", priority: 0.5 };
    sitemapStream.write(route);
  });
  console.log(`End getting categories.`);

  console.log(`Start getting posts.`);
  const posts = await getPosts();
  posts.map((post) => {
    post.updatedAt;
    const route = { url: `/posts/${post.id}`, changefreq: "monthly", priority: 0.8 };
    sitemapStream.write(route);
  });
  console.log(`End getting posts.`);

  // blog記事取得時にupdatedAtの降順でソートしているので、配列の1件目のupdatedAtが最新の更新日となる
  const lastmod = posts.length > 0 && posts[0].updatedAt;

  sitemapStream.write({ url: "/", changefreq: "daily", priority: 1.0, lastmod: lastmod });
  sitemapStream.write({ url: "/about", changefreq: "monthly", priority: 0.5 });

  // sitemapの生成を終了します
  sitemapStream.end();

  console.log(`Start writting sitemap.xml.`);
  // sitemapをXML形式に変換し、ファイルに書き込みます
  streamToPromise(sitemapStream).then((sitemap) => {
    createWriteStream("public/sitemap.xml").write(sitemap);
  });
  console.log(`End writting sitemap.xml.`);
  console.log(`End generating sitemap.`);
};
createSitemap();

package.jsonにscripts登録

...
"scripts": {
    ...
    "generate-sitemap": "node scripts/generateSitemap.js"
},
...

sitemap.xmlをpushするworkflowの作成

repository_dispatchは外部サービスからGithub actionを発火させるためのキーで、microCMSでのwebhook登録時に必要になります。

各種環境変数は事前にGithubのsecretsに登録しておく必要があります。

参考:https://docs.github.com/ja/actions/security-guides/using-secrets-in-github-actions#creating-secrets-for-a-repository

name: Sitemap Generator

on:
  push:
    branches:
      - main
  repository_dispatch:
    types: [generate-sitemap]

permissions:
  contents: write

jobs:
  build:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [20.8.0]

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}

      - name: Install dependencies
        run: npm ci

      - name: Generate sitemap
        run: npm run generate-sitemap # sitemapを生成するスクリプトを実行します
        env:
          MICROCMS_API_KEY: ${{ secrets.MICROCMS_API_KEY }}
          MICROCMS_SERVER_DOMAIN: ${{ secrets.MICROCMS_SERVER_DOMAIN }}
          MY_HOST_NAME: ${{ secrets.MY_HOST_NAME }}

      - name: Commit and push
        run: |
          git config --local user.email "[email protected]"
          git config --local user.name "GitHub Action"
          git commit -m "Update sitemap.xml" -a || echo "No changes to commit"
          git push

microCMS側のwebhook設定

microCMSの公式ヘルプに詳しく記載してあります、この通りに進めれば問題ないです。

https://help.microcms.io/ja/knowledge/webhook-github-actions-settings

これで記事を追加するたびにGithub actionsが起動してsitemap.xmlがリポジトリにpushされ、その内容がCloudflare pagesにデプロイされるようになります。

以下コード

https://github.com/waka-apps/microcms-sitemap-updater