unified生态下解析markdown
Laeni
2022-02-13
unified是一个使用抽象语法树 (AST) 转换内容的项目。以解析Markdown为例认识和学习unified。
步骤
- markdown ----(remark-parse)----> mdast语法树(markdown 专用语法树)
- mdast语法树 ----(remark-rehype)----> hast语法树(HTML 专用语法树)
- hast语法树 ----(rehype-stringify)----> HTML字符串
语法树
AST:抽象语法树,如 markdown 的抽象语法树是 mdast,html 的抽象语法树是 hast。
esast — JS
hast — HTML
mdast — Markdown
nlcst — 自然语言
xast — XML
处理器列表
其他
remark-rehype - 将 Markdown 转换为 HTML
remark-toc - 生成目录
remark-gfm - gfm(GitHub Flavored Markdown)是Markdown的方言,该插件将生成GitHub风格的HTML
rehype-remark - 将 HTML 转换为 Markdown
rehype-slug - 用于将id添加到标题中,添加后可以通过锚点导航到标题
rehype-document - 将HTML片段(语法树)包装在完整的HTML文档中
unist - 语法树的规范
Unist简介
Unist处理过程:
| .................................. process .................................. |
| .......... parse ...... | ........ run ........ | ....... stringify ..........|
+-------------+ +----------------+
Input ->- | Parser(解析) | ->- Syntax Tree(语法树) ->- | Compiler(编译) | ->- Output
+-------------+ | +----------------+
X
|
+-------------------+
| Transformers(变换) |
+-------------------+
如图所示,使用unist时必须有“解析”和“编译”这两个过程,否则会报错误。
示例
import remarkGfm from "remark-gfm"
import remarkMath from 'remark-math'
import remarkParse from 'remark-parse'
import remarkRehype from 'remark-rehype'
import rehypeMathjax from 'rehype-mathjax'
import rehypeStringify from 'rehype-stringify'
import { unified } from 'unified'
const vfile = await unified()
// 注意,这些插件顺序一般无关紧要,因为 unified 会自动根据插件的定义进行排序,但最终的效果大致类似于下面的顺序
.use(remarkParse) // 【解析】将 Markdown 解析为 mdast 语法树(markdown 语法树)
.use(remarkMath) // 【解析】对 remarkParse 未完全解析的数学公式(这里还是 Markdown 字符串)解析为 hast 语法树
.use(remarkGfm) // 【解析】GitHub 风格的 Markdown 支持(它能解析表格,原理同 remarkMath),如果不使用该插件,需要单独解析表格
.use(remarkRehype) // 【变换】将 mdast 语法树 转为 hast 语法树(HTML 语法树)
.use(rehypeMathjax) // 【变换】将 remarkMath 解析得到的部分特定 hast 语法树(数学公式部分)转换为 SVG
.use(rehypeStringify) // 【编译】hast语法树 -> HTML 字符串
.process('# Title\n\nMarkdown text.\n\nMath: $4=2^2$')
console.log('html: ', vfile.value)
注:React 中使用时一般使用react-markdown库,该库虽然是unified的包装,但是最终输出React组件,而不是普通HTML,这解锁了更多有用的东西,比如可以在Makdown中使用自定义的React组件等。