构建 Markdown 编辑器 (Markflow)
Source: Dev.to
我一直在使用 Markdown 编辑器,既是作为普通用户,也在尝试深入了解它们在底层是如何运作的,尤其是当文档变得更复杂(代码块、数学公式、图表等)时。
作为一次小小的探索,我构建了一个最小化的编辑器来实验这些想法:
这篇文章不是公告,而是对一些实现决策的总结,如果你正在构建类似的东西,可能会有所帮助。
起点
最初的目标很简单:
- 将 Markdown 作为唯一的真相来源
- 支持常见的扩展(代码、数学、图表)
- 避免引入额外的文档格式
从这里开始,大部分工作都围绕编辑的处理方式展开,而不是渲染本身。
使用 Monaco 作为编辑层
编辑器基于 Monaco 构建。这带来了:
- 成熟的文本编辑模型
- 良好的性能特性
- 对选区、撤销/重做等行为的可预测性
与此同时,Monaco 只操作纯文本,而 Markdown 本身隐含结构。如何弥合这两者的差距成为核心问题。
将 Markdown 视为结构
实现并不是把 Markdown 当作单纯的字符串,而是通过解析成 AST 来跟踪其结构。这使得我们可以从以下角度进行推理:
- 块(段落、标题、列表)
- 围栏区域(代码、数学、图表)
- 文档层级
即使是部分的结构感知,也能在编辑混合内容时避免某些类的问题。
同步结构与编辑器状态
核心之一是保持两种表示的同步:
- Monaco 中的文本
- 解析后的 Markdown 结构
这种同步用于:
- 检测光标当前所在的块
- 在不破坏周围内容的情况下应用转换
- 保持渲染结果与编辑器状态一致
这部分仍在演进中,但它定义了大部分内部复杂度。
渲染管线
渲染基于 Markdown 生态系统中的标准工具:
- 通过
highlight.js进行语法高亮 - 通过
KaTeX渲染数学公式 - 通过
Mermaid绘制图表
这些工具作用于解析后的 Markdown,而不是直接作用于原始文本,从而保持职责分离:
- 解析 → 结构
- 渲染 → 可视输出
移动端行为
编辑器设计为在浏览器中运行,不假设只能在桌面环境使用。为此做了一些调整,使其能够:
- 在小屏幕上自适应布局
- 滚动和输入保持可用
- 文档可以在移动设备上查看和编辑
这不是一个独立的移动版——只是同一编辑器针对不同屏幕尺寸的适配。
无后端的共享方式
项目中没有后端。为了实现共享,文档状态可以编码进 URL。打开该链接即可在编辑器中重建文档。
这种方式:
- 不需要存储
- 不在服务器端持久化数据
- 适用于快速共享或示例
它故意保持简单,并受限于 URL 长度,但足以满足轻量使用场景。
结语
该项目主要是一次技术探索,旨在研究如何在内部结构化 Markdown 编辑,同时仍以标准文本编辑器为基础。如果你也在做类似的工作,欢迎提供反馈或讨论。