サイトマップは存在するだけでは足りない — indexから辿れることを検査する
今回やったこと
静的サイトの public/ にサイトマップが置かれていて、HTTP 200 を返していても、検索エンジンがそこへ到達できるとは限らない。今回の焦点は、個々の XML の疎通ではなく、sitemap-index.xml からすべての sitemap が参照されているかを検査することにした。
実害の形は単純だった。Astro 側の sitemap は index から参照されていた一方、静的に配置されたレガシー側の sitemap-legacy.xml は存在していたのに index に含まれていなかった。レガシー側には約2万 URLがあり、ファイル自体は200を返すため、本番 URL をいくつか確認するだけでは漏れが見えない。
ファイルの存在と参照関係を分ける
まず public/ を走査して、静的な sitemap を拾う。src/lib/static-sitemaps.mjs の staticSitemapFiles() は sitemap の種類を区別し、入れ子の sitemap index を通常の urlset として扱わない。次に、生成された sitemap-index.xml の参照先と、実際に public/ にあるファイルを比較する。
public/
├── sitemap-index.xml
├── sitemap-0.xml
└── sitemap-legacy.xml
この例で index が sitemap-0.xml だけを指していれば、sitemap-legacy.xml は「ファイルがあるが、入口から辿れない」状態になる。検査関数 unreferencedSitemaps() はこの差分を返し、未参照のファイルがあれば停止させる。index 自体が無い場合も「漏れ0」とは答えず、検査不能として扱う。
const missing = unreferencedSitemaps(publicDir);
if (missing.length > 0) {
throw new Error(`index から未参照: ${missing.join(', ')}`);
}
実装上は、sitemap を index に追加する側と、追加漏れを検査する側を同じ設定の流れへ置く。astro.config.mjs では sitemap() の後に assertSitemapsIndexed() が動くこともテストで確認している。生成前に確認すると、まだ存在しない index を見てしまうからだ。
回帰テストで「200なのに漏れる」を固定する
scripts/test_static_sitemaps.mjs には実データの確認と、一時ディレクトリを使った fixture テストがある。正常系では sitemap-0.xml と sitemap-legacy.xml の両方を index が指すことを確認する。異常系では、レガシー sitemap を置いたまま index から外し、未参照として検出する。
| 状態 | HTTPだけの確認 | index到達性の検査 |
|---|---|---|
| sitemap が無い | 失敗 | 失敗 |
| sitemap があり200 | 成功に見える | 参照されなければ失敗 |
| index が全ファイルを参照 | 成功 | 成功 |
| index が無い | 判定不能 | 判定不能として停止 |
この差分が必要なのは、疎通と発見可能性が別の性質だからである。ファイルを配信できることは、サイトマップの入口から辿れることを意味しない。静的ファイルを追加する運用では、追加した人が index の編集を忘れるだけで同じ穴が再発する。
自動化する範囲としない範囲
この検査が保証するのは、public/ の静的 sitemap が index から参照されていること、index が存在すること、入れ子の sitemap index を誤って受け入れないことだ。URL の内容が正しいか、重複していないか、検索エンジンが実際に取得できるかまでは別の検査になる。
したがって、サイトマップの数を手で数えて正常と判断するのではなく、配置場所を走査し、入口との関係を機械で比較する。参照漏れが起きたときにビルドを止めることで、200を返す不完全な成果物をそのまま配らずに済む。
参照した実装は src/lib/static-sitemaps.mjs、scripts/test_static_sitemaps.mjs、astro.config.mjs である。レガシー sitemap の漏れと、修正後の回帰テストの形を整理した。
環境・バージョン: テストは Node.js の組み込み test runner を node --test で実行する構成で、外部サービスへの問い合わせを前提にしない。
更新履歴
- 2026-09-02: 初稿。リポジトリ内の実装とテスト記録をもとに整理。
訂正履歴
(なし)