后保留内容与撤销历史?)
如何让 Lexical 编辑器在 Vite 热更新HMR后保留内容与撤销历史【免费下载链接】lexicalLexical is an extensible text editor framework that provides excellent reliability, accessibility and performance.项目地址: https://gitcode.com/GitHub_Trending/le/lexical在 Vite 开发环境下修改代码触发热更新后Lexical 编辑器的文档内容会消失、光标状态丢失、撤销栈被清空。原因是开发阶段的 HMR 会重新执行每个模块而 Lexical 依赖对象标识来做节点类注册、命令分发和扩展去重——模块重新执行后这些对象全部换新编辑器状态随之失效。Lexical 为此在lexical/extension中提供了HMRExtension它在 HMR 周期之间保存当前EditorState、可编辑标志editable flag以及由HistoryExtension维护的 undo/redo 历史让你改完代码保存后编辑器里的内容和撤销历史原样保留。本文基于仓库中的官方 HMR 示例dev-examples/hmr和 React FAQ 的 HMR 章节给出完整的接入方式和验证方法。先跑通官方示例确认效果仓库自带一个最小的 Vite React 示例工程可以先用它确认预期行为。仓库要求 Node20.19.0、pnpm11.0.0见根目录 package.json 的engines与packageManager字段。在仓库根目录执行pnpm install pnpm -C dev-examples/hmr dev然后打开终端打印的 URL示例的 vite.config.ts 将开发服务器固定在4328端口且启用strictPort。按 dev-examples/hmr/README.md 的验证步骤在编辑器里输入一些内容并做几次可撤销的编辑例如输入后删除用“Make read-only”按钮切换一下可编辑标志确认当前状态修改 src/App.tsx 并保存触发 Vite 热更新。成功条件重新加载后编辑器内容、editable 标志和 undo/redo 历史都还在——你可以直接按撤销能回到热更新前删除的那段文字。在你的项目中接入 HMRExtension示例之所以有效是因为它的扩展声明里挂了HMRExtension。核心配置见 FAQ 文档import {buildEditorFromExtensions, configExtension, defineExtension, HMRExtension} from lexical/extension; import {RichTextExtension} from lexical/rich-text; import {HistoryExtension} from lexical/history; const editor buildEditorFromExtensions( defineExtension({ name: [root], namespace: my-editor, dependencies: [ RichTextExtension, HistoryExtension, configExtension(HMRExtension, {hot: import.meta.hot ?? null}), ], }), );要点hot配置接受任何带data: Recordstring, unknown属性的对象Vite 的import.meta.hot天然满足。生产环境或没有 HMR 的环境传null即可——扩展会安全地变成 no-op所以import.meta.hot ?? null可以不用区分开发和生产。撤销/redo 历史的保留依赖HistoryExtension作为 peer 存在扩展并不声明它为依赖而是在运行时检测。如果编辑器里没有HistoryExtension内容和 editable 标志仍会保留历史不会。工作原理扩展在 bundler 的 HMR 数据区里只暂存当前EditorState的引用因此每次编辑的开销不随文档大小增长真正序列化发生在被新模块实例替换的那一刻。文档状态和历史条目是作为“同一个族”一起序列化的保证各版本共享的节点恢复后仍然共享——这决定了重载后的第一次 undo 只会 diff 变化的部分而不是重建整篇文档。页面上有多个编辑器时的隔离规则扩展用 HMR key 区分不同编辑器的保存状态规则来自 HMRExtension 的源码注释与 FAQ需要照此配置namespace不同的编辑器自动隔离无需额外配置。namespace通过defineExtension或createEditor设置。完全没有设置namespace的编辑器会共用同一个 key因为createEditor自动生成的 namespace 每次重载都是新的随机串不能用于匹配。页面上超过一个编辑器时给每个编辑器配namespace。两个编辑器同时共用同一个import.meta.hot上下文和同一个namespace时用稳定的id区分defineExtension({ name: [main], namespace: shared, dependencies: [configExtension(HMRExtension, {hot: import.meta.hot ?? null, id: main})] }) defineExtension({ name: [sidebar], namespace: shared, dependencies: [configExtension(HMRExtension, {hot: import.meta.hot ?? null, id: sidebar})] })id必须是稳定的非空字符串例如main、sidebar不要用useId()、Math.random()或任何按挂载生成的值——每次挂载生成新值会导致 key 匹配不上状态永远无法恢复。空字符串会触发开发环境告警并被当作未提供。嵌套编辑器继承父编辑器的namespace因此两者不会被 namespace 自动隔离给嵌套编辑器单独的id或独立的namespace。开发环境下与父级共用 key 会输出告警。保存状态归属于 key 而非某一次重载开发阶段同一 key 的编辑器卸载后重新挂载恢复的是上一个实例留下的状态而不是自己的$initialEditorState。因此展示不同文档的两个编辑器需要不同的 namespace即使它们从不同时出现在屏幕上。开发环境下的告警可以直接当作诊断信号两个已挂载编辑器写了同一个 key 时会提示Two mounted editors are sharing the HMR key ...保存的状态无法解析时会提示改用$initialEditorState重新开始例如文档里某个节点类在这次重载中被删掉了导致旧状态无法重建。Fast Refresh 的边界与降级方案HMRExtension解决的是模块级重载但 React Fast Refresh 只在一个模块只导出 React 组件时才生效。如果一个模块同时还导出 hook、类、命令或常量Vite 会回退到整棵组件树重挂载丢弃组件状态。仓库给出的处理方式把非组件导出拆到配套的*Utils文件里从*Utils模块直接导入非组件值可以获得更细粒度的 HMR 边界因为改动组件文件不会使这些导入失效。lexical/react的多个插件模块已经按这个模式拆分。自定义插件请沿用同样模式React 组件放一个文件hook、常量、类放单独文件。跨入口点共享的值必须定义在同一个模块里而不是内部模块——内部模块会被内联进每个入口各入口拿到的是不同对象而命令和instanceof是按对象标识匹配的。如果模块无法拆分例如组件与紧耦合的非组件逻辑在一起可以用框架的指令强制完整刷新。以 Next.js 为例在文件顶部加// refresh reset注释每次改动都会强制整文件重挂载。限制与边界只有本编辑器自己记录的 undo/redo 条目会被保留。配合SharedHistoryExtension时嵌套编辑器会把条目压进父级的栈但条目只能应用到记录它的那个编辑器——那些编辑器已被这次重载替换相关条目会被留在原地开发环境会输出Left behind ... undo/redo entries告警。保存状态无法解析时比如由另一版本构建写入的 payload扩展在开发环境告警并回退到$initialEditorState重新开始不会抛错。Webpack 和 Parcel 暴露的是module.hot而不是import.meta.hot其module.hot.data由 dispose handler 填充、不能直接读写因此不能直接传给hot配置需要用module.hot.addDisposeHandler写一个自定义适配器见 HMRExtension.ts 对HotContext接口的说明。本文的主路径只覆盖 Vite。参考dev-examples/hmr/README.md示例的运行方式与验证步骤dev-examples/hmr/src/App.tsxLexicalExtensionComposer下的完整示例代码packages/lexical-website/docs/react/faq.mdHMR 原理、多编辑器隔离与 Fast Refresh 兼容性packages/lexical-extension/src/HMRExtension.tsHMRConfighot、id与恢复逻辑的完整文档注释【免费下载链接】lexicalLexical is an extensible text editor framework that provides excellent reliability, accessibility and performance.项目地址: https://gitcode.com/GitHub_Trending/le/lexical创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考