45 lines
1.6 KiB
TypeScript
45 lines
1.6 KiB
TypeScript
import { SitemapStream, streamToPromise } from "sitemap";
|
||
import { absoluteUrl, normalizeSiteUrl } from "./url.js";
|
||
import type { SitemapEntry, SiteSeoConfig } from "./types.js";
|
||
|
||
/**
|
||
* 生成 sitemap.xml 字符串(走官方 `sitemap` 包流式序列化)。
|
||
* 异步:stream 需 `streamToPromise` 冲刷。
|
||
*/
|
||
export async function buildSitemapXml(
|
||
site: Pick<SiteSeoConfig, "siteUrl">,
|
||
entries: SitemapEntry[],
|
||
): Promise<string> {
|
||
const stream = new SitemapStream({
|
||
hostname: normalizeSiteUrl(site.siteUrl),
|
||
});
|
||
const done = streamToPromise(stream);
|
||
for (const e of entries) {
|
||
stream.write({
|
||
url: absoluteUrl(site.siteUrl, e.url),
|
||
...(e.lastmod ? { lastmod: e.lastmod } : {}),
|
||
...(e.changefreq ? { changefreq: e.changefreq } : {}),
|
||
...(e.priority !== undefined ? { priority: Math.min(1, Math.max(0, e.priority)) } : {}),
|
||
...(e.alternates?.length
|
||
? {
|
||
links: e.alternates.map((alt) => ({
|
||
url: absoluteUrl(site.siteUrl, alt.href),
|
||
lang: alt.hreflang,
|
||
})),
|
||
}
|
||
: {}),
|
||
});
|
||
}
|
||
stream.end();
|
||
const xml = await done;
|
||
return String(xml);
|
||
}
|
||
|
||
/** 常用:从路径列表生成 entry(默认 priority/changefreq 可覆盖)。 */
|
||
export function pathsToEntries(paths: string[], defaults?: Partial<SitemapEntry>): SitemapEntry[] {
|
||
return paths.map((p) => {
|
||
const { url: _u, ...rest } = defaults ?? {};
|
||
return { ...rest, url: p };
|
||
});
|
||
}
|