https://endaaman.me/sitemap.xml で見られる。

このサイト(というかブログ)はトップページと各メモ(記事)しかコンテンツはないので簡単に済んだ。

サーバーサイドでもReduxのstoreが見えているので、メモの一覧取得のアクション(getMemos)をstore.dispatch(getMemos())で発行して、返り値のPromiseを待ち受けて、そのコールバックでgetState().memo.itemsで一覧を取得して、

import { createSitemap } from 'sitemap'


function buildSitemap(baseUrl, memos) {
  function escapeQuery(url) {
    const [path, query] = url.split('?')
    if (!query) {
      return url
    }
    return path + '?' + encodeURIComponent(query)
  }

  const urls = [
    {
      url: baseUrl + '/',
      changefreq: 'daily',
    }
  ]

  for (const memo of memos) {
    if (memo.draft) {
      continue
    }
    const url = {
      url: `${baseUrl}/memos/${memo.slug}`,
      lastmodISO: (new Date(memo.updated_at)).toISOString(),
      changefreq: 'weekly',
    }
    if (memo.image_url) {
      url.img = escapeQuery(memo.image_url)
    }
    urls.push(url)
  }

  const sitemap = createSitemap({
    cacheTime: 3 * (60 * 60 * 1000), // x hours
    urls: urls
  })

  return sitemap.toString()
}

みたいなのを呼ぶだけ。今回このサイトのURLは/memoの下にslugフィールドをつなげただけのものなのでこんなもんで十分だったが、react-router等で複雑なRoutingを実装してるとクライントサイドの設定から生成しなきゃいけなくなったりするので、なるべく扱うデータ(store)自体に一意なURLを生成するための情報をもたせる様な設計にしておくと良いだろう。