• #sitemap
  • #seo
  • #nuxt
  • #cloudflare-pages
  • #nuxt-content

サイトマップ実装の対応方針

背景と目的

現在のプロジェクトにはサイトマップ(sitemap.xml)が実装されていない。サイトマップを実装することで以下のメリットが得られる:

  • 検索エンジンがコンテンツを効率的にクロールできる
  • SEOの向上
  • 新しいコンテンツの発見が早くなる
  • サイト構造の明確化

プロジェクトの特徴

  • Nuxt: 4.1.2
  • @nuxt/content: 3.7.1
  • デプロイ先: Cloudflare Pages(cloudflare-pagesプリセット)
  • コンテンツ構成:
    • Markdown/MDXコンテンツ(日付ディレクトリ配下)
    • カスタムVueページ(pages/blog/など)

調査結果

パッケージの選定

推奨パッケージ: @nuxtjs/sitemap(最新版: 7.4.7)

  • 旧パッケージ nuxt-simple-sitemap@nuxtjs/sitemap に統合された
  • Nuxt SEOパッケージの一部として提供されている
  • Nuxt 3/4に対応
  • @nuxt/contentとの統合機能を提供

Cloudflare Pages互換性

互換性の状況:

最新版(7.x系)は互換性あり

  • 2025年2月のデプロイメント設定でバージョン7.2.4が使用されている実績あり
  • 過去のバージョン5.3.1では問題があった(execaパッケージの依存関係によるNode.js互換性問題)

⚠️ 注意点:

  • ビルド時のNode.js互換性問題が発生する可能性がある
  • 循環依存の問題が報告されている(特にsitemap_index.xml.js)
  • テストビルドで事前確認が推奨される

Nuxt Content統合のポイント

重要な設定:

  1. モジュールのロード順序
    export default defineNuxtConfig({
      modules: [
        '@nuxtjs/sitemap',  // 必ずcontentモジュールより前に配置
        '@nuxt/content'
      ]
    })
    
  2. コレクションの拡張
    • Nuxt Content v3では asSitemapCollection() 関数を使用してコレクションを拡張する
    • frontmatterから直接sitemap設定が可能
  3. サポートされるコンテンツ形式
    • Markdown (.md)
    • YAML (.yml / .yaml)
    • JSON (.json)
    • CSV (.csv)

実装手順

1. パッケージのインストール

cd apps/web
pnpm add @nuxtjs/sitemap

2. nuxt.config.tsの設定

export default defineNuxtConfig({
  modules: [
    '@nuxtjs/sitemap',  // contentより前に配置!
    '@nuxt/content',
    // ... その他のモジュール
  ],

  sitemap: {
    // サイトのベースURL(本番環境)
    hostname: 'https://your-domain.com',

    // Nuxt Content統合の設定
    strictNuxtContentPaths: true,

    // 除外するパス(必要に応じて)
    exclude: [
      '/api/**',
      '/admin/**'
    ],

    // デフォルトの設定
    defaults: {
      changefreq: 'daily',
      priority: 0.8
    }
  },

  // Cloudflare Pages用の設定(既存)
  nitro: {
    preset: 'cloudflare-pages'
  }
})

3. content.config.tsの設定(オプション)

Nuxt Contentのコレクション定義で asSitemapCollection() を使用する場合:

import { defineCollection, asSitemapCollection } from '@nuxt/content'

export const collections = {
  content: defineCollection(
    asSitemapCollection({
      type: 'page',
      source: '**/*.md'
    })
  )
}

4. フロントマターでの個別設定(オプション)

各Markdownファイルのfrontmatterでサイトマップ設定を上書き可能:

---
title: "記事タイトル"
sitemap:
  changefreq: "weekly"
  priority: 0.9
  lastmod: "2025-12-02"
---

5. 動的ルートの追加(カスタムVueページ用)

server/api/sitemap.ts または nitro.hooks を使用してカスタムページを追加:

// server/routes/sitemap.xml.ts
import { defineSitemapEventHandler } from '#imports'

export default defineSitemapEventHandler(async (e) => {
  return [
    {
      loc: '/blog',
      lastmod: new Date(),
      changefreq: 'daily',
      priority: 0.9
    },
    // その他のカスタムページ
  ]
})

テスト方法

開発環境でのテスト

cd apps/web
pnpm dev

ブラウザで以下にアクセス:

  • http://localhost:3000/sitemap.xml
  • http://localhost:3000/sitemap_index.xml(複数サイトマップの場合)

ビルドテスト

cd apps/web
pnpm build
pnpm preview

プレビューサーバーで http://localhost:3000/sitemap.xml にアクセスして確認。

Cloudflare Pagesでのテスト

cd apps/web
pnpm deploy:cloudflare

デプロイ後、本番URLで /sitemap.xml にアクセスして確認。

予想される課題と対策

課題1: Cloudflareビルド時のNode.js互換性エラー

対策:

  • 最新版の @nuxtjs/sitemap (7.x系) を使用する
  • ビルドエラーが発生した場合は、依存関係を確認し、必要に応じて package.jsonoverrides または resolutions を設定する

課題2: 日付ディレクトリ構造への対応

対策:

  • strictNuxtContentPaths: true を設定し、コンテンツの実際のパスを使用する
  • 必要に応じて server/routes/sitemap.xml.ts でカスタムロジックを追加

課題3: 画像URLの扱い

対策:

  • サイトマップには基本的にページURLのみを含める
  • 画像サイトマップが必要な場合は別途 sitemap-images.xml として生成を検討

実装の優先度

必須(Phase 1)

  1. @nuxtjs/sitemap のインストール
  2. ✅ 基本設定(nuxt.config.ts)
  3. ✅ Nuxt Content統合の設定
  4. ✅ 開発環境でのテスト

推奨(Phase 2)

  1. カスタムVueページの追加ロジック実装
  2. フロントマターでの個別設定の活用
  3. Cloudflare Pagesでのデプロイテスト

オプション(Phase 3)

  1. サイトマップの分割(複数サイトマップ)
  2. 画像サイトマップの生成
  3. 多言語対応(必要な場合)

参考リンク

実装済みの内容

完了した作業

  1. @nuxtjs/sitemap v7.4.7のインストール完了
  2. nuxt.config.tsにサイトマップ基本設定を追加
  3. ✅ Vueページが自動的にサイトマップに追加されることを確認
  4. ✅ Nuxt Content統合のためのサーバールート作成(server/routes/__sitemap__/urls.ts

Nuxt Content統合の実装方法

server/routes/sitemap/urls.tsを作成:

import { serverQueryContent } from '#content/server'
import { asSitemapUrl, defineSitemapEventHandler } from '#imports'

export default defineSitemapEventHandler(async (e) => {
  const contentList = await serverQueryContent(e).find()
  return contentList.map((c) => {
    return asSitemapUrl({
      loc: c._path,
      lastmod: c.updatedAt || c.publishedAt
    })
  })
})

この実装により、Nuxt Contentで管理されているすべてのMarkdownファイルがサイトマップに自動的に追加されます。

注意事項

開発環境で複数のプロセスが起動すると、SQLiteデータベースのロック競合が発生する可能性があります。この場合は:

  1. すべての開発サーバープロセスを停止
  2. .nuxtディレクトリを削除
  3. 開発サーバーを再起動

本番環境(Cloudflare Pages)では、D1データベースを使用するため、この問題は発生しません。

まとめ

実装完了:

  • @nuxtjs/sitemap 最新版(7.4.7)を使用
  • Nuxt Contentとの統合をdefineSitemapEventHandlerで実装
  • モジュールロード順序に対応(sitemapをcontentより前に)

次のステップ:

  1. 開発環境でのクリーン再起動とテスト
  2. Nuxt Contentページがサイトマップに含まれていることを確認
  3. ビルドテスト
  4. Cloudflare Pagesへのデプロイテスト