63 lines
1.8 KiB
TypeScript
63 lines
1.8 KiB
TypeScript
import type { MetadataRoute } from "next";
|
|
import { routing } from "@/i18n/routing";
|
|
import { getAllPosts } from "@/lib/posts";
|
|
import { siteConfig } from "@/lib/site-config";
|
|
|
|
/**
|
|
* 动态生成 sitemap.xml。
|
|
*
|
|
* 覆盖:首页、关于页,以及全部已发布文章(草稿不会出现在这里)。
|
|
* 每个条目都带上 hreflang alternate,帮助搜索引擎理解多语言对应关系。
|
|
*
|
|
* 内容来自数据库,因此 sitemap 也在请求时生成并缓存,
|
|
* 而不是在构建期固化——否则构建之后新增的文章不会出现在 sitemap 中。
|
|
*
|
|
* 注意:Next.js 要求 sitemap 返回绝对 URL。
|
|
*/
|
|
export const revalidate = 60;
|
|
|
|
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
|
|
const posts = await getAllPosts();
|
|
|
|
/** 为一条路径生成所有语言的 alternates */
|
|
const buildAlternates = (path: string) => ({
|
|
languages: Object.fromEntries(
|
|
routing.locales.map((locale) => [
|
|
locale,
|
|
`${siteConfig.url}/${locale}${path}`,
|
|
]),
|
|
),
|
|
});
|
|
|
|
const staticEntries: MetadataRoute.Sitemap = routing.locales.flatMap(
|
|
(locale) => [
|
|
{
|
|
url: `${siteConfig.url}/${locale}`,
|
|
lastModified: new Date(),
|
|
changeFrequency: "daily" as const,
|
|
priority: 1,
|
|
alternates: buildAlternates(""),
|
|
},
|
|
{
|
|
url: `${siteConfig.url}/${locale}/about`,
|
|
lastModified: new Date(),
|
|
changeFrequency: "monthly" as const,
|
|
priority: 0.6,
|
|
alternates: buildAlternates("/about"),
|
|
},
|
|
],
|
|
);
|
|
|
|
const postEntries: MetadataRoute.Sitemap = routing.locales.flatMap((locale) =>
|
|
posts.map((post) => ({
|
|
url: `${siteConfig.url}/${locale}/posts/${post.slug}`,
|
|
lastModified: new Date(`${post.date}T00:00:00Z`),
|
|
changeFrequency: "weekly" as const,
|
|
priority: 0.8,
|
|
alternates: buildAlternates(`/posts/${post.slug}`),
|
|
})),
|
|
);
|
|
|
|
return [...staticEntries, ...postEntries];
|
|
}
|