目前编辑器让我不爽的点
常年在一些在线文档上写一些技术文档,所以没有段落空两格的说法。昨天写读书笔记时心血来潮想尝试一下现在网文的行文风格,使用大量的段落,然后每个段落都空两格。
预览之下竟然每个段落都被渲染成了 code 模块。
于是进行排查,typecho 使用的是 hyperDown 的 MarkDown 解析器,在 hyperDown 的语法解析中就是会将 4 个空格解析成一个 code 模块。如果想要解决这个问题可以直接以两个全角的空格代替。但是呢在 mac 上似乎没有快捷的输入方式(也可能是我不知道)。
这种隐式的语法和解决方式当然让我很不爽。我想让自己主题的编辑器更加现代,能力更强,扩展更方便,所有的工能都能在编辑器的工具栏找到,不存在隐式的语法,不会让编写文章的作者在预览时被这些糟心事打得措手不及。
加上本就对于 typecho 默认的编辑器能力不满足,当即决定扩展 slowcloud 的编辑器的能力,同时想更换掉 hyperDown ,换上一个更加现代的解析器(此时我还没有意识到事情的严重性)。
参考目前社区中成熟方案
要做这样的大工程,第一步当然是参考优秀项目的成熟方案啦。目前大多数在线文档都是所见即所得类型,比如钉钉文档,飞书文档,Notion 等,但是在博客领域这种交互形式并没有必要,还会带来不必要的复杂度。在博客领域据我所知 Joe 的编辑器就非常优秀,有着丰富的自定义能力,同屏预览能力也是在线的。
Joe 的编辑器使用的是 codemirror 6,令我讶异的是它依然使用的是 hyperDown 的解析器,解析器会将 Markdown 的语法解析成对应的 Html。自定义的一些语法,会在这一步被解析成一些自定义的标签。这个 Html 是所谓的服务端渲染的产物,爬虫能拉到的也是这个。那些自定义标签在前端会被 js 替换成对应的自定义组件,以实现了自定义组件的扩展。
Joe 在实时预览时当然不能再使用 php 运行的解析器,而是使用了 hyperDown.js 解析器进行解析,解析成 Html,这个 Html 也是包含了自定义标签,然后使用 js 替换对应的自定义组件。
看到 Joe 的实现,直觉上让我觉得有问题,文章真实渲染和实时预览分别采用 php 版的解析器和 javascript 版的解析器,如果这其中解析出现些许的不同就会导致实时预览和最终渲染出现差异,这时不能够接受的,所以在后续我的设计中这个解析器必须是被统一的。
我的设计
Markdown 原文
↓
Remark Parser
↓
MDAST(Markdown 语法树)
↓
自定义语法插件:把自定义语法变为自定义节点
↓
Remark/Rehype 转换
↓
HTML AST
↓
HTML / DOM- 在我的设计中我决定编辑器也是使用 codemirror 6(mirror系列的能力,无需多言),codemirror 只负责用户的编辑体验,工具栏设计这些,最终的产物是 Markdown 文本
- Remark 负责将 Markdown 文本解析成为 AST,过程中使用自定义语法插件,将自定义语法设计为 MDAST 自定义节点
- 使用 Remark/Rehype 进行 AST 到 HTML 的转化
- 使用 DOMPurify 对于 HTML 进行安全性处理
将 2,3,4 抽象出来,那么真实文章和实时预览就能使用同一个解析器和渲染器,那从根本上解决了预览和真实渲染可能不一样的问题,并且这个解析器和渲染器我还能抽到其他的地方,比如说可以作为一个本地的 Markdown 文本编辑器的内核。
遇到的问题
理想很丰满,现实很骨感。
但在整个方案实施之际我却想到了一个问题,如果真实文章采用 js 进行解析和渲染,这会严重的影响文章的 SEO ,这时不可接受的。
但是我依然不想使用破坏目前的设计,在这个前提下 php 渲染文章之际,调用 Node 去运行 js 的解析器和渲染器,这个方案是可行的,流量小的小站是没有问题的,一旦流量起来百分百成为瓶颈。那只能常驻一个 Node,但是 slowcloud 作为一个开源的博客主题,显然这是不合适的。
没有更好的解法,这也不赖 typecho 使用的是 php 为开发语言,因为即使采用 java、Go、python等等等开发,会有一样的问题,现代工程应用中应该会有大量与我相同的痛点吧。
脑中突然闪现如果使用的是 Next.js 或者 Nuxt.js 开发,是不是一切的一切都没有问题了。Next.js、Nuxt.js 真的是太太太太太伟大了!!!!怎么还没一统世界。