BlockNote 调研:开发状态、扩展边界与富文本编辑器选型
AI 参与说明(Agent:Codex):本文根据 BlockNote、竞品官方文档、公开仓库、npm 与公共资助记录整理,覆盖产品概念、维护状态、扩展方式和选型边界。资料核查日期为 2026-10-08;发展前景与选型建议是依据公开证据作出的判断,不是维护承诺或性能排名。运行记录:模型
gpt-6.1-sol,reasoning effortultra,执行入口 Codex Desktop,提供方openai,CLI 版本0.162.0-alpha.2(不代表桌面 App 版本)。
标签整理(2026-10-16,Agent:Codex):本次仅补齐分类标签并核对元数据,未改写或重新校验原文技术结论。运行记录:模型
gpt-6.1-sol,reasoning effortultra,执行入口 Codex Desktop,提供方openai;CLI 版本0.162.0-alpha.17.2(不代表桌面 App 版本)。
资料补充(Agent:Codex):2026-10-08 根据 Laper 官方产品与架构说明补充 Plate 实际采用案例,厘清编辑核心、编辑框架与 CRDT 的职责,并分析其对通用文档与知识库产品的参考价值。运行记录:模型
gpt-6.1-sol,reasoning effortultra,执行入口 Codex Desktop。
BlockNote 值得进入 React 文档、笔记与知识库产品的首轮选型,尤其适合希望快速获得 Notion 风格编辑体验的团队。 它的开发仍然活跃,已有实际下游采用和可核验的持续投入;主要代价是接受 BlockNote 的文档模型、跟进仍在变化的 API,以及为部分高级功能承担 XL 许可成本。
它并没有在所有场景胜过 Tiptap、Plate 或 Lexical。若编辑器本身是产品核心、需要很大范围改变文档结构和交互,Tiptap 或 Plate 可能更合适;若主要需求是审阅、Office 文档处理和企业支持,也应评估 CKEditor 5。本文先厘清各技术的角色,再看维护证据、文档模型与使用方式,最后给出同条件比较方法。
| 英文术语 | 中文名称 | 简要解释 |
|---|---|---|
| Block | 内容块 | 段落、标题、图片等可独立操作的文档单元 |
| Inline Content | 行内内容 | Block 内的文字、链接或提及等内容 |
| Schema | 结构定义 | 约束文档支持哪些内容类型、属性和样式 |
| Extension | 扩展 | 增加快捷键、输入规则或编辑行为的模块 |
| Headless | 无预设界面 | 提供编辑逻辑,界面由应用自行组合 |
| ProseMirror | 保留原名 | 管理结构化文档、选区与编辑事务的底层工具集 |
| Slate | 保留原名 | 管理文档树、选区与编辑操作的编辑框架 |
| Tiptap | 保留原名 | 基于 ProseMirror 的扩展式编辑器框架 |
| Plate | 保留原名 | 基于 Slate 的 React 编辑框架,提供插件与可选 UI |
| BlockNote | 保留原名 | 基于 Tiptap / ProseMirror 的 Block 编辑器,提供默认 UI |
| Yjs | 保留原名 | 用于共享文档状态和合并并发修改的库 |
| Loro | 保留原名 | 提供 Text、Map、Tree 等共享数据类型的 CRDT 引擎 |
| CRDT | 无冲突复制数据类型 | 让不同副本的并发修改按规则合并的数据机制 |
| Editor Binding | 编辑器适配层 | 在编辑器模型与 CRDT 数据模型之间转换修改 |
| Provider | 同步连接层 | 在客户端、服务器或本地存储之间传递 Yjs 更新 |
| XL Packages | 高级功能包 | BlockNote 采用 GPL-3.0 / 商业双许可证的功能包 |
先分清角色:编辑层与协作层
Slate、ProseMirror 回答“编辑怎样发生”;Plate、BlockNote 提供更完整的编辑框架与体验;Yjs、Loro 回答“多个副本的修改怎样合并”。 这些技术跨越不同层级,不能作为六个平级的编辑器比较。
| 技术 | 所在层与主要职责 | 应怎样理解 |
|---|---|---|
| ProseMirror | 编辑核心:Schema、文档、选区、编辑事务与视图 | 构建编辑器的底层工具集;产品交互可以直接开发,也可以通过 Tiptap 等框架组合 |
| Slate | 编辑核心:文档树、选区、编辑操作与结构规范化 | 与 ProseMirror 属于不同的编辑核心体系;Plate 建立在其上 |
| Plate | Slate 上的 runtime、React bindings、headless plugins 与可选 Plate UI | 提供可组合的编辑框架;不仅是 Slate 的界面皮肤 |
| BlockNote | Tiptap / ProseMirror 上的 Block 模型、API、扩展与默认 UI | 以完整 Block 编辑体验为出发点,替应用承担更多菜单、拖动与结构组织工作 |
| Yjs | CRDT 共享数据类型、增量更新与并发合并 | 可与多种编辑器结合;网络传输、持久化和业务权限需要配套接入 |
| Loro | CRDT 共享 Text、Map、List、Tree 等数据及并发合并 | 与 Yjs 属于同一层的候选,也可以用于编辑器以外的共享状态 |
职责依据:ProseMirror Guide、Slate Editor、Plate Introduction、BlockNote Introduction、Yjs、Loro。
两条编辑器依赖链
BlockNote 的依赖关系包含一个容易遗漏的中间层 Tiptap。Tiptap 把 ProseMirror 的能力组织为 Extensions、Nodes、Marks、Commands 等接口;BlockNote 再提供自己的 Block 模型与界面。
flowchart TD
U[文档或知识库产品] --> B[BlockNote<br/>Block API / 默认 UI]
B --> T[Tiptap<br/>Extensions]
T --> P[ProseMirror<br/>文档 / 选区 / 编辑事务]
Plate 的另一条依赖链是:
flowchart TD
U[文档或知识库产品] --> P[Plate<br/>插件 / React / 可选 UI]
P --> S[Slate<br/>文档树 / 选区 / 编辑操作]
图中表示依赖与抽象关系,不是每次按键的精确调用栈。BlockNote Introduction、Tiptap Overview、Plate Introduction
例如用户选择一段文字并加粗:菜单按钮属于界面;选中了什么、怎样表达加粗、文档怎样更新,属于编辑核心及其扩展。ProseMirror 的 EditorState 通过 Transaction 更新;Slate 的 Editor 保存文档树、选区与 operations。这些本地编辑变更本身不等于已经完成多人合并的 CRDT 更新。ProseMirror Guide、Slate Editor、Slate Operations
Slate 官方称其为 schema-less core,但它仍有内置结构约束,并允许扩展 normalizeNode。不能把两者简化为“ProseMirror 有规则,Slate 可以任意保存 JSON”。Slate Normalizing
CRDT 通过适配层连接编辑器
Editor Binding 把插字、删字、节点移动等编辑动作转换为共享数据操作,并把远端更新映射回编辑器;Yjs 的连接 Provider 则传递这些更新。网络服务、持久化和访问授权仍各有职责。Yjs Editor Bindings、Yjs Connection Providers
flowchart TD
E[编辑器<br/>输入、选区与文档结构] <-->|转换本地与远端修改| B[Editor Binding<br/>编辑模型与共享模型适配]
B <--> C[CRDT 共享状态<br/>Yjs 或 Loro]
C <-->|交换增量更新| N[同步通道 / 服务<br/>持久化与服务端授权]
这是职责示意图;具体实现可能采用 WebSocket、WebRTC 或其他传输与存储组合,并不要求所有更新先经中心服务器。Yjs 的数据合并机制与网络方式解耦。Yjs
这些组合也不是固定配对:BlockNote 有官方 Yjs 集成,Plate 也有官方 YjsPlugin;Laper 使用 Plate 与 Loro 的桥接方案。因此不能把“BlockNote 对应 Yjs、Plate 对应 Loro”当成生态规则。跨引擎替换需要重做或核验适配、数据迁移和同步协议。BlockNote Collaboration、Plate Collaboration、Laper Collaboration
用两个人改一句话理解合并粒度
假设两人都从“今天开会”开始,甲插入“下午”,乙在句尾插入“讨论方案”。编辑器处理各自的输入与光标;适配层将动作转换为共享 Text 的插入操作;CRDT 按其规则合并;同步通道交换更新。收到相同更新后,两份数据应收敛,而最终句子是否符合写作意图仍需使用者判断。
若应用把整段当普通字符串字段,每次都用完整新值替换,合并语义就不同:甲提交“今天下午开会”,乙提交“今天开会讨论方案”,可能按字段冲突规则只保留一个值。Loro 本身支持字符级 Text 合并。 官方文档直接比较了 LoroText.insert 与 LoroMap.set 保存字符串的不同结果;后者采用 Last-Write-Wins,不能理解成“哪个网络包最后到服务器就赢”。Loro Text、Loro Map
因此,判断协作质量需要同时看编辑器 Schema、CRDT 数据类型和适配方式。Laper 公布的同段落替换取胜,是其具体桥接与操作粒度的边界,不能推导为 Loro 只能合并段落;同样,换成 Yjs 也不会自动让整段覆盖变成逐字合并。Laper Collaboration
对文档与知识库产品,建议先比较 BlockNote 与 Plate 的编辑模型和定制成本,再检查所需协作绑定。若优先快速获得标准 Block 体验,可先验证 BlockNote 与配套 Yjs;若需要大范围控制 React 交互,可验证 Plate,协作仍可选官方 Yjs 路径。Loro 也值得评估,但采用它的理由应落在数据模型和具体集成能力上,而不是只因为 Laper 使用了它。
开发状态:活跃,但还不能按稳定平台对待
版本与维护节奏
截至整理日,GitHub 最新正式 Release 与 npm @blocknote/core 的 latest 都是 0.55.0,发布于 2026-09-22。按 GitHub Releases API 的 published_at 统计,2025-10-08 至 2026-10-08 之间有 34 个非草稿、非 prerelease 发布;这是项目 Release 数,不是把每个 npm 子包重复计算。v0.55.0、Releases API、npm metadata
这个节奏说明项目持续有人投入。比“有多少 Star”更有用的是观察最近版本修了什么、是否标明迁移路径,以及下游能否跟上升级。近期已有两次明显的接入变化:
- 0.52.0 拆分 Yjs 协作接入。 当前文档用
@blocknote/core/yjs的withCollaboration包装编辑器选项。官网首页在本次核查时仍展示直接传collaboration的旧片段,因此复制首页演示代码时应再对照版本和参考文档。v0.52.0、Real-time Collaboration - 0.53.0 的 shadcn 集成从 Radix 改为 Base UI。 对已有菜单、主题或底层组件定制的项目,这类依赖变更需要实际回归,不能只看 TypeScript 编译通过。v0.53.0
本文判断:BlockNote 已超出早期概念演示的阶段,但仍需要按快速演进的 0.x 产品管理升级。 不应因版本号小就否定生产采用,也不能因发布频繁就假设接口长期兼容。建议锁定同一版本的 @blocknote/* 包、保存 lockfile,并把自定义 Schema、粘贴、撤销和协作列入升级回归。
近期工作也包含实际能力改善:0.55.0 将移动 Formatting Toolbar 从 experimental 转为 supported;0.54.0 增加 Math / Diagram 相关能力;0.54.1 包含按 changed range 处理修改的性能优化与 Typst 导出路径。方向覆盖移动体验、技术内容、性能和输出质量,已经不只是补齐基础菜单。v0.55.0、v0.54.0、v0.54.1
真实采用与持续投入
法国 DINUM 的协作文档项目 Docs / La Suite Docs 在公开代码中采用 BlockNote。它是比官网客户 Logo 更具体的证据:能够查看应用依赖、接入代码和维护讨论;但单个下游的使用不能证明所有移动端、文档规模和权限模式均适用。Docs 依赖源码
OpenProject 也在公开依赖中使用 BlockNote,并维护独立的 op-blocknote-extensions。这既增加了真实采用证据,也提供了深入扩展的参考;它不能直接证明自己需要的扩展可无成本复用。OpenProject 依赖源码、OpenProject extensions
NLnet 的 NGI0 Entrust 项目页面记录了 BlockNote 的早期支持。更近的欧盟 ELFA 项目在 CORDIS 列出的周期是 2026-06-01 至 2029-05-31,参与方 OpenBlocks B.V. 的 Net EU contribution 为 €376,368.75。这笔金额是该公共项目中的资助记录,不能写成公司融资、收入或利润。NLnet BlockNote、CORDIS ELFA
官网自述为独立、bootstrapped 团队,公开商业路线包括 XL 订阅和企业定制支持。BlockNote、Pricing
据此,对其中期发展前景可以保持审慎乐观:底层技术有生态支撑,下游有真实需求,投入来源不只有个人兴趣。但公共资助与订阅方案不能证明现金流、团队规模或盈利,也不能构成 2029 年之前所有功能都有人维护的保证。采购支持时,应核对当前合同,而不是从资助期限推导 SLA。
维护集中度仍应关注:本次 GitHub Contributors API 的两页记录中,前三位贡献者约占累计 contributions 的 78%。口径含机器人记录,是 GitHub 归属的累计提交数,不代表工时、审阅或近期投入,也不能直接换算成团队人数。它提示长期选型需要关注核心维护者的持续参与,而不能只看贡献者总数。Contributors API、第二页、About
问题记录怎样解读
本次发现的具体风险信号包括:
| 记录 | 已核验情况 | 选型时的含义 |
|---|---|---|
| #3135 / PR #3136 | 0.55.0 被报告在另一客户端光标存在时,接受 / 拒绝 AI 修改出现 nodeSize 错误;核查时修复 PR 尚未合并 | 同时启用 AI 与协作,要专门测试双方在线时的接受、拒绝与撤销 |
| #2244 | 协作撤销问题的讨论涉及 React 19 StrictMode 与 Provider 生命周期 | 用实际应用的生命周期测试协作,不把一次单人演示当验收 |
| #2994 | iOS 自定义 React Block 冻结报告仍开放,但评论已反馈 0.54.0 的最小复现可用,维护者也指出相关修复 | 不能写成“最新版仍在 iOS 冻结”;应使用当前版本与自己的 Block 在真机重测 |
开放 Issue 是调查入口,不等于所有使用者都会遇到的问题。本文没有在真实 iOS / Android、中文输入法或多人服务器上复现这些报告,也没有执行跨编辑器性能基准。
产品概念与能力范围
BlockNote is a block-based rich-text editor with a ready-made UI, built on Tiptap and ProseMirror. Introduction
开发者把它嵌入自己的 Web 应用,用户在应用里编辑内容。它主要面向 React,也允许高级使用者通过核心 API 自建 vanilla JavaScript 界面。它提供编辑器这一层;账号、文档列表、访问权限、媒体存储、搜索与发布工作流仍由应用维护。
| 范围 | 当前提供什么 | 应用还要完成什么 |
|---|---|---|
| 基础编辑 | 段落、标题、列表、待办、代码、引用、表格和媒体等 Block;拖动与嵌套 | 针对自己的内容模型设置允许类型和交互 |
| 编辑界面 | Slash Menu、Formatting Toolbar、链接与文件面板等 | 品牌样式、复杂布局和业务命令 |
| 自定义内容 | Custom Blocks、Custom Inline Content、Custom Styles | 数据定义、渲染、导入导出与迁移 |
| 实时协作 | Yjs 集成、协作光标;可选择不同 Provider | 网络服务、持久化、身份与服务端授权 |
| Comments | 线程、回复、反应及 ThreadStore 接口 | 用户解析、存储与可信的权限控制 |
| 格式互通 | BlockNote JSON、专用 HTML;普通 HTML / Markdown 有损转换 | 接受哪些损失、如何发布与迁移 |
| XL | AI、多列布局、PDF / DOCX / ODT 等导出 | 许可、模型调用和导出质量验证 |
能力来源:Built-in Blocks、UI Components、Custom Schemas、Comments、Format Interoperability。
需要注意两项成熟度边界:AI 文档仍标为 early preview;官网把 Suggestions & Versioning 标为 coming soon。能对 AI 输出接受 / 拒绝,不等于已经具备完整的人类 Track Changes 或可采购的文档版本历史。AI Integration、BlockNote homepage
它的 Table 是文档内容,不能据此推导出 Notion Database、关系视图、公式和完整项目管理能力。Office 导出也不能理解成任意 Word 文档无损导入和往返编辑;官方格式表需要逐项读。
文档模型与协作接入
前面的依赖图说明了分层;接入应用时,更具体的约束在于文档怎样保存、扩展类型怎样传播,以及协作状态怎样持久化。
文档不是一串 HTML
一个 Block 有稳定的 id、type、props、content 和 children。例如标题可通过 props.level 表达级别,段落的 content 保存 Inline Content,嵌套列表通过 children 表达。Table 的内容结构又与普通段落不同。Document Structure
这样做的价值是,应用可以直接操作“这一段”“这个附件”“这个业务卡片”,而不用靠解析任意 HTML 判断其身份。需要同步维护的代价是 Schema:一篇包含 notice Block 的文档,消费它的编辑器和发布端都必须知道 notice 是什么。
BlockNote JSON is the recommended lossless storage format; standard HTML and Markdown conversions are lossy. Format Interoperability
因此,如果项目要求保留 Markdown / MDX 源码里的表达式、组件调用、自定义语法和排版,应先检查转换能否满足要求。把 Markdown 导入、编辑后再导出,不能自动视为原文件无损往返。适合的组织方式通常是保存原生 JSON,另生成 HTML / Markdown 阅读副本;需要源文件忠实编辑的产品,则应比较直接编辑源码的方案。
协作、离线与持久化各有职责
接入协作时,应用将 Yjs 文档中的 Fragment 交给 BlockNote,通过 Provider 传递增量更新。官方列出 Hocuspocus、Y-Sweet、Liveblocks、PartyKit、y-websocket 等选择;y-indexeddb 用于浏览器本地持久化。Real-time Collaboration
“支持 local-first”不表示仅安装编辑器就完成离线保存与多设备恢复。完整方案还需要决定:谁能连接某个文档、更新如何持久化、离线状态在哪里保留、备份怎样恢复,以及不同 Schema 版本如何兼容。协作模式下不能用两个客户端最后写入的完整 JSON 相互覆盖,来代替 Yjs 的合并过程。
Comments 的权限边界尤其具体:官方明确说明 ThreadStoreAuth 主要用于显示 / 隐藏界面操作,数据安全仍需服务端校验;直接使用 YjsThreadStore 时,没有合适的服务端限制,用户技术上可能修改他人评论。RESTYjsThreadStore 可以让写入经过后端授权,但这种写入路径不适合要求离线修改评论的 local-first 模式。Comments
可拓展性:业务内容很方便,彻底改变编辑范式成本更高
它提供的扩展面足够覆盖许多知识库和业务文档:
| 扩展点 | 典型用途 | 应核验的边界 |
|---|---|---|
createReactBlockSpec | 提示、图表、附件、业务卡片 | 内容类型、属性、可编辑区域、外部 HTML 与粘贴解析 |
createReactInlineContentSpec | 提及、标签、文档引用 | 显示文本、标识、选区和复制行为 |
| Custom Styles | 自定义文字样式 | 编辑、保存、发布三端一致 |
BlockNoteSchema.create().extend() | 添加类型并保留默认能力 | 旧文档与不同版本客户端可否读取 |
| UI Controllers / Components | 替换菜单、工具栏和插入入口 | 键盘、焦点、浮层、移动端行为 |
createExtension | 快捷键、输入规则、底层编辑行为 | 支持 ProseMirror Plugins 和 Tiptap Extensions,但须满足 BlockNote 模型约束 |
对应文档:Custom Blocks、Custom Inline Content、Custom Styles、Custom Schemas、UI Components、Extensions。
我的评价是:扩展业务内容很强,任意改变文档结构的自由度不如直接使用底层框架。 “能接入 Tiptap Extension”不能推出所有 Tiptap Node、Mark、NodeView 都能不经适配就组合;它们还要符合 BlockNote 的 Block 组织、选区与序列化约定。
开发一个新 Block 也不是把任意 React 组件塞进正文就结束:React 组件实现由代码提供,文档保存的是结构和属性。当前公开的 PropSchema 属性值类型限定为 string、number、boolean,复杂业务对象宜保存稳定 ID、由业务服务解析,或者明确设计版本化序列化;不能假设任意对象都可直接写进 props。Custom Blocks
本文建议的完整开发路径: 先定义类型和属性,再完成编辑渲染、插入入口、保存 / 恢复、只读发布和复制粘贴;最后用旧版文档检查迁移。toExternalHTML 与 parse 分别关系到外部 HTML 输出和导入识别,只有编辑器中“看起来正常”并不代表 Block 可长期使用。toExternalHTML 在独立 React root 中渲染,不能假设它继承应用的 React Context;省略它时会回退到 render,依赖业务 Provider 的组件应准备独立的外部渲染方式。Custom Blocks
使用方式:一个可复制的 React 示例
无需安装即可先体验 官方 Getting Started 与 Custom Blocks 示例。重点操作 / 菜单、拖动、嵌套、文字选区和自定义提示内容,观察是否符合目标产品的编辑习惯。
下面的 TypeScript / TSX 示例在已有 React 客户端工程中使用,包版本固定为 BlockNote 0.55.0,Mantine 8.3.11;@blocknote/mantine@0.55.0 的 peer dependency 接受 React 18 / 19 与此 Mantine 版本。Mantine setup、Package metadata
npm install --save-exact @blocknote/core@0.55.0 @blocknote/react@0.55.0 @blocknote/mantine@0.55.0
npm install --save-exact @mantine/core@8.3.11 @mantine/hooks@8.3.11 @mantine/utils@6.0.22
把下一段作为工程的 App.tsx,由现有 React 入口挂载并运行现有开发命令。它添加一个 notice Block,并用两个按钮演示 JSON 快照保存和恢复。快照只保存在组件内存里,刷新即清空;生产接入应把保存结果写到经过授权的持久化接口。
import { useState } from "react";
import { BlockNoteSchema } from "@blocknote/core";
import "@blocknote/core/fonts/inter.css";
import { createReactBlockSpec, useCreateBlockNote } from "@blocknote/react";
import { BlockNoteView } from "@blocknote/mantine";
import "@blocknote/mantine/style.css";
const createNotice = createReactBlockSpec(
{
type: "notice",
propSchema: {
tone: { default: "info", values: ["info", "warning"] },
},
content: "inline",
},
{
render: ({ block, contentRef }) => (
<aside
data-tone={block.props.tone}
style={{ border: "1px solid #888", padding: 12 }}
>
<strong contentEditable={false}>提示</strong>
<div ref={contentRef} />
</aside>
),
},
);
const schema = BlockNoteSchema.create().extend({
blockSpecs: { notice: createNotice() },
});
export default function App() {
const [snapshot, setSnapshot] = useState("");
const editor = useCreateBlockNote({
schema,
initialContent: [
{ type: "paragraph", content: "试试输入 /、拖动和文字格式。" },
{ type: "notice", props: { tone: "info" }, content: "这是自定义 Block。" },
],
});
return (
<main>
<BlockNoteView editor={editor} />
<button onClick={() => setSnapshot(JSON.stringify(editor.document))}>
保存快照
</button>
<button
disabled={!snapshot}
onClick={() => editor.replaceBlocks(editor.document, JSON.parse(snapshot))}
>
恢复快照
</button>
<pre style={{ whiteSpace: "pre-wrap" }}>{snapshot}</pre>
</main>
);
}
预期结果:出现普通段落和一个提示 Block;编辑后点击“保存快照”,JSON 中可见 type: "notice"、props.tone 与正文;继续修改后点击“恢复快照”,内容恢复到保存时的状态。新增类型出现在 Schema 中不会自动给它建立 Slash Menu 入口,实际产品还应补插入命令。Custom Blocks、Manipulating Content
本次实际验证:在 React 19.2.0、TypeScript 5.9.3 与 Vite 7.1.7 的客户端工程中,以上示例通过类型检查与生产构建;桌面浏览器中确认自定义 Block 可编辑、JSON 保留类型与属性、修改后能恢复快照,控制台未出现错误。本例没有接入多人协作后端,也未完成真实手机或中文输入法组合输入验收。
若只需要默认编辑器,去掉 createNotice 和自定义 Schema,使用 useCreateBlockNote() 即可。持续保存可使用 useEditorChange 读取 editor.document;远程保存还需设计节流、错误反馈和写入顺序,不能把每次键入发一个请求直接当成生产方案。Format Interoperability
界面有 Mantine、Ariakit、shadcn 等接入路径,也能自行组装。已有 UI 框架时应比较样式和依赖成本;选择 Mantine 的示例不代表必须把整个应用迁到 Mantine。内置本地化包含简体中文 zh,通过 dictionary 传入;中文界面与中文输入法的可靠性是两项不同的验收内容。Getting Started、Localization
编辑器界面需要在浏览器端运行。Next.js 的官方指南同时使用 Client Component 与关闭 SSR 的 Dynamic Import;这与服务端内容处理是两件事。服务端可通过 @blocknote/server-util 的 ServerBlockNoteEditor 转换文档和 Yjs 状态,但具体运行时及自定义 React 渲染需要单独验证,本文未验证 Edge / Workers 兼容性。Next.js setup、Server-side Processing
开源与商用成本:需要逐个包判断
The core editor is MPL-2.0; XL packages use GPL-3.0 or a commercial license. Pricing and licensing
| 层次 | 主要范围 | 选型含义 |
|---|---|---|
| Core | 基础 Block、UI、实时协作和 Comments | 可以用于商业闭源应用,但仍须满足 MPL-2.0 |
| XL | AI、多列布局及高级导出 | 选择 GPL-3.0 合规使用,或购买商业许可 |
| 运行服务 | 同步服务、数据库、对象存储、模型调用 | 编辑器许可不包含这些基础设施的成本 |
MPL-2.0 是文件级 copyleft:分发时需要遵守相关源码与告知义务;分发修改后的 MPL 文件需提供对应源码,但不会因此要求整个闭源应用全部改成 MPL。浏览器收到的 JavaScript 也属于 Mozilla FAQ 所讨论的分发情形,不能简单将它当成“服务端 SaaS 所以没有义务”。Mozilla MPL FAQ,Q8–11、Q16–17
2026-10-08 核查的 Business 页面,默认年付价格为 US$2,340 / 年,折合 US$195 / 月;月付选项为 US$390 / 月。价格和折扣可能变化,应在采购时重新确认。Pricing
更值得关注的是 XL 商业条款:标准许可对应一个 Application、一个 Production Environment,并允许五个 Licensed Developers seats;已部署应用继续使用也要求有效商业许可,不能理解为购买一年、以后停在旧版本就可无限期使用。标准计划不提供 perpetual license,多应用或特殊部署应按条款与维护方确认。Commercial License,§2.4、§2.7、§3.2
支持承诺也要单独核查:Priority Support 的首次响应与 Standard Support 不同;当前 SLA 将修复支持限于最新版、不承诺旧版 backport。要求长期固定版本的团队,应把这一点纳入采购与升级预算。Technical Support SLA
未使用 @blocknote/xl-ai、自行开发模型调用和 Block 修改逻辑的方案,不应仅因“用了 AI”就被算作已使用 XL;但自行实现会承担更多编辑交互与测试成本,也须分别满足所用依赖的许可。
有没有更好的同类竞品
比较前应对齐层级:BlockNote 是包含默认 Block UX 的产品组件,Tiptap / Lexical 更接近编辑器框架,Plate 在框架之上提供插件和可复制的 UI。接入时间、自由度和维护责任不同,不能只按演示界面或 Star 数排名。
| 候选 | 更适合的场景 | 相对 BlockNote 的主要取舍 |
|---|---|---|
| Tiptap | 文档结构、扩展体系和多框架接入优先 | 基于 ProseMirror,更自由的 Extension / Node / Mark;要承担更多 UI 与 Block UX 组装;core MIT。Docs |
| Plate | React 项目希望掌控 UI 源码并大量定制 | 基于 Slate,headless plugins + 复制到项目的 Plate UI;灵活但本地 UI 升级由团队维护;仓库默认 MIT,独立包许可优先,Plus 另计。Docs、LICENSE |
| Lexical | 团队愿意建设自己的编辑器基础设施 | Meta 与社区维护的独立引擎,MIT、官方 React / Yjs 集成;菜单、布局、存储等仍需组装,当前 API 仍在迁移。Introduction、Repository |
| Editor.js | 较简单的 CMS Block 输入和结构化 JSON 消费 | 核心 Apache-2.0、按 Tool 扩展;官方协作仍列 roadmap,插件质量和许可需逐个检查。Repository / Roadmap |
| CKEditor 5 | 审阅、Office 流程、企业支持优先 | 完整 UI、自有 model / conversion / plugin 体系;GPL 2+ / 商业许可,高级协作、导出和 LTS 有商业边界。Licensing |
Tiptap:最值得与 BlockNote 同时评估的通用候选
Tiptap 的 Node、Mark、Commands、Extension 与 NodeView 更贴近底层模型。若需要复杂结构、特殊选区或一个横跨多类编辑场景的统一平台,这种自由度可能比 BlockNote 的现成 UI 更重要。NodeView
不要把 Tiptap 的实时协作笼统当成付费功能。 开源 Collaboration 与 Yjs 可以配合 MIT 的 Hocuspocus 自托管;Tiptap Platform 提供另一条托管和高级功能路线,收费边界应按所用产品检查。Hocuspocus、Hocuspocus LICENSE、Platform pricing
截至整理日,最新版本是 3.31.4(2026-09-30)。活跃维护和商业产品是持续投入的信号;团队仍需维护自己组合的 UI 和升级路径。BlockNote 与 Tiptap 有共同底层,不表示两者 JSON 可无损互换,迁移要映射节点、属性、嵌套与样式。v3.31.4
Plate:愿意维护组件源码时,定制空间很有吸引力
Plate 官方区分 platejs runtime、headless plugins 与可选 Plate UI。Plate UI 复制到应用成为本地代码,容易改造,也意味着升级 npm 包不会自动更新这些组件。Introduction
它有官方 YjsPlugin 和多种 Provider 接入。latest 为 53.3.16,GitHub 发布时间换算到北京时间为 2026-10-08,网页搜索缓存可能仍显示前一版。若已有 Slate 经验,或希望较大范围控制 React 界面,Plate 值得进入首轮;如果目标是尽快上线标准 Block UX,仍应实测是否比 BlockNote 节省总工时。Yjs、v53.3.16
一个可核验的采用案例是剧本创作平台 Laper:截至 2026-10-08,其官方产品页明确说明剧本编辑器使用 Plate 构建带类型的剧本节点,AI 编辑工具也通过当前 Plate 编辑器执行修改;创始人技术介绍同时列出 Plate.js / Slate。这些官方资料确认了其主剧本编辑器采用 Plate / Slate。产品说明、AI 编辑链路、创始人技术介绍
编辑器框架和协作引擎应分别判断:Laper 官方公开的同步路径是 Plate operation → Loro 节点更新 → worker 持久化 → lorosync WebSocket → 其他客户端。它采用 Loro CRDT,不能因 Plate 有 YjsPlugin 就推断 Laper 使用 Yjs。公开说明未确认具体 Plate 版本、是否使用 Plate Plus,也不能证明全站每个输入组件都使用同一框架。协作架构
Lexical:有生命力,但不是省去编辑器研发的捷径
Lexical 不建立在 ProseMirror 或 Slate 上,它使用自己的不可变 EditorState 和节点树,通过 Commands、Transforms、Listeners 等操作模型。Introduction
latest 是 0.52.0(2026-09-28)。官方 Release 明确描述向 1.0 演进并包含 Breaking Changes;0.51.0 已转为 ESM-only,新的 Lexical Extensions 也改变配置与组合方式。因此不能从 Meta 背景推导出“当前 API 稳定”或固定的长期支持期限。v0.52.0、v0.51.0、Lexical Extensions
对于有编辑器工程经验、愿意长期控制底层的团队,它很有价值;只是要做文档输入功能时,界面与升级成本可能抵消免费许可带来的优势。本次没有同条件 benchmark,不能宣布 Lexical 或任何候选性能胜出。
Editor.js 当前仍在维护(2.31.7,2026-09-17),但若多人实时协作是必需条件,官方协作 roadmap 使它不宜作为默认首选。CKEditor 5 当前为 48.5.2(2026-09-22);它适合把企业文档流程置于优先级最高的团队,而非仅想接入轻量 Block 编辑的项目。Editor.js Release、CKEditor Release
Laper 对文档与知识库产品的参考价值
本文判断:Laper 的主要参考价值在于语义文档、范围明确的 AI 工具、统一的编辑写入路径和从正文派生的视图。 这些原则可以先进入产品设计,再通过需求确定编辑器与协作引擎。下文依据其公开架构自述提出建议;本次没有审计 Laper 的私有实现或执行多人协作测试。
先设计可被引用和操作的文档模型
Laper 把场景标题、人物提示、对白等保存为带类型的节点,并使用稳定节点标识关联导航、AI 和协作。场景顺序来自正文中场景标题的顺序,结构视图据此派生;故事节拍等需要作者判断的信息则作为独立、可编辑的规划数据。Formatting、Structure Visualization
对知识库产品,建议第一轮明确标题、段落、代码、附件和文档引用等内容类型,为文档与可操作 Block 保留稳定 ID。目录、反向链接、搜索片段和引用位置尽量从同一份正文派生,避免多份列表各自维护正文事实。语义类型表达“这是什么”,外观由渲染器决定;自动生成的主题标签、摘要或关联推荐还应保留来源与人工修改方式,不应冒充确定的原文事实。
这里需要提前作出一个产品决定:原生结构化文档还是 Markdown / MDX 源码,哪一份是可编辑的权威内容? 若选结构化文档,发布与搜索保存可重建的投影;若承诺 MDX 源码无损编辑,应保留 AST、组件与表达式的语义,并实际测试往返。仅把富文本导出成 Markdown,无法履行后一种承诺。
让 AI 有明确的读取范围和修改目标
Laper 的读取工具支持 cursor、outline、scene、range、node 和 full 等范围,要求目标 ID 来自实际读取;超出范围时说明截断,目标过时则重新读取。其 AI 写入经过当前 Plate 编辑器及同一操作桥接层。AI Workspace
知识库产品可以对应为:读取目录、读取选区或小节、检索相关文档、针对已读取 Block 提出修改。跨文档检索用于发现资料,写入前仍要重新读取经过授权的当前正文,不能把搜索索引中的旧片段当成修改依据。
例如,用户要求“精简这个小节”时,建议先读取目标 Block 与必要上下文,再生成带目标 ID 和基础内容版本的 patch;用户查看差异并接受时,重新校验权限、目标是否存在及基础内容是否仍匹配。期间若有人改了该 Block,应提示重新生成或重新确认,不能静默覆盖。权限校验须覆盖读取、交给模型的上下文与最终写入,不能只在界面隐藏文档。
flowchart TD
R[授权读取目标 Block<br/>记录内容版本] --> A[AI 生成修改建议]
A --> D[展示差异<br/>接受或拒绝]
D --> V[接受时校验<br/>权限、目标与内容版本]
V -->|通过后| E[共用编辑命令<br/>更新正文与派生视图]
这是本文建议的工作流,包含应由产品实现和验证的保障,不是 Laper 已公开证明的完整协议。共用编辑命令有助于复用 Schema 校验、同步和撤销路径,但不能自动证明撤销、幂等与恢复均正确;这些仍需验收。
将正文协作与业务实时更新分开
Laper 的正文经 Loro 与 lorosync 同步,Presence、任务和账户信号另走相应通道。浏览器主线程持有文档,浏览器 worker 处理字节持久化与网络 IO;这里的 worker 不应混同于 Cloudflare Workers。Collaboration
采用 React、Convex 与 Cloudflare 的产品可以沿用这些技术,并明确职责:编辑器负责输入与结构;业务后端负责身份、文档权限、空间与任务记录;搜索索引和发布内容是派生结果。需要多人逐字共写时,再评估编辑器与 CRDT 的集成,并指定正文唯一的权威状态和更新协议,避免编辑器写一份 CRDT、后台又用整篇 JSON 覆盖另一份。
Convex 的 OCC 与 serializable transactions 处理数据库事务并发。由此不能推导出“把两份完整正文都写入数据库,就会自动合并两人的文字”:重试一次将字段替换为客户端给定内容的 mutation,仍然只是执行该替换语义。字符和结构合并、版本预检或显式冲突处理,需要在文档操作层定义。这是依据事务契约作出的工程判断。Convex OCC and Atomicity
也应准确理解 Laper 的具体限制:其官方说明在两人同时替换同一段落时,以段落值作为冲突边界、后来解析的值取胜;这不是字符级合并保证,也不能扩大为所有同段落逐字输入都会丢失。它要求已有项目先在线完成初始同步才允许编辑,打开后的短暂断网可排队同步;这不是“任何时候离线都能重新打开并编辑”的承诺。Loro、Yjs 或 CRDT 的名称本身都不能替代桥接层与离线行为的实际测试。Laper Collaboration
对未来产品,按什么顺序落地
以下是本文建议的分阶段路线,尚未实现:
| 优先级 | 第一轮产物 | 验收依据 |
|---|---|---|
| 优先完成 | 内容 Schema、稳定 ID、版本与旧数据样本 | 保存、读取、只读发布及引用定位一致;未知类型不会静默丢失 |
| 优先完成 | 小范围 AI 读取、修改建议及差异审阅 | 能说明读了哪里;被截断内容可见;无权文档不进入模型上下文 |
| 优先完成 | 人工与 AI 共用的编辑入口 | 用户先修改目标后,旧 AI 建议不会静默覆盖;接受、拒绝和撤销可复验 |
| 随后加入 | 目录、反向链接和可追溯的搜索引用 | 正文变更后视图可重建;搜索结果能回到原文及其来源版本 |
| 有明确需求再加入 | 多人共写、断网重连、快照恢复 | 同段输入、整段替换和 AI 改写分别测试;重连收敛、恢复可用、越权被服务端拒绝 |
首轮可以把同一组 Schema、一个业务 Block 和“精简小节”工作流分别接到 BlockNote 与 Plate:比较实现代价、结构约束、HeroUI 界面适配、发布转换和升级回归,再决定框架。若 BlockNote 的现有扩展面已覆盖需求,可以优先使用配套协作路径;只有明确存在无法满足的结构或交互要求时,才为直接使用 Plate 或自行建立 Loro 桥接承担额外工程成本。Laper 的实际采用提供了一种可行案例,不能单独证明它的整套技术组合对通用知识库最优。
怎样做一次有判据的选型验证
本文建议首轮只比较 BlockNote、Tiptap、Plate;已有底层编辑器经验再加入 Lexical。 先给所有候选相同文档、业务 Block 和保存接口,再比较完成同一体验的成本。不要把一个成品组件与另一个仅有段落输入的最小示例比较。
| 验证任务 | 操作与产物 | 通过依据 |
|---|---|---|
| 基础编辑与中文输入 | 中文输入法组合、选区、嵌套列表、撤销;在桌面和真实手机录下结果 | 不丢字、不重复提交组合文字,撤销范围符合预期;仅手机尺寸模拟不算真机验收 |
| 一个真实 Custom Block | 实现业务卡片、插入入口、保存 / 恢复和只读输出 | ID、属性和正文可恢复;发布结果无编辑按钮和缺失内容 |
| 格式互通 | 用同一份 Word / 网页 / Markdown 粘贴;记录往返差异 | 需求必须保留的结构不丢;其余损失有明确清单 |
| 协作与权限 | 两人同时编辑、离线重连;第三个无权用户尝试连接与写入 | 文档收敛,无权读写在服务器被拒绝,不能只隐藏前端按钮 |
| AI 与协作组合 | 两人在线时接受 / 拒绝模型修改并撤销 | 无结构异常,原内容可恢复;不以单人生成成功替代此项 |
| 长文与设备负载 | 对相同 100 / 1000 Block 样本测加载、输入、滚动和保存 | 记录文档、设备、插件集、bundle 与延迟;以自己的产品预算判定,不套用未经实测的排名 |
| 升级与迁移 | 用旧数据加载新版 Schema,测试 HTML 与协作客户端 | 不静默丢弃未知 Block;有迁移、回退及旧文档样本 |
| 许可与总成本 | 列实际使用的包、功能、服务与开发工时 | 必需能力都有可接受的许可和运维路径,XL 持续订阅与本地 UI 维护已纳入预算 |
若要求完整 MDX 源码往返、复杂文档审阅、原生移动端组件,或者禁止所需功能的商业订阅,应先把这些列成不可妥协的条件。BlockNote 是 Web 编辑器,不能因为使用 React 就当成 React Native 原生编辑组件。
发展前景判断应在升级时复核:看 Release 是否继续提供迁移说明、关键问题是否获得修复、下游是否跟进、许可和支持政策是否变化。这比单纯追踪 Star 数更能帮助长期决策。