乐于分享
好东西不私藏

网页里让人像Word一样打字,为什么是前端地狱?ProseMirror作者再出手

网页里让人像Word一样打字,为什么是前端地狱?ProseMirror作者再出手

Wordgard官网:ProseMirror作者做的浏览器内富文本编辑器库

你有没有想过,在网页里让用户像用Word一样打字、加粗、贴图,到底有多难?

听上去像是个小功能。一个输入框而已,无非是敲字、选中、点个加粗按钮。可只要你真在前端里干过这活,就会知道那是一片沼泽。这次让我想起这片沼泽的,是一个消息:Marijn Haverbeke发布了一个新的浏览器内富文本编辑器库,叫Wordgard。这个名字很多人陌生,但它背后那个人和他的前作,你大概率天天在用,只是不知道。

先说清楚,”富文本编辑”为什么是前端地狱

浏览器里想做一个能编辑的文本区域,官方给你的工具叫contenteditable。你给一个div加上这个属性,它就”可编辑”了——用户能打字、能删、能选。看起来很美好。

然后噩梦开始。你按下回车,Chrome生成一个div,Firefox可能给你一个br,Safari又是另一套。用户粘贴一段从Word里复制的文字,塞进来一大坨乱七八糟的内联样式和莫名其妙的标签。你想让”加粗”这个状态可控,可浏览器早年那套execCommand命令行为诡异、各家实现不一,早就被业界判了死刑。更别提中文输入法的组合状态、光标位置、撤销重做——每一样都是坑。

说白了,contenteditable把”渲染”和”编辑”混在了一起,你既拿不到一个干净的数据模型,又管不住浏览器的自作主张。这就是为什么一个看起来五分钟的功能,能耗掉一个团队几个月。

contenteditable背后,是无数浏览器兼容的深坑。图:Markus Spiske/CC0

十年前,有个人决定驯服它

Marijn Haverbeke是荷兰程序员,前端圈里的一个隐形巨匠。他写过《Eloquent JavaScript》,很多人学JS的第一本书就是它;他做了CodeMirror,浏览器里那个能高亮、能自动补全的代码编辑器组件,无数在线IDE、文档站的代码框底层都是它;他还写了Acorn,一个被大量工具链依赖的JS解析器。

2015年前后,他带着做CodeMirror攒下的经验,动手做了ProseMirror,专门去解决富文本这摊事。ProseMirror的思路很关键:它不直接信任浏览器那个乱糟糟的DOM,而是自己维护一份干净的、有明确结构约束(schema)的文档模型,所有编辑操作先作用在这份模型上,再同步到界面。它还内建了协同编辑的支持。

这套东西成了很多产品的地基。它不是那种一装就能用的”傻瓜编辑器”,而是给开发者的一套工具集——你自己决定文档能有哪些结构、支持哪些内容。正因为够扎实、够可控,它被大量做协作和文档类产品的团队拿去当底层。这就是所谓”隐形基础件”的价值:你看不见它,但少了它整个楼就塌了。

如今他推倒重来,做了Wordgard

按官网的说法,Wordgard是一个开源的JavaScript库,实现了一个浏览器内的富文本编辑器,采用MIT许可证。它的定位和ProseMirror一脉相承:不是一个自由的HTML编辑器,而是一套”构建内容编辑器的工具”,让开发者精确控制文档能有什么结构。

有意思的是Marijn自己的说法。他在发布0.1版本的博客里直言,ProseMirror虽然还在维护,但里面有些设计”每次动它我都要皱一次眉”。他没选择打补丁式的向后兼容更新,而是干脆推倒,做了一次”绿地重写”,把这九年攒下来的教训一次性灌进去。

具体改了什么?我挑几处懂行的人会点头的。一是变更表示,ProseMirror那套复杂的step系统被换成了借鉴CodeMirror的做法——一次变更就是一串”保留、替换、更新”的片段,用他的话说,”容易检查、容易推理”。二是内容约束放松了,ProseMirror用正则表达式去校验文档结构,Marijn发现这既坑用户体验,又让写通用的文档处理代码”实在太难”,Wordgard只保留类型约束。三是扩展机制,它吸收了CodeMirror 6那套facet系统,扩展粒度更细,取代了ProseMirror里比较粗糙的插件排序。还有一处很硬核:选区处理,Wordgard”咬牙”几乎全部自己接管了鼠标和键盘的选择行为,连双向文字(比如阿拉伯语从右往左)都自己算,不再把这事甩给浏览器。

一个人二十年,守着“让浏览器好好编辑文字”这一件事。图:Colin/CC BY-SA 4.0

我怎么看这件事

Wordgard现在是0.1版,Marijn说会在0.x待上”至少一年”,边收反馈边打磨。所以别指望它明天就替代ProseMirror,它还有粗糙的边角。真正让我觉得值得写一笔的,是这个人本身。

一个人,二十年,就守着”让浏览器好好编辑文字”这一件看似无聊的事——从CodeMirror到ProseMirror再到Wordgard。他还坚持MIT开源,明确拒绝靠”人为制造稀缺”来收钱,说自己的模式是”给世界提供足够的价值”,靠社区自愿资助活着。他甚至一个人单干,连别人提的代码合并请求都不收,就为了保持设计的干净。

在这个人人追风口、什么火做什么的年头,这种把一件小事做到极致、做够二十年的工匠劲,我是真服。富文本编辑这活儿又难又不出彩,用户永远只会觉得”不就是个输入框吗”。可正是这些没人愿意碰的脏活累活,撑起了我们每天在用的一个个产品。Wordgard能不能成还两说,但有人愿意在这条冷板凳上继续坐下去,本身就挺让人踏实。

资料来源:Wordgard官网(wordgard.net)、Marijn Haverbeke个人博客《Wordgard Release 0.1》、Hacker News讨论。功能与版本状态以官方文本为准。

你做过富文本编辑器吗,被contenteditable坑过没?说说你的看法。