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:content
の getCollection
を利用してすべてのマークダウンファイルの情報を取得しています。
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