Astroで理想のサイトマップを自作する

公開日:2023/2/2更新日:2023/2/7

Astroにはサイトマップのインテグレーションがあり、npx astro add sitemapとコマンドを打つだけで自動的にサイトマップ生成機能が追加されます。

しかし、執筆時点でこのサイトマップ機能にはバグがあり、3桁の数字を含むURLはサイトマップに追加されません。含まれる・含まれないのルールは以下の通りです。

https://example.com/hello/ 含まれる
https://example.com/12/ 含まれる
https://example.com/123/ 含まれない
https://example.com/1234/ 含まれる
https://example.com/hello/world/ 含まれる
https://example.com/blog/12/ 含まれる
https://example.com/blog/123/ 含まれない
https://example.com/hello/789/world/ 含まれない

生成する際にpathnameを使っていて、その中に404/が含まれるため、それを除外することがこの仕様になっている理由だと推測するのですが、https://example.com/blog/123/のような構成は普通にあり得るため、そういった構成を考慮すべきですし、せめて404だけピンポイントで除外する仕様にして欲しかったところです。

サイトマップを自作する方法

何はともあれ、サイトマップに含まれないとSEO上少しまずいので、上記の問題を回避できるサイトマップを自作しました。

せっかく自作するので、デフォルトの仕様であるsitemap.index.xmlsitemap-0.xmlの両方を出力するのではなく、sitemap.xmlだけ単体で出力するようにします。

インテグレーションを自作する

必要なモジュールをインストールします。

npm install --save sitemap

Astroではインテグレーションを自分で作ることができます。指定のディレクトリはないため、ルートフォルダにintegrations/sitemap.tsとしてファイルを用意し、以下のコードを記述します。

hostnameの値は自分のサイトに変更してください。

import type { AstroIntegration } from "astro";
import { SitemapStream } from "sitemap";
import { createWriteStream } from "fs";
import { fileURLToPath } from "url";

const sitemap = (): AstroIntegration => {
  return {
    name: "shinobiworks/sitemap",
    hooks: {
      "astro:build:done": async ({ dir, pages }) => {
        const hostname = "https://ringorin.com/";
        const sms = new SitemapStream({
          hostname,
        });
        const excludeSlugs = ["404", "sitepolicy", "privacypolicy"];
        const destinationDir = fileURLToPath(dir);
        const outputFileName = "sitemap.xml";

        pages.forEach(({ pathname }) => {
          const slug = pathname.slice(0, -1);
          if (!excludeSlugs.includes(slug)) {
            sms.write(hostname + pathname);
          }
        });
        sms.end();
        sms.pipe(createWriteStream(destinationDir + outputFileName));

        console.log(`%s${outputFileName} is generated!\n`, "\x1b[32m");
      },
    },
  };
};

export default sitemap;

設定ファイルに追加

先ほどのインテグレーションをastro.config.mjsに追加します。これで完了です。

import { defineConfig } from "astro/config";

import sitemap from "./integrations/sitemap";

export default defineConfig({
  integrations: [sitemap()],
});

おまけ

問題の箇所はgenerate-sitemap.tsに記載されてある以下のコードです。

.
.
.
const STATUS_CODE_PAGE_REGEXP = /\/[0-9]{3}\/?$/;
.
.
.
const urls = [...pages].filter((url) => !STATUS_CODE_PAGE_REGEXP.test(url));

変数名から察するに、404以外にも400500などのエラーもカバーしようとしているのかもしれませんが、執筆時点では404以外のエラーページは出力されないので、なぜわざわざこのような仕様にしているのか見当もつきません。