Markdown 解析、渲染与编辑接入
解释 Markdown 原文、语法树、HTML 和编辑文档之间的转换及安全边界。
一份原文可以走不同管线
Markdown 原文适合文本编辑、版本比较和文件交换。解析器将它转为语法树;后续可以生成 HTML、React 元素、搜索文本或富文本编辑器的 JSON。每个输出保留的信息不同,应先声明 Markdown 方言和要支持的节点。
CommonMark、GFM、数学、脚注和 MDX 具有不同扩展条件。开启 GFM 并不自动开启公式或任意 JSX。解析器支持语法、渲染器支持节点、编辑 schema 能保存该结构,需要分别核对。MDX 含执行能力,适合可信的工程内容;用户提交的普通文本不能不经隔离就当成应用代码编译。
在 React 中,react-markdown 通过语法树创建元素,可以配置 remark 与 rehype 插件;GFM 支持需要对应插件。原始 HTML、插件及自定义组件会改变安全边界。react-markdown README
import Markdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
export function MarkdownView({ source }: { source: string }) {
return <Markdown remarkPlugins={[remarkGfm]}>{source}</Markdown>;
}这是保留默认 URL 处理、未开启原始 HTML 的渲染片段。应用增加链接组件时,要检查是否覆盖安全转换;链接的可访问名称、外部窗口和下载行为也应明确。插件来自可信依赖仍不足以证明它的输出安全。
插件顺序影响语义和安全
通常先解析 Markdown 并处理其树,再转换成 HTML 树,最后生成 HTML 或元素。启用原始 HTML 时,先把它解析到 HTML 树,再按白名单清洗,随后输出。代码高亮及数学插件可能增加 class、style 或额外标签,清洗配置应只允许所需结构。
清洗之后再用不可信输入拼接 HTML,会重新引入风险。Shiki 的高亮输出、KaTeX 的公式输出和原始图片 URL 也需要对应限制,不能因使用某个库就整体跳过信任判断。高亮在浏览器执行会带来初始化与语言加载成本;服务端或构建期生成可以减少客户端工作,但需保留主题和缓存条件。
目录和标题锚点从同一解析结果派生,重复标题、标点和中文需要稳定规则。不要另存一份手工标题列表。原文修改、插件版本或标题算法变化时,相关搜索文本和锚点也需要更新。
原文和渲染结果的保存关系
若 Markdown 是权威表示,保存原文及修订版本;HTML 为缓存,需要由内容和渲染配置共同决定有效性。仅根据正文哈希缓存,可能漏掉清洗白名单、高亮主题或转换器升级引起的变化。
富文本编辑器采用结构化树作为权威表示时,Markdown 是导出视图。往返转换可能丢失图片尺寸、列宽、提示块类型、批注或任意节点属性;只比较“显示看起来相同”无法证明信息保留。为所有受支持节点定义映射,对不能表示的结构说明拒绝、降级或扩展语法。
Tiptap 官方提供 @tiptap/markdown,页面仍标为 beta。其配置包含 Markdown 初始内容、解析与序列化;实际兼容性需固定版本并检查自定义扩展的转换。官方安装说明
import { Editor } from '@tiptap/core';
import StarterKit from '@tiptap/starter-kit';
import { Markdown } from '@tiptap/markdown';
const editor = new Editor({
extensions: [StarterKit, Markdown],
content: '# 标题\n\n正文',
contentType: 'markdown',
});上述片段需要浏览器编辑器环境。是否可以把粘贴的纯文本自动识别成 Markdown,是单独的产品规则:代码、日志和普通星号文本可能被误判。显式“作为 Markdown 粘贴”可以保留用户选择;自动识别则应有可撤销结果和足够样本。
复制、粘贴和长内容
剪贴板可以同时提供纯文本与 HTML,应用专用格式也可携带结构化内容。专用 JSON 应有版本和合法节点检查;整文替换与选区插入具有不同影响。处理同一次粘贴时明确优先级,避免多个插件重复消费事件。
模型流式输出的 Markdown 可能停在半个代码围栏、链接或表格中。可以积累原文并周期性重解析,也可以采用支持增量呈现的路线;最终保存仍需明确完整原文。临时显示应控制布局抖动和计算成本,不把每个网络 chunk 都当成完成的语法单元。
大文档的瓶颈可能是解析、高亮、树大小或 DOM 布局。先测所用内容与语言组合,再决定缓存、分块或延迟高亮。编辑器、阅读器和代码编辑器有不同交互任务,不必为了保持单一库强行共用同一种视图。
检查转换保留了什么
用具有意义的样本检查标题、嵌套列表、表格、链接、图片、代码、数学及未知节点。安全样本包含事件属性、脚本协议、原始 HTML 和超长内容。往返检查要定义等价关系:允许格式归一化时,可以比较语法树和保留属性;要求字节保真时,就不能只比较树。
本页吸收归档 Markdown 渲染与编辑实践,未执行所列管线。原材料的包版本和维护排行是历史数据;采用建议由格式需求、可信内容范围和实际验证决定。
最后更新于