hyme

AstroのSSRモードで動的パスを含むコンテンツのサイトマップをつくる

Astroには公式のプラグインで @astrojs/sitemap というサイトマップをつくるためのプラグインが存在します。

しかしこのプラグインでは、SSRモードのダイナミックルートのサイトマップエントリーを生成できません。(上記サイトより引用)

This integration cannot generate sitemap entries for dynamic routes in SSR mode.

そこで、本ブログでは自作で sitemap.xml をつくりました。

つくったもの

以下のような sitemap.xml.ts というファイルを pages/ に配置し、Custom Endpointとして設置することになりました。

import type { APIContext } from 'astro'
import { getCollection } from 'astro:content'
import { SITE_URL } from '~/const/website'

export async function GET(ctx: APIContext) {
  const scraps = await getCollection('scrap')
  const items = scraps.map((scrap) => ({
    loc: `${SITE_URL}/scrap/${scrap.slug}/`,
    lastmod: scrap.data.pubDate,
  }))

  items.unshift({
    loc: `${SITE_URL}/`,
    lastmod: new Date(),
  })

  const itemsStr = items
    .map(
      ({ loc, lastmod }) =>
        `<url><loc>${loc}</loc><lastmod>${lastmod.toJSON()}</lastmod></url>`,
    )
    .join('')

  const sitemap = `<?xml version="1.0" encoding="UTF-8"?>
   <urlset xmlns="https://www.sitemaps.org/schemas/sitemap/0.9">
     ${itemsStr}
   </urlset>`

  const res = new Response(sitemap)
  res.headers.set('Content-Type', 'text/xml')
  return res
}

解説

現状 Content Collections を利用してマークダウンファイルを管理しています。

そのため、 astro:contentgetCollection を利用してすべてのマークダウンファイルの情報を取得しています。

const scraps = await getCollection('scrap')

このコレクションからサイトマップを作成します。

サイトのトップページもサイトマップに追加したかったので、それをまず追加しています。

items.unshift({
  loc: `${SITE_URL}/`,
  lastmod: new Date(),
})

主なコードは以下です。

const itemsStr = items
  .map(
    ({ loc, lastmod }) =>
      `<url><loc>${loc}</loc><lastmod>${lastmod.toJSON()}</lastmod></url>`,
  )
  .join('')

const sitemap = `<?xml version="1.0" encoding="UTF-8"?>
   <urlset xmlns="https://www.sitemaps.org/schemas/sitemap/0.9">
     ${itemsStr}
   </urlset>`

最後に、XMLとしてレスポンスを返して完了です。

const res = new Response(sitemap)
res.headers.set('Content-Type', 'text/xml')
return res