从 Quill 到 ProseMirror,3年富文本编辑器经历教会我的架构思维—— 以及我怎么用它做出了一个 SaaS 模板

0 阅读3分钟

三年前,我接手了一个基于 Quill 二次开发的富文本编辑器项目。

当时觉得没什么,Quill 生态成熟,改改样式、加几个自定义功能, 应该不复杂。

然后我遇到了表格。


Quill 的表格是噩梦

富文本里的表格,看起来是个普通功能,做起来是另一回事。

核心问题出在 diff 层面: Quill 的数据模型是线性的 Delta 格式, 表格天然是二维结构——行、列、合并单元格、跨行跨列……

线性模型去描述二维结构,diff 的时候会出现严重的语义丢失。 用户改了一个单元格,diff 算法可能把整行都标记为变更。 协作场景下,冲突合并几乎是不可预测的。

修了几个月,越修越深,最后结论是: Quill 的架构天花板到了,绕不过去。


换到 ProseMirror,重新理解"模型"

迁移到 ProseMirror + Tiptap 之后,第一感受是:陡峭。

ProseMirror 没有 Quill 那种开箱即用的便利感, 它要求你先定义 Schema——文档的数据结构长什么样, 节点之间的关系是什么,哪些操作是合法的。

但正是这个设计,让我第一次认真思考:

一个系统,应该从数据模型开始设计,而不是从 UI 开始。

ProseMirror 的插件系统也是一次认知刷新: 每个插件只做一件事,通过 State、View、Transaction 层层传递, 插件之间不直接通信,边界清晰,可以独立替换。

表格问题在新架构下迎刃而解—— 因为表格节点在 Schema 里是一等公民,diff 在模型层做, 语义是准确的。


这套思维用到了 SaaS 开发上

去年我开始做独立产品。

第一次搭 SaaS 基础设施的时候,我发现了一个熟悉的问题: Auth、支付、部署、邮件、存储……每个模块耦合在一起, 改一个牵一发动全身。

这和当年 Quill 表格的问题本质上一样: 架构没有在一开始给每个模块清晰的边界。

所以我从设计层面重新想这件事:

  • Auth 是独立模块,替换 provider 不影响其他层
  • 支付网关可以在 Stripe 和 Creem 之间切换,业务逻辑不动
  • 部署目标(Cloudflare Workers / Vercel / Docker) 在同一套代码里,通过 adapter 层隔离,一行配置切换

这套模块化设计,就是我做编辑器时学到的那套思维的直接迁移。


最后做成了 MuseMVP

把这套设计打包成了一个 Next.js SaaS 启动模板,叫 MuseMVP。

不只是代码,是一套可以复用的架构决策: 每个模块职责清晰,可以独立替换, 整体结构对 AI 辅助开发也足够友好。

目前已经有 14 个开发者在用它上线产品了。

如果你也在做独立产品,或者对 SaaS 架构设计感兴趣, 欢迎去看看 musemvp.com/

也欢迎在评论区聊—— 你在做富文本或者系统设计的时候, 遇到过哪些让你重新理解架构的时刻?