我们写的不是同一个 Markdown

Markdown 语法简单, Markdown 被广泛采用… 但是 Markdown 有一些不那么美好的地方.

我们写的不是同一个 Markdown

Markdown是一种轻量级标记语言,创始人为约翰·格鲁伯(英语:John Gruber)。它允许人们“使用易读易写的纯文本格式编写文档,然后转换成有效的XHTML(或者HTML)文档”。这种语言吸收了很多在电子邮件中已有的纯文本标记的特性。

Wikipedia

没有明确的规范

Markdown 的一大设计原则是可读, 即使不做渲染, 也可以简单的阅读原文. 相应的, Markdown 在能力上就孱弱一些. 另一方面, 作者并没有给出一个明确的标准–关于 Markdown 的解释器如何实现. 对更多功能–比如表格–的需求, 催生了不同的实现. 结果就是在某一平台上可用的 Markdown 内容, 在另一平台上可能有一些微妙的差异… 同时, 前面提到, Markdown 本身没有明确的规范, 所以你并不能简单的丢出一个语法错误.

在这个基础上, 曾经有一伙人在一起搞了个 Standard Markdown, 后来变成了 Common Markdown, 似乎就是现在的 CommomMark. 他们给出了一套明确的规范和严格的语法, 并且给出了一组测试工具用于检测 Markdown 内容的正确性.

再后来, Github 发布了基于 CommonMark 的 GFM(Github Flavored Markdown), 在原有的基础上支持了 Checklist 等特性.

目前诸多 Markdown 解释器对不同的规范大都有支持, 并且允许通过配置来切换不同的特性, 没有明确的规范这一大问题多少是有所缓解了.

不可扩展

但是你现在拎出任意一个规范, 比如说 CommonMark 或者 GFM 吧. 你要怎么在现有的基础上进行扩展, 比如说我的图片不想生成为 p > img 的形式, 我需要用 figure 嵌套 img, 并且追加一个可选的 caption 字段以生成 figcaption 元素. 目前来, 除非直接写 HTML 代码, 不然是没有一个明确的方案来解决的, 除非你对解释器进行修改, 但是一跨平台就不行了.

当然不同的平台多少给出了一些方案来解决这个问题, 就以 Hugo 为例. 你可以在 template 中用 replaceRE 方法对 .Content 中的标签进行一遍替换, 这个站点目前是这样做来实现的, 将 p > img 替换为 figure > picture > source + img 的形式, source 中提供 WebP 图片, img 中提供 fallback. 并且拿 alt 的内容作为 figcaption. 但是实现这个需求要写一堆混杂着 \" 的并且没有换行和缩进的 HTML 代码–正则表达式需要.

当然 Hugo 也是给了另外一个方案的, shortcodes. 就是写一些 Hugo 私有的语法 {\{< webp "image.png" "some alt txt" >}}(这里的斜杠是多余的, 不过不敲一个就会被解析为图片), 渲染是替换为预先定义好的模版, 模版里边随便你怎么写. 你甚至可以针对不同的输出格式给出不同的 shortcodes 模版, 比如默认的 HTML 和 AMP. Hugo 给出了一个相当强大的 figure 实现支持了似乎有十多个属性, 随便你怎么对图片进行定义. 另外还实现了了像是 YouTube 这种嵌入式内容, 以及支持高亮具体行数的代码块. 这个方法的话不用写一大串逻辑, 而且扩展性灵活性都很强. 类似的实现还有 vuepress, 可以在 Markdown 中写 vue 组件.

这确实是一个很不错的方法, 但可惜不能通用. 个人平时会用 或者 VSCode 来写内容, 前者是一个在线的 Markdown 编辑器, 内容保存在第三方云存储比如 Google Drive, 可以直接发布到 Github 可以实现云写作; 后者是大家耳熟能详的编辑器. 这两个工具, 以及其它大家得心应手的 Markdown 编辑器, 比如 Typora, MWeb 可没有对应的实现呐, 一个结果是, 脱离了 Hugo 之后, 图片这些内容就不能直接预览了.

当然这已经脱离 Markdown 的设计初衷了, 但是需求总是有的, Web 也在不断发展. HTML 现在还有 details / summary 这对标签, 以及 cite, time 等等. 使用他们能够带来更好的语义化, 或者展示效果. 而且还有直接写 HTML 代码这个方案, 只是繁琐了点.