EmDashのコレクションのURLパターンを/{slug}/にしても、EmDashが出すサイトマップには/fooのように末尾スラッシュのないURLが載ります。サイトが/foo/を正規のURLにしている場合、サイトマップの全URLが301を返すことになります。Astroの設定は変えずに、記事と固定ページのサイトマップと同じパスのルートを自分で作り、EmDashのサイトマップの代わりに返して対処します。
確かめたのはEmDash 1.3.1です。
末尾スラッシュが消える仕組み
EmDashはURLパターンからURLを作るとき、末尾のスラッシュを必ず外します。付け直すのは、AstroのtrailingSlashが"always"の時だけです。初期設定の"ignore"のままでは、URLパターンに/を書いても消えます。
trailingSlashを”always”にしない
astro.config.mjsにtrailingSlash: "always"を入れると、サイトマップには末尾スラッシュが付きます。しかし開発サーバーでは、管理画面(/_emdash/admin)とAPI(/_emdash/api/〜)が404になりました。Astroのルーティング全体に影響する設定なので、サイトマップのためだけに変えないほうが安全です。
同じパスのルートを作ってサイトマップを差し替える
EmDashのコレクション別サイトマップは、/sitemap-[collection].xmlという動的なルートです。src/pages/sitemap-posts.xml.tsのような固定のルートを作ると、Astroはそちらを優先します。
import type { APIRoute } from "astro";
import { getEmDashCollection } from "emdash";
const escapeXml = (s: string) =>
s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
export const GET: APIRoute = async ({ site, url }) => {
const origin = (site ?? url).origin;
const urls: string[] = [];
let cursor: string | undefined;
do {
// ログインしていない状態で取得するので、下書きは含まれない
const { entries, nextCursor } = await getEmDashCollection("posts", {
orderBy: { published_at: "desc" },
limit: 100,
cursor,
});
for (const entry of entries) {
const loc = escapeXml(`${origin}/${encodeURIComponent(entry.id)}/`);
const lastmod = entry.data.updatedAt ?? entry.data.publishedAt;
urls.push(
`<url><loc>${loc}</loc>` +
(lastmod ? `<lastmod>${new Date(lastmod).toISOString()}</lastmod>` : "") +
"</url>",
);
}
cursor = nextCursor;
} while (cursor);
const body = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">${urls.join("")}</urlset>`;
return new Response(body, { headers: { "Content-Type": "application/xml; charset=utf-8" } });
};
WXRから取り込んだ直後は、updatedAtが取り込みの日時になり、全記事のlastmodが同じ日になります。公開日を出したい場合は、publishedAtを先に見るように順番を入れ替えます。
固定ページ用には、"posts"を"pages"に替えたsitemap-pages.xml.tsを作ります。サイトマップの一覧(/sitemap.xml)は、EmDashのものをそのまま使います。中身はsitemap-posts.xmlとsitemap-pages.xmlへのリンクだけなので、末尾スラッシュの問題は起きません。
載っているURLがすべて200か確かめる
差し替えた後は、サイトマップに載ったURLを全部開いて、200が返るか確かめます。試したサイトでは、公開中の記事20件と固定ページ4件のすべてが200でした。下書きの記事は、サイトマップに載りませんでした。