Nuxt Contentでsitemap.xmlの自動生成

先日,ブログ移行後の投稿記事が検索インデックスに反映されていないことに気づきました.

以前は WordPress でサイトマップは自動生成されていたのでクローラに親切だったのですが,すっかり存在を忘れていました…

SSG で静的サイトを生成するときにもサイトマップを自動で生成して欲しいですね.

Nuxt.js ではコミュニティの @nuxtjs/sitemap というパッケージがあるので,これを使うと簡単に生成できるそうです.

(SSG だったために若干の苦労があることをこのときはまだ知らない)

環境

  • Node.js: v13.12.0
  • npm: v6.14.8
  • @nuxtjs/sitemap: v2.4.0

また,静的ページだけでなく @nuxt/content で作成したサイトの動的ページもサイトマップに含めたいと思います.

インストールコマンドは以下の通りです.

terminal

$ yarn add @nuxtjs/sitemap

サイトマップの作成

@nuxtjs/sitemap では静的なルーティングが設定されたページはデフォルトでサイトマップに含まれるようになっています.

しかし,動的に追加されるようなコンテンツ(@nuxt/content における .md ファイル)は生成時に構造が理解できないため,追加できません.

そのため,設定ファイルにてサイトマップに含める内容を明示的に宣言する必要があります.

SSRとSSGでの扱いの違い

Nuxt.js は SSR でも SSG でも利用できますが,@nuxt/content で紹介されている方法は SSR でしか使えない感じがします.

const { $content } = require('@nuxt/content')
const articles = await $content('articles').fetch()

上記のように require することでコンテンツを読み込むことができるのですが,SSG の場合はモジュールがロードされてから出ないと呼ぶことができず,そこら辺の影響でなのか取得できません(よくわかってない).

参考:Advanced - Nuxt Content

(追記 2020.12.21)

フィード生成と同じように自分でモジュール化して generate 後に動くようにフックしておけば動きそう.

https://blog.mktia.com/generate-feed-in-nuxt-ssg

SSGでのサイトマップ作成例

検索してみるといろいろあります(今回は別の方法で実装しましたが参考までに).

Axios を使う方法は SSR でも SSG でも使えそうですが,SSG の場合は二回デプロイしなければならなくなるのでやめました.

JSON や walk-sync を使う方法は SSG でも簡単に生成できる方法ですが,それのためだけに新しくパッケージをインストールするのも…と思ってこちらも断念.

結局 Node.js に付属している fs で実装することにしました.

実装例

nuxt.config.js

export default {
  ...
  modules: [
    `@nuxtjs/sitemap`
  ],

  sitemap: {
    hostname: 'https://<your-site.com>'
    routes: () => {
      const fs = require('fs')
      const files = fs.readdirSync('./content/articles')
      return files.map((file) => {
        if (RegExp('md$').test(file)) {
          return file
        }
      })
    }
  }
}

* @/content/articles 以下に .md ファイルを置いている場合.

対象のディレクトリ内で正規表現に適合したファイル名のみを持ってきています.

私の環境では各エントリーの URL が https://<your-site.com>/<article-slug> となっているため,上記のようになっています.

fs がないと怒られる場合は以下の記事を参考にしてみてください.

https://blog.mktia.com/cant-resolve-fs-on-nuxtjs

最後に

記事ページだけではありますが,sitemap.xml を設定できたのでクローラが周りやすくなるんじゃないかと思います.