refactor: Markdown 管线迁移到 Sätteri(Phase 1 + Phase 2)
把 markdown.processor 从 unified() 换成 Astro 7 的默认管线 satteri(),
并把原来 12 个 remark/rehype 插件逐一移植到 Sätteri 的 MDAST/HAST 插件模型。
内置能力直接替代(零代码)
- remark-math → features.math
- remark-directive → 未启用(见下)
- rehype-slug → satteriHeadingIdsPlugin()
新增 src/plugins/satteri/(6 个插件,约 200 行)
- reading-time.mjs after 钩子写 ctx.data.astro.frontmatter.minutes/words
- excerpt.mjs 取第一段写 frontmatter.excerpt
- shift-headings.mjs 工厂按 fileURL 判断,只对 posts 下的文章生效
- sectionize.mjs remark-sectionize 的等价实现(递归分组 + data.hName)
- autolink-headings.mjs 标题锚点,输出与 rehype-autolink-headings 逐字一致
- image-lightbox.mjs 上一版 rehype 图片灯箱的 HAST 版
删除(已迁移或本就无效)
- remark-reading-time / remark-excerpt / remark-shift-headings /
remark-directive-rehype / rehype-component-admonition /
rehype-image-lightbox —— 共 6 个旧插件文件
- 未启用 features.directive:内容里的 `::: tip`(冒号后有空格)和
`> [!tip] Tip` 在迁移前后都渲染成普通段落/引用,属于死语法;
保持现状以免升级顺手把它激活。
行为对齐
- smartPunctuation: { dashes: false } —— Astro 的 unified 管线会把直引号
排成弯引号但不转换 ---,Sätteri 默认会转,显式关掉 dashes 才能逐字一致。
验证(与 unified() 构建逐页对比,41 页)
- 正文 HTML 完全一致 35 页;把 HTML 实体和表格对齐写法归一化后,
只剩 3 页有差异:1 页是 KaTeX 尚未迁移(见下),2 页是中文/emoji 旁的
引号方向(Sätteri 的结果更正确)。
- meta description 仍由 excerpt 正确生成;阅读时长与基线一致。
- astro check:1 error / 0 warnings,与迁移前完全相同(原有 footer.astro 报错)。
- pnpm build 41 页通过;dev server 正常。
尚未迁移
- KaTeX:Sätteri 的 math 只负责解析,不渲染。数学公式目前落成
<code class="language-math">,是可见的回归,Phase 3 处理。
- package.json 里 remark-*/rehype-* 依赖暂未清理,等 Phase 3 确定后再收。
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
import { defineMdastPlugin } from "satteri"
|
||||
import getReadingTime from "reading-time"
|
||||
|
||||
/**
|
||||
* 把阅读时长写进 frontmatter(minutes / words)。
|
||||
*
|
||||
* 页面侧通过 render(entry).remarkPluginFrontmatter 读这两个值,
|
||||
* 与 unified 时期完全一致,所以 posts/[...slug].astro 不用改。
|
||||
*/
|
||||
export const readingTime = defineMdastPlugin({
|
||||
name: "reading-time",
|
||||
after(root, ctx) {
|
||||
// 与原实现 mdast-util-to-string 的默认行为对齐
|
||||
const text = ctx.textContent(root, { includeImageAlt: true, includeHtml: true })
|
||||
const stats = getReadingTime(text)
|
||||
const frontmatter = ctx.data.astro.frontmatter
|
||||
frontmatter.minutes = Math.max(1, Math.round(stats.minutes))
|
||||
frontmatter.words = stats.words
|
||||
},
|
||||
})
|
||||
Reference in New Issue
Block a user