Synth Daily

我们为什么还在用 Markdown?

Markdown 是一种简洁的标记语言,但其语法模糊、多种写法导致输出不一,并且支持内嵌 HTML 带来了复杂的解析和严重的安全隐患。由于缺乏明确的规范和构建系统,它难以满足现代复杂文档的需求。更好的解决方案是开发一种语法明确、易于解析、并支持编译钩子的新型标记语言,以克服 Markdown 的根本性缺陷。

优点:简洁易用

Markdown 的初衷是成为一种用于排版简单文档的极简语言,核心任务是将 Markdown 文件输出为 HTML 文件。

  • 语法可读性强: 它的语法非常直观,即使没有任何辅助工具也易于编写。
  • 输出可预测: 对于基础用法,用户可以预见最终的输出,例如 **粗体** 总是会变成 <b>粗体</b>
  • 学习曲线低: 普通用户只需看一眼速查表就能上手使用。

缺点:混乱的设计与安全风险

Markdown 存在许多糟糕的设计决策,当用户试图深入使用时,会发现它处处掣肘。

这门语言有太多根深蒂固的糟糕决策,以至于当你认为自己掌握了它时,它会立刻开始与你作对。

语法不明确且冗余

Markdown 最大的问题之一是语法不明确。同样的目标可以通过多种不同的语法实现,这导致了混乱和不可预测性。

  • 多种写法,相同输出: 不同的 Markdown 写法可以产生完全相同的 HTML 输出,这违背了“明确”的原则。
  • 混乱的强调语法: 粗体可以通过 **bold**__bold__<b>bold</b> 来实现。不同的解析器甚至支持 _*bold*_ 这样的写法。
  • 安全漏洞: 这种语法的复杂性和模糊性直接导致了被称为 ReDoS(正则表达式拒绝服务) 的漏洞。即使是 markdown-it 这样优秀的库也受其影响,足见问题之严重。

内嵌 HTML:复杂性与风险的根源

Markdown 允许在文档中直接嵌入 HTML 代码,这个特性虽然看似强大,但却是一切问题的核心。

  • 解析极其困难: 为了正确解析 Markdown,解析器不仅要理解 Markdown 语法,还必须内置一个功能完善的 HTML 解析器。这违背了 Markdown “简单”的初衷。
  • 安全噩梦: 允许内嵌 HTML 等同于打开了 XSS (跨站脚本) 攻击的大门。每次我们允许内嵌 HTML、插件钩子或嵌入式执行引擎时,都在扩大攻击面。

如果你本来就在 Markdown 中使用 HTML,为什么不从一开始就直接用 HTML 呢!

过时且令人困惑的语法

Markdown 的语法源自上世纪 90 年代电子邮件和 Usenet 帖子的书写习惯。这种历史遗留导致了许多问题:

  • 冗余的语法: 标题、无序列表、水平分割线等元素都有两种或以上的写法。
  • 语法冲突: 某些语法之间会发生冲突,例如一种水平分割线的写法与一种标题写法会混淆。
  • 上下文依赖: 类似脚注和引用链接的语法,其含义依赖于文档其他部分的定义,这使得纯粹的上下文无关解析变得不可能,极大地增加了复杂性。

我们真正需要的是什么?

现实中,我们对文档工具的需求早已超出了 Markdown 的能力范围。开发者们希望工具能支持 LaTeX、图表(PlantUML, Mermaid)、自定义样式、短代码、标签和分类、脚注和文献引用等。

当我们试图用 Markdown 这个“锤子”来完成“绘画”这样复杂的任务时,只会把“画布”弄得一团糟。

我们需要的不是一个简单的工具来完成简单的工作,而是试图用这个简单的工具来完成复杂的工作,这注定会失败。

解决方案:构建一种新的、更合理的语言

所有现有的标记语言,无论是纯文本、ReStructured Text 还是 MDX,都有其自身的缺陷。最大的问题在于,它们都没有一个正式的构建系统

一个理想的替代方案应该具备以下特点:

  • 禁止内嵌 HTML: 从根本上杜绝相关的安全风险和解析复杂性。
  • 定义明确的短代码和函数: 提供可控的、安全的方式来扩展功能。
  • 支持编译钩子: 允许在编译前、编译中和编译后执行自定义操作。
  • 语法明确且易于解析: 拥有一个为现代需求量身定制的、毫不含糊的语法。
  • 拥有一个构建系统: 像其他编程语言一样,通过正式的构建流程来确保输出的可靠性和一致性。

我们试图将 Markdown 当作一种编程语言来使用,但由于它缺乏正式的语言基础,导致它既不是一个好的标记语言,也不是一个好的编程工具。是时候放弃 Markdown,去寻找一个真正为现代需求而设计的工具了。