互联网那些技术 | 扒一扒互联网Markdown的那些事儿

最近感觉到 Markdown 似乎已成为各大社区的编辑器标配所支持的格式,侧面看来其设计之初的目标 “ to be used as a format for writing for the web.” 已经成为了现实。不妨就扒一扒互联网 Markdown 的这些事儿。

Markdown 的演进

Markdown 是一种标记语言,对比于 HTML 这样的标记语言来说简洁很多,因此其描述为轻量级的标记语言(lightweight markup language,简称 LML)更为合适。当然,轻量级标记语言并非只有 Markdown,在其之前就有很多种。比如:Setext (Structure Enhanced Text) 用于一些纯文本的场景比如 Email、Usenet(新闻组)等。

请在此添加图片描述

也有能把格式文本转换为HTML类似早期语言 reStructuredText(rST),为了更好的阅读 Python源码和 Python 技术源码而设计。

请在此添加图片描述

Markdown 就是在这样的背景下诞生,在2004年由John Gruber和Aaron Swartz共同创建出来,有兴趣的可以看下最初文章《Introducing Markdown》。 这两个作者也有很多故事,比如Gruber是《The Talk Show》播客节目主持人;Swartz 2013年已经故去,其曾因使用麻省理工颁发给他的访客用户帐户从JSTOR系统下载学术期刊文章,随后被麻省理工院警方以非法闯入的罪名逮捕。

(PS:笔者并非八卦博主就不多赘述了,感兴趣的自行了解)

到了2008年时候 Stack Overflow 的联合创始人 Jeff Atwood 推其成为 Stack Overflow的编辑方式,并且非常认同其设计;也就是这个时候开始大规模的在程序员中流行起来。Github 大概在2009年开始使用 Markdown,并推出扩展版 GitHub Flavored Markdown (GFM)。

2012年,Jeff 提议Stack Exchange、GitHub、Meteor、Reddit 等一些访问量大的公司组织一起制定出 Markdown的标准规范和其实现的标准测试用例。2014年的时候发布了一个Standard Markdown 的项目,不过 Gruber反对使用Markdown的名字,后来最终改成了 CommonMark,其中包含了 600+个测试用例以及 C语言和 JavaScript的实现。

2016年时候 IETF也发布了征求意见稿RFC7763,在media type中定义了 test/markdown 的类型;2017年 GFM基于CommonMark Spec正式发布了 GitHub Flavored Markdown Spec,支持表格、任务列表、禁止HTML等等。

当然到目前 Markdown 演进也远未结束,除开 GFM 其实还有更多的 基于 CommonMark 的扩展,比如微软的 Markdown for Microsoft Learn 有 !NOTE 的扩展语法。

Markdown 解析引擎

Markdown解析引擎也是非常多的,这里主要介绍一些 JavaScript 开源项目。

Showdown

正如演进提到的 2004年的时候,Gruber写了第一个版本的 Markdown 解析引擎 Markdown.pl ; 2007年时候 John Fraser 基于 Gruber的工作成果创建了 Showdown;不过,似乎 Fraser 早已经不再维护了,Corey Innis 将其迁移到了 Github , 从迁移后的提交看 Santos 维护比较多。它除开实现了 Markdown 原始标准外,也支持一些 Atx、Setset的语法规则。比如:# My Heading #等。

基本使用

    
    var showdown  = require('showdown'),
    converter = new showdown.Converter(),
    text      = '# hello, markdown!',
    html      = converter.makeHtml(text);

请在此添加图片描述

Marked

Marked 同样也是非常早的 Markdown解析引擎,Christopher Jeffrey在 2011年最早创建的,目前GitHub上已经 30k+ 的收藏。很多产品都在使用,不过虽然其支持CommonMark以及GFM,但是似乎支持的还不够完整,截至到2022年11月的 V4.2.3 还并没有 100% 支持到两大标准。有个有意思的现象,今年其版本更新非常快 2023年3月份还是 V4.3.0 到如今11月份版本迭代到了 V9.1.5。

基本使用

import { marked } from 'marked';
// or const { marked } = require('marked');

const html = marked.parse('# Marked in Node.js');

请在此添加图片描述

Commonmark

应该说是 Commonmark Spec的亲闺女,John MacFarlane 2014年时候最早创建的,他同时也是标准制定人之一,还是 Pandoc的作者。将Markdown文档解析成 抽象语法树(AST),并通过渲染(AST)转换成 HTML 或者 XML;从笔者测试看其性能非常优异。

基本使用

var reader = new commonmark.Parser();
var writer = new commonmark.HtmlRenderer();
var parsed = reader.parse("Hello *world*"); // parsed is a 'Node' tree
// transform parsed if you like...
var result = writer.render(parsed); // result is a String

请在此添加图片描述

Remarkable 与 Markdown-it

Remarkable 是2014年左右的开源项目,目前已更新很少了;Markdown-it 是 Remarkable 核心两个作者后面开的开源项目,同时借鉴参考了 MacFarlane 的 Commonmark 的一些实现,也是功能、扩展性都非常不错的 Markdown解析引擎 目前有 16.2k 的收藏。

基本使用

var md = require('markdown-it')();
var result = md.render('# markdown-it rulezz!');

请在此添加图片描述

Micromark 与 Remark

Micromark 和 Remark 创建者都是 Titus Wormer(wooorm),14年毕业于阿姆斯特丹大学,同时也是 unified 研发生态的创建者。unified 是一个文本处理库、插件和工具的生态系统,其生态内有500+的开源库,在Github 有1.3m+的项目在使用。

Remark目前就是unified生态中的一员,严格说来它还早于unified,是一个Monorepo风格的管理库,主要包含remark-parse 、remark-stringify、remark、remark-cli ,其功能相信从命名也能看出一二。

  • remark-parse — 用于将Markdown文本转化为语法树(mdast)的插件
  • remark-stringify — 用于将语法树(mdast)转化为Markdown文本的插件
  • remark — 包括unified、remark-parse和remark-stringify,适用于输入和输出都是Markdown的情况
  • remark-cli — 基于remark的命令行界面工具,用于在脚本中检查和格式化Markdown

PS:Markdown Abstract Syntax Tree 简称为 mdast

其中最被广泛使用的是 remark-parse,其解析上也应用了Micromark一些库。

基本使用

// micromark
import {micromark} from 'micromark'
console.log(micromark('## Hello, *world*!'))

// remark
import {unified} from "unified";
import remarkParse from 'remark-parse'
import remarkRehype from 'remark-rehype'
import rehypeStringify from 'rehype-stringify'

console.log(
    unified().use(remarkParse)
    .use(remarkRehype)
    .use(rehypeStringify)
    .processSync("Hellow,*world*").value
);

其他

或许会疑惑为什么没有看到 Tiptap、ProseMirror、React-markdown? Tiptap 围绕 PoroseMirror研发的开源项目,ProseMirror 主要聚焦在富文本编辑器领域 对于 Markdown解析引擎默认使用的是 Markdown-it;React-markdown 聚焦在 React component领域上,Markdown解析引擎用的是 Remark,其实类似还有 Milkdown 等等。而且围绕 Markdown 解析引擎研发的开源项目非常之多,仅 reamrk-parse 在写本文时就有 100w+代码库,2k+ Packages在使用。

请在此添加图片描述

当然受限于笔者知识也必然会有遗漏的Markdown解析引擎,行文见谅。

要用,选哪个?

这个问题比较直接也比较实际,但其实很难一言论断。应当从多方面考虑,比如是否需要100%支持 GFM?是否有自定义扩展语法的需要?自定义扩展语法是否比较复杂?又是否需要兼容Atx之类的写法?是否对性能有很高要求?是否需要使用到 AST抽象语法树?等等;作为一个向往和平与爱的博主,更多的建议还是根据自身需求来选择开源Markdown引擎,其实每一个产品都有自己独特的优劣。

当然什么也不考虑,就只是随意看看,可能 Commonmark 、unified生态会是一个不错的选择。

附上一张文章中提及到的Markdown解析引擎的NPM下载趋势图,可以看到近些年来发展非常迅速,特别注意下其数值大小并非代表项目好坏。客观上说每个项目定位不同、使用范围不同、年限长度不同,其npm上下载量的自然也就不同;根据自身需求来选择合适的Markdown解析引擎最为重要。

请在此添加图片描述

PS:这图为什么每年都有个陡降点?12月25日圣诞节

未来呢?

从大量轻量语言的出现,到 Gruber 和 Swartz 创建 Markdown;从 Jeff 对 Markdown 设计的热爱,推其广泛应用与制定标准 到 Gruber 反对标准使用 Markdown之名;从 CommonMark、GFM的出现,到 ETF征求意见稿发布;还有贯穿其中的各种 Markdown 扩展、应用到各种场景的开源项目,演进到如今不可谓不热闹,颇有一番春秋战国百家争鸣的味道。

即使今天这场“百家争鸣”也还未停息,目前最热的技术莫过于AI、AIGC,ChatGPT 默认显示就是Markdown语法;由于 Markdown 轻量的语法、结构化的文本,助其可能成为了AI时代文本格式的首选之一;此外轻量语言之间仍在相互借鉴,新的扩展语法还在不断涌现,各大开源生态的战场仍在继续书写历史。

但在 Markdown 演进中可以看到标准制定、基础解析引擎整体国内身影较少,但随着国内云社区、开源社区发展日益火热,更多的有志青年投身其中,相信未来也是璀璨的;也或许某天会有 Tencent Flavored Markdown Spec(TFM) 的出现。

欢迎关注 Java研究者专栏、公众号。

posted @ 2023-11-06 10:11  Java研究者  阅读(737)  评论(2编辑  收藏  举报