用途
本技能用于在应用代码与 TanStack Devtools 面板之间建立双向通信。前提是先阅读并理解 devtools-event-client 技能,因为它建立在 EventClient、其事件映射类型、emit()/on() API、pluginId 命名空间、连接生命周期以及单例模式之上。本技能假定你已经拥有一个可用的 EventClient 实例。
核心概念
EventClient 并非单向。emit() 和 on() 在应用代码或面板代码任一侧都可用,且共享同一个事件总线。方向是通过你设计事件映射时建立的约定,而不是 API 本身的限制。
- 应用代码调用 client.emit('state-update', ...)(观测),面板代码调用 client.on('state-update', ...)(观测)。
- 面板代码调用 client.emit('set-state', ...)(命令),应用代码调用 client.on('set-state', ...)(命令)。
主要能力与核心模式
1. 应用到 Devtools 的观测
应用发出状态变更,面板监听并渲染。在共享模块中定义事件映射与客户端,使用 pluginId(如 counter-inspector)并可通过 process.env.NODE_ENV !== 'production' 在生产环境禁用。应用侧在状态变化时 emit 观测事件,面板侧用 on 监听并调用渲染函数。
2. 从 Devtools 到应用的命令
面板发送命令,应用监听并变更状态。在事件映射中扩展命令事件(如 reset、set-count)。面板侧在用户交互时 emit 命令,应用侧用 on 监听命令并作出反应。命令处理函数在变更状态后会重新 emit 一个观测事件,从而闭合回路,让面板看到自己命令的执行结果。
3. 时间旅行调试
将观测(快照)与命令(回退)结合,构建时间旅行滑块。事件映射中包含 snapshot(观测)与 revert(命令)。应用侧使用 structuredClone 发出快照,并监听 revert 命令;此处 structuredClone(state) 是必需的。若不使用,快照负载会持有对实时状态对象的引用,后续应用变更状态时,面板中此前存储的所有快照都会因指向同一对象而被破坏。面板侧收集快照并通过滑块触发 revert。应用处理 revert 后应重新 emit 快照,使面板时间线保持最新(应用侧示例中的 revert 处理器未重新 emit,如 UI 需要在回退后更新时间线可自行添加)。
4. 双向事件映射设计
当单个插件同时需要观测和命令事件时,将它们定义在同一个事件映射中,并用命名约定区分方向。观测事件描述发生了什么(如 state-update、action-dispatched、error-caught、snapshot);命令事件描述要做什么(如 set-state、dispatch-action、reset、revert)。该区分仅是事件映射键上的约定,EventClient API 对两者相同,但保持约定可使事件映射自文档化,并避免混淆哪一侧 emit 与监听。技能给出了完整的双向接线示例(StoreInspectorClient),应用中处理 set-state 与 reset 命令,面板中监听 state-update 并发出命令。
高频观测事件的防抖
高频状态变化(如鼠标跟踪、动画帧)可能淹没事件总线。可在 emit 侧防抖,例如用 setTimeout 以约 16ms(约 60fps 上限)节流。命令事件是用户发起且频率低,不要对其防抖。
常见错误
- 快照未使用 structuredClone(高):会导致快照负载持有实时状态引用,面板中所有已存储快照被静默破坏。这适用于任何面板累积历史数据的观测事件,而不仅是时间旅行。
- 跨标签页场景中的不可序列化负载(高):使用服务器事件总线(WebSocket/SSE/BroadcastChannel)时负载会被序列化传输,函数、DOM 节点、带方法的类实例、Map、Set、WeakRef 和循环引用都会静默失败或丢失数据。在双向模式中尤其危险,因为命令负载会从面板流向应用并可能跨越传输边界。经验法则:若 JSON.parse(JSON.stringify(payload)) 无法干净地往返,该负载对事件总线就不安全。
- 未区分观测与命令事件(中):混用命名约定会让事件映射混乱且易错。建议观测使用过去式/描述性后缀(-update、-changed、-dispatched、-caught),命令使用祈使式(set-、dispatch-、reset、revert)。该约定不被 API 强制,但一致命名可防止接线错误。
适用场景与限制
适用于为 TanStack Devtools 编写插件、在开发环境中观测应用状态并允许面板反向控制应用的场景,例如状态检查器、时间旅行调试器和计数器检查器。使用前提是已有可用的 EventClient 实例并理解其基础 API。事件映射中的方向区分依赖开发者自觉遵守命名约定,API 本身不强制;跨传输边界时负载必须可干净序列化。具体收费、价格、平台支持范围等信息暂未提供。