依赖
- astro 5 → 7.3.3,@astrojs/{mdx,react,rss,sitemap,check}、astro-expressive-code
与 @swup/astro 同步升到最新
- 新增 @astrojs/markdown-remark(Astro 7 默认改用 Sätteri 处理器,
本项目依赖大量 remark/rehype 插件,故显式固定回 unified 管线)
内容集合迁移到 Content Layer API(Astro 6 已移除旧 API)
- src/content/config.ts → src/content.config.ts,三个集合改用 glob() loader
- z 改从 astro/zod 导入
- 所有 entry.slug → entry.id;entry.render() → render(entry)
Astro 7 兼容
- 修复 bookshelf-content.astro 里多行 {/* */} 注释导致的 Rust 编译器
"Unterminated regular expression"
- 删除该文件里一处多余的 </div>(旧 Go 编译器会静默纠正,新编译器不会)
- global.css: @import "tailwindcss" → "tailwindcss/index.css"
(Vite 8 不再解析裸包名的 style 条件)
- astro.config.mjs 显式设置 compressHTML: true,保持 v6 的空白处理行为
验证:构建 41 页通过;与线上(Astro 5 构建)对比 39 个 URL 无一丢失,
仅新增新文章 DIY-computer 的 2 个 URL;逐页渲染文本与线上一致;
pnpm build 与 dev server 均正常。
48 lines
1.4 KiB
TypeScript
48 lines
1.4 KiB
TypeScript
import rss from "@astrojs/rss"
|
|
import type { APIContext } from "astro"
|
|
import MarkdownIt from "markdown-it"
|
|
import sanitizeHtml from "sanitize-html"
|
|
import { getSortedPosts } from "@/lib/posts"
|
|
import { homeTitle, site } from "@/data/site"
|
|
|
|
const parser = new MarkdownIt()
|
|
const FULL_CONTENT_LIMIT = 10
|
|
|
|
function stripInvalidXmlChars(str: string): string {
|
|
return str.replace(
|
|
/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F\uFDD0-\uFDEF\uFFFE\uFFFF]/g,
|
|
"",
|
|
)
|
|
}
|
|
|
|
export async function GET(context: APIContext) {
|
|
const posts = await getSortedPosts(true)
|
|
const publicPosts = posts.filter((post) => !post.data.encrypted)
|
|
|
|
return rss({
|
|
title: homeTitle,
|
|
description: site.description,
|
|
site: context.site ?? "https://example.com",
|
|
items: publicPosts.map((post, index) => {
|
|
const content = typeof post.body === "string" ? post.body : String(post.body || "")
|
|
const cleanedContent = stripInvalidXmlChars(content)
|
|
const item = {
|
|
title: post.data.title,
|
|
pubDate: post.data.published,
|
|
description: post.data.description || "",
|
|
link: `/posts/${post.id}/`,
|
|
}
|
|
|
|
if (index >= FULL_CONTENT_LIMIT) return item
|
|
|
|
return {
|
|
...item,
|
|
content: sanitizeHtml(parser.render(cleanedContent), {
|
|
allowedTags: sanitizeHtml.defaults.allowedTags.concat(["img"]),
|
|
}),
|
|
}
|
|
}),
|
|
customData: `<language>${site.lang}</language>`,
|
|
})
|
|
}
|