Eleventy ビルドで sitemap.xml と robots.txt を自動生成

shoelace-style/webawesome

Eleventy のドキュメントビルド時に SEO 必須の sitemap.xmlrobots.txt を自動生成し、Docs の公開パイプライン全体で自動的に提供できるようになりました。

背景

SEO 監査で /sitemap.xml/robots.txt が 404 となっていることが指摘され、検索エンジンのインデックス付与とクロール制御が不十分でした。Webawesome のドキュメントはスタンドアロンのビルドと webawesome-app への組み込みの二つの形態で配布されるため、手動でファイルを配置する運用はミスが起きやすく保守コストが高くなります。そこでビルドプロセスに sitemaprobots.txt の生成ロジックを組み込み、ビルド結果に必ず含める設計が採用されました。

技術的な変更

Sitemap collection の導入HtmlBasePlugin の有効化により、公開対象の URL を絞り込んだコレクションを生成します。.eleventy.js では addCollection('sitemap', ...) が追加され、noindexeleventyExcludeFromCollections が設定されたページ、管理画面系パス(/admin など)およびエラーページを除外するフィルタリングロジックが実装されています。

// Sitemap collection: public, indexable URLs only.
const SITEMAP_EXCLUDE_PATTERNS = [
  /^\/admin(\/|$)/,
  /^\/workspaces(\/|$)/,
  // ... 省略
];

eleventyConfig.addCollection('sitemap', collection => {
  return collection
    .getAllSorted()
    .map(item => {
      const raw = String(item.data.ogUrl || item.url || '').replace(/\.njk$/, '');
      const urlPath = raw.replace(/^https?:\/\/[^/]+/, '');
      return { item, urlPath };
    })
    .filter(({ item, urlPath }) => {
      if (!urlPath) return false;
      if (item.data.noindex) return false;
      if (item.data.eleventyExcludeFromCollections) return false;
      if (SITEMAP_EXCLUDE_PATTERNS.some(re => re.test(urlPath))) return false;
      // ... 省略
      return true;
    })
    .map(({ item, urlPath }) => ({ path: urlPath, lastmod: item.date }));
});

sitemap.xml.njk テンプレートは 11ty のベースブログパターンを踏襲し、layout: false により XML が HTML ラップされないようにしています。htmlBaseUrl(siteMetadata.url) フィルタで絶対 URL に変換し、将来的にパスプレフィックスが付くケースでも正しい URL が生成されます。

---
permalink: /sitemap.xml
layout: false
eleventyExcludeFromCollections: true
---
<?xml version="1.0" encoding="utf-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
{%- for entry in collections.sitemap %}
  <url>
    <loc>{{ entry.path | htmlBaseUrl(siteMetadata.url) }}</loc>
    {%- if entry.lastmod %}
    <lastmod>{{ entry.lastmod }}</lastmod>
    {%- endif %}
  </url>
{%- endfor %}
</urlset>

robots.txt.njk はシンプルに全クローラを許可し、先ほど生成した sitemap.xml の絶対 URL を宣言します。eleventyExcludeFromCollections: true によりコレクション対象外とし、余計なインデックス対象にならないようにしています。

---
permalink: /robots.txt
layout: false
eleventyExcludeFromCollections: true
---
User-agent: *
Allow: /

Sitemap: {{ "/sitemap.xml" | htmlBaseUrl(siteMetadata.url) }}

設計判断

ビルド時に動的生成 する方針が採用され、静的ファイルとしてリポジトリに配置する代わりに Eleventy のレンダリングプロセスで出力します。これによりビルド環境やデプロイ先が変わっても常に最新の URL リストが反映され、手動管理のリスクが排除されました。HtmlBasePlugin を組み込むことで URL の絶対化ロジックをプラグイン側に委譲し、テンプレート側はシンプルにフィルタ呼び出しだけで済む設計となっています。

また、公開対象の絞り込み をコレクション段階で行うことで、robots.txt に不要なパスが含まれないように保証しています。特に認証が必要なアカウント関連ページは account ディレクトリのソースパスで判定し、許可リストに入っていないファイルは除外するロジックが追加されました。これにより SEO に悪影響を与える可能性のある内部ページがサーチエンジンにインデックスされるリスクが低減します。

まとめ

この PR は Eleventy ビルドに sitemap.xmlrobots.txt の自動生成を組み込み、SEO 必須のファイルが常に最新かつ正確に配布されるようにした変更です。コレクションフィルタで公開対象を明示的に絞り、HtmlBasePlugin による絶対 URL 化を活用することで、ビルドプロセスと設定の一貫性を保ちながら運用コストを削減しました。

記事メタデータ

Generated by:
gpt-oss-120b for DiffDaily
LLM Trace:
1459145a

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
gpt-oss-120b for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

リード文、背景、技術的な変更、設計判断(任意)、まとめの5セクションが揃っており、総論→各論→結論の流れが明確です。

カスタムMarkdown構文 ✓ PASS

シンタックスハイライト・GitHubリンク記法の正確性

コードブロックは `language:filename` の形式で正しく記述され、PR リンクは `[PR #2546](URL)` の形で正しくハイパーリンク化されています。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

対象はEleventyやSEOに慣れたエンジニア向けで、初心者向けの余計な解説はありません。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクションは総論・各論・結論の段落構成になっており、1段落は1トピック、文数も6文以下で、段落間は空行で区切られています。

Diff内容との照合 ⚠ WARNING

コードブロックとDiff内容の一致

`.eleventy.js` のコードブロックは主要ロジックを示していますが、Diff にある `SITEMAP_EXCLUDE_PATTERNS` の全リストやアカウントファイルの allowlist ロジックが省略されています。省略は理解の妨げにならないものの、完全な Diff 反映ではないため警告としました。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

使用されている用語(Sitemap collection、HtmlBasePlugin、eleventyExcludeFromCollections など)は PR と一致しており、誤用はありません。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

記事の技術的説明は PR の説明と一致しており、根拠のある記述です。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

PR で示された事実(404 の指摘、ビルド時生成、除外パターンなど)と記事内容が整合しています。外部知識や推測はありません。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR 番号 #2546 が正しく記載されています。その他数値や固有名詞の誤りはありません。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事タイトルは PR の内容(sitemap.xml と robots.txt の追加)を的確に表しています。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

LTS、EOL、リリース日程等の外部知識は一切記載されていません。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

時間表現の歪曲はなく、PR の記述と整合しています。