十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Tiptap 富文本 JSON 与 HTML 互转利器 @tiptap/html:核心 API、双端实现与演进全解析

Tiptap 富文本 JSON 与 HTML 互转利器 @tiptap/html:核心 API、双端实现与演进全解析 Tiptap 富文本 JSON 与 HTML 互转利器 tiptap/html核心 API、双端实现与演进全解析【免费下载链接】tiptapThe headless rich text editor framework for web artisans.项目地址: https://gitcode.com/GitHub_Trending/ti/tiptap在 Tiptap 生态中tiptap/html是一个专注于把 Tiptap/ProseMirror 的 JSON 文档与 HTML 互相转换的轻量工具包。无论你需要在服务端把编辑器内容渲染成静态 HTML用于导出、邮件、SEO 快照还是需要把用户粘贴的 HTML 转回可编辑的 JSON 结构它都提供了开箱即用的函数。读完本文你将掌握generateHTML、generateJSON、getHTMLFromFragment的准确用法与适用环境理解它浏览器端依赖原生 DOM、Node 端基于 happy-dom的双入口设计并通过 packages/html/CHANGELOG.md 记录的关键变更看懂该包在序列化实现、安全与稳定性上的演进脉络。一、包定位与依赖关系根据 packages/html/package.json 的自述tiptap/html的定位是utility package to render tiptap JSON as HTML将 Tiptap JSON 渲染为 HTML 的实用工具包是典型的 headless 工具它不承载编辑器 UI只负责文档格式之间的转换。安装时需要注意它的运行约束peerDependencies必须与tiptap/core、tiptap/pmProseMirror 封装层同版本配套使用happy-dom^20.8.9既是 peerDependencies 又是 devDependencies。Node 端的./server入口在实现上需要 happy-dom 提供 DOM 环境因此服务端使用者必须自行安装 happy-dom详见下文双端实现一节。从源码目录packages/html/src可以看出该包的全部公开能力generateHTML.ts/generateJSON.ts/getHTMLFromFragment.ts——浏览器端实现server/generateHTML.ts/server/generateJSON.ts/server/getHTMLFromFragment.ts——Node 端实现。根入口 src/index.ts 与 src/server/index.ts 内容相同都是统一导出generateHTML与generateJSON真正的差异在各自模块内部。二、核心 API 使用详解2.1 generateHTMLJSON → HTMLgenerateHTML(doc, extensions)接收一份 ProseMirror JSONContent 文档与一组 Tiptap 扩展返回 HTML 字符串。源码在 packages/html/src/generateHTML.ts 中给出了权威示例import { generateHTML } from tiptap/html import StarterKit from tiptap/starter-kit const doc { type: doc, content: [ { type: paragraph, content: [ { type: text, text: Hello world!, }, ], }, ], } const html generateHTML(doc, [StarterKit]) console.log(html) // pHello world!/p实现只有三步见 src/generateHTML.tsgetSchema(extensions)用扩展列表构建 ProseMirror SchemaNode.fromJSON(schema, doc)把普通 JSON 对象实例化为 ProseMirror 文档节点交给getHTMLFromFragment(contentNode, schema)完成序列化。关键在于extensions参数最终输出的 HTML 标签与属性由你注册的扩展决定。例如想输出h1、strong、ul等就传入含 Heading、Bold、List 等扩展的数组或直接使用 StarterKit这与编辑器实例中扩展的解析规则保持一致。2.2 generateJSONHTML → JSONgenerateJSON(html, extensions, options?)是反向操作把一段 HTML 字符串解析为{ type: doc, content: [...] }结构。它的可选第三个参数options是 ProseMirrorParseOptions透传给底层解析器可用于控制preserveWhitespace、findPositions等行为。import { generateJSON } from tiptap/html import StarterKit from tiptap/starter-kit const json generateJSON(pHello, world!/p, [StarterKit]) console.log(json) // { type: doc, content: [{ type: paragraph, content: [{ type: text, text: Hello, world! }] }] }其内部链路见 packages/html/src/generateJSON.ts先用window.DOMParser().parseFromString(html, text/html)得到 DOM再由DOMParser.fromSchema(schema).parse(doc.body, options).toJSON()完成 ProseMirror 解析并输出 JSON。因此未被扩展识别的标签会被丢弃或降级为文本解析结果完全取决于 Schema。2.3 getHTMLFromFragment面向高级序列化getHTMLFromFragment(doc, schema, options?)接收的是已经实例化的 ProseMirrorNode与Schema而非 JSON 与扩展适合已有现成文档节点的二次封装场景generateHTML内部正是复用它。其实现核心在 packages/html/src/getHTMLFromFragment.tsconst wrap window.document.createElement(div) DOMSerializer.fromSchema(schema).serializeFragment(doc.content, { document: window.document }, wrap) return wrap.innerHTML它借道 ProseMirror 的DOMSerializer.serializeFragment把文档内容写入临时div再读取wrap.innerHTML作为结果字符串。注意它还接受options.document允许调用方注入自定义 Document在 iframe、worker 或测试环境非常有用。三、浏览器端与 Node 端同一函数两套实现这是该包最值得注意的设计。在 v3 引入server-only 导出之前服务端转换必须依赖异步 DOM 模拟体验割裂而 CHANGELOG 中d0e0adb3.0.1 的 Major Changes明确记录Created a new server-only export for the html package that will handle conversions with happy-dom while the client version relies on the browser DOM implementation separating concerns——即包被拆分出独立的 server 导出Node 端用 happy-dom 完成转换浏览器端仍用原生 DOM职责彻底分离。3.1 条件导出配置在 packages/html/package.json 的exports中可以看到双入口{ exports: { .: { import: { browser: ./dist/index.js, node: ./dist/server/index.js, default: ./dist/index.js } }, ./server: { import: ./dist/server/index.js, require: ./dist/server/index.cjs } } }也就是说在 Node 环境下 import 默认入口时解析器会自动落到 server 构建产物同时包还暴露了显式的tiptap/html/server子路径供需要明确指定运行环境的代码或无法自动按条件解析的打包器使用。3.2 运行环境自检与错误提示双端实现都内置了运行环境自检避免在错误的宿主里悄悄失败浏览器版 src/generateHTML.ts 检测到typeof window undefined时直接抛错提示若要在 Node 中使用请改用tiptap/html/server导入服务端版 src/server/generateHTML.ts 则采用正向 Node 检测判断process.versions.node是否存在否则抛出相反的引导提示。服务端代码注释透露了这段检测逻辑的由来Use positive Node.js detection to allow for jsdom/happy-dom environments in tests。这正好对应 CHANGELOG 3.17.1 中547cf9e记录的修复——此前正向/负向检测方式的边界问题导致server exports failing in Node.js test environments with jsdom/happy-domNode 测试环境下的导出失败改为正向检测后jsdom/happy-dom 模拟的 DOM 环境不再被误判。3.3 服务端 happy-dom 生命周期管理服务端版generateJSON与getHTMLFromFragment见 src/server/generateJSON.ts 与 src/server/getHTMLFromFragment.ts都会新建一个轻量的 happy-domWindow并通过 settings 关闭一切无关能力以提高效率const localWindow new Window({ settings: { disableJavaScriptEvaluation: true, disableJavaScriptFileLoading: true, disableCSSFileLoading: true, disableIframePageLoading: true, disableComputedStyleRendering: true, }, })转换完成后统一在finally块中执行localWindow.happyDOM.abort()与localWindow.happyDOM.close()清理实例。这正是 CHANGELOG 3.6.4 / 3.6.5提交61494a7、8525964所修复的memory leak caused by unclosed happy-dom windows——早期版本未关闭 Window 会造成内存泄漏如今源码中的finally清理即是对该问题的根治。generateJSON在拼装输入时还会先包装一层!DOCTYPE htmlhtmlbody.../body/html再交给 DOMParser以贴近真实浏览器文档结构。四、序列化实现的演进从 XMLSerializer 到 innerHTMLgetHTMLFromFragment如今用wrap.innerHTML读取结果但这一选择并非一直如此。CHANGELOG 3.22.3提交5812fde给出了清晰的动机Remove unnecessaryxmlnshttp://www.w3.org/1999/xhtmlattribute fromgenerateHTMLoutput by usinginnerHTMLinstead ofXMLSerializerfor HTML serialization.也就是说早期服务端实现曾使用XMLSerializer序列化 DOM而 XML 序列化会在根元素上输出xmlns命名空间属性改用innerHTML之后generateHTML的输出不再携带多余的xmlns结果更干净、更贴近浏览器实际渲染的 HTML。追溯更早的版本命名空间的引入本身就是一次有意的迁移3.0.1 的bf040b9记录Replacezeed-domwithhappy-dom-without-nodefor broader compatibility of the HTML parser. The only difference you should see is thathappy-dom-without-nodewill outputxmlns... which makes it compliant with the HTML5 specification。从 v2 时代的hostic-dom到zeed-dom再到 happy-dom 系列CHANGELOG 忠实记录了这个包服务端 DOM 引擎的换代过程——每次换代都围绕HTML5 解析兼容性与输出纯净度两个目标在权衡。五、happy-dom 升级安全修复与版本配套作为 Node 端唯一的 DOM 依赖happy-dom 的版本安全直接关系到所有服务端使用该包的用户。CHANGELOG 中有两条值得关注的安全相关记录3.6.739912ef将 happy-dom 从^18.0.1升到^20.0.0以修复CVE-2025-61927。该记录特别强调这是dependency/security-only change不修改任何公共 API并说明升级是为了防止漏洞被拉入依赖tiptap/html的消费方项目中3.7.21351d4d继续修复CVE-2025-62410将 happy-dom 提升到^20.0.2。这两条记录的价值在于提醒维护者一个事实tiptap/html的安全性与其 peerDependencyhappy-dom的版本强相关。由于 happy-dom 同时是 peerDependency消费方项目需要自行保证安装的 happy-dom 处于已修复安全问题的版本区间当前 packages/html/package.json 要求的基线为^20.8.9。CHANGELOG 中 3.22.07208e64的 Updated happy-dom to 20.8.9 则显示了依赖随版本持续跟进的过程。六、v3 重大变更速览升级前必须知道的事CHANGELOG 的 3.0.1 条目集中罗列了从 v2 / beta 走向 v3 stable 时的破坏性变更对打算升级或首次接入 v3 的开发者是重要的核对清单变更说明构建产物切换为 tsupa92f4a6不再支持 UMD 构建需要 UMD 的团队必须自行重新打包repackageserver 导入要求安装 happy-dom1a88826服务端转换改为同步执行、避免异步行为代价是必须显式安装 happy-domzeed-dom → happy-dom 系列bf040b9提升 HTML 解析器兼容性根元素输出xmlns以符合 HTML5 规范后在 3.22.3 通过 innerHTML 移除新增 server-only 导出d0e0adb浏览器端继续依赖浏览器 DOMNode 端由 happy-dom 处理转换关注点分离此外还有两条工程性修复值得留意3.22.427ea931修复包更新后 peerDependency 解析冲突导致的依赖安装问题3.0.14f49894包装 happy-dom 的Window/DOMParser创建避免把全局process置为null对应 issue #6368——这也是如今所有 Window 创建都收敛在包内部实现函数中的一个原因。七、结合测试与 Demo 深入验证如果你希望验证上述行为仓库提供了充分的测试与示例packages/html/tests/generateHTML.spec.ts、packages/html/tests/generateJSON.spec.ts 覆盖常规 JSON↔HTML 双向转换断言packages/html/tests/server-with-jsdom.spec.ts 专门验证 Node 测试环境jsdom下 server 导出的可用性对应 CHANGELOG 3.17.1 的环境检测修复。在demos目录中还可以找到贴近真实业务的配套示例demos/src/GuideContent/GenerateHTML 演示如何把编辑内容以 JSON 输入、HTML 输出含 Vue/React 双版本与tsx实现demos/src/GuideContent/GenerateJSON 演示反向的 HTML→JSON 解析同含 Vue/React 双版本与jsx实现。将它们与 packages/html/CHANGELOG.md 一起阅读可以直观感受到API 稳定不变、底层实现持续演进的版本节奏。结语tiptap/html虽然 API 面很小却是打通编辑器 JSON 文档与通用 HTML之间的关键桥梁。理解它意味着你既能写出可靠的导出/导入代码也能在遇到服务端序列化差异、happy-dom 版本安全告警、输出中多余xmlns等具体问题时第一时间定位到对应的实现与变更记录。无论你的场景是服务端预渲染、富文本内容迁移还是粘贴 HTML 的规范化入库这套JSON ↔ Schema → DOM → HTML的链路都值得沉淀为团队的公共知识。【免费下载链接】tiptapThe headless rich text editor framework for web artisans.项目地址: https://gitcode.com/GitHub_Trending/ti/tiptap创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表