news 2026/9/21 1:21:29

在 SolidJS 中接入 json-render DevTools:`@json-render/devtools-solid` 使用指南与源码解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
在 SolidJS 中接入 json-render DevTools:`@json-render/devtools-solid` 使用指南与源码解析
  • 人工智能
  • AI 应用
  • 前端
  • MCP 服务

【免费下载链接】json-render

The Generative UI framework

项目地址:https://gitcode.com/GitHub_Trending/js/json-render
点击查看免费下载

导读

@json-render/devtools-solid是 json-render 生成式 UI 框架(Generative UI framework)为 SolidJS 提供的 DevTools 适配器,一个开箱即用的<JsonRenderDevtools />组件。本文从安装、最小接入、全部 Props 参考讲到面板的 Spec / State / Actions / Stream / Catalog 五大标签页与 DOM 拾取器(Picker)的实际用法,并深入packages/devtools-solid/src/index.tsx等源码,说明它如何在 SolidJS 的细粒度响应式体系下完成事件采集、状态联调与生产构建零开销。读完你可以在自己的 SolidJS 应用中快速集成、调试 AI 流式生成的 UI,并按需调整停靠位置、快捷键与内存缓冲。

一、背景:框架无关的 DevTools 核心与适配器分层

json-render 的 DevTools 采用「框架无关核心 + 各框架薄适配器」的两层设计:

  • @json-render/devtools(packages/devtools/README.md)是纯 TypeScript 实现的框架无关核心,提供 Shadow DOM 隔离的面板 UI、事件存储(event store)、DOM 拾取器与流式 tap 工具。它自身不依赖任何 UI 框架,绝大多数用户不会直接 import 它。
  • @json-render/devtools-solid则是 SolidJS 适配器,把核心能力封装成一个null渲染、零 UI 输出的挂载型组件,你只需放进组件树即可。

同层的适配器还包括@json-render/devtools-react@json-render/devtools-vue@json-render/devtools-svelte。从packages/devtools-solid/package.json可以看到,该包依赖@json-render/core@json-render/devtools@json-render/solid三个 workspace 包,说明它在运行时同时桥接「核心面板逻辑」与「Solid 渲染器的状态/动作上下文」。

二、安装与前提

npm install @json-render/devtools @json-render/devtools-solid
  • Peer dependencysolid-js@^1.9。安装时若版本不匹配,包管理器会给出 peer 冲突提示,请确保项目中的solid-js不低于 1.9.0(package.json 中声明为solid-js: ^1.9.0)。
  • @json-render/devtools会被@json-render/devtools-solid自动引入,显式安装是为了让 npm 正确解析依赖树,同时你也能直接使用其暴露的底层 API(如服务端流式 tap)。
  • 使用时还需要@json-render/solid(渲染器)与@json-render/core(目录、Registry、状态模型)。Solid 渲染器的完整安装方式见 packages/solid/README.md:npm install @json-render/core @json-render/solid zod,其中solid-js ^1.9.0zod ^4.0.0为 peer 依赖。

说明:zod用于为 Catalog 中的组件 props 与 actions 定义 schema,是定义 Catalog 的必要依赖。

三、最小接入:三步把 DevTools 放进 Solid 应用

1. 定义 Catalog(组件与动作清单)

// catalog.ts import { defineCatalog } from "@json-render/core"; import { schema } from "@json-render/solid/schema"; import { z } from "zod"; export const catalog = defineCatalog(schema, { components: { Card: { props: z.object({ title: z.string(), description: z.string().nullable(), }), description: "A card container", }, Button: { props: z.object({ label: z.string(), action: z.string(), }), description: "A clickable button", }, }, actions: { submit: { description: "Submit the form" }, cancel: { description: "Cancel and close" }, }, });

2. 创建 Registry(组件实现)

// registry.tsx import { defineRegistry } from "@json-render/solid"; import { catalog } from "./catalog"; export const { registry } = defineRegistry(catalog, { components: { Card: (renderProps) => ( <div class="card"> <h3>{renderProps.element.props.title as string}</h3> {renderProps.children} </div> ), Button: (renderProps) => ( <button onClick={() => renderProps.emit("press")}> {renderProps.element.props.label as string} </button> ), }, actions: { submit: async () => {}, cancel: async () => {}, }, });

3. 在 JSONUIProvider 内放置<JsonRenderDevtools />

import { JsonRenderDevtools } from "@json-render/devtools-solid"; import { JSONUIProvider, Renderer } from "@json-render/solid"; import { registry } from "./registry"; import { catalog } from "./catalog"; export function App(props: { spec: () => any }) { return ( <JSONUIProvider registry={registry}> <Renderer spec={props.spec()} registry={registry} /> <JsonRenderDevtools spec={props.spec()} catalog={catalog} messages={messages()} // AI SDK 消息数组,用于 Stream 标签页 /> </JSONUIProvider> ); }

组件放置位置没有限制(只要是JSONUIProvider内即可),它本身不渲染任何 DOM。JSONUIProvider是 Solid 渲染器提供的合并 Provider,内部串联了StateProviderVisibilityProviderValidationProviderActionProvider(见 packages/solid/README.md)。

默认行为

  • 浮动开关:出现在页面右下角,点击展开/收起面板。
  • 快捷键Ctrl/Cmd+Shift+J切换面板开关。
  • 生产构建零成本:组件在 production 下 tree-shake 为null,不会被打包进产物。

四、Props 完整参考(与源码逐一对应)

以下 Props 定义直接来自 packages/devtools-solid/src/index.tsx 的JsonRenderDevtoolsProps接口:

Prop类型默认值说明
specSpec \| null当前要检查的 UI Spec。多渲染器场景下由面板内部按需读取最新值
catalogCatalog \| null组件/动作目录,用于 Catalog 标签页与拾取器解析
messagesChatLikeMessage[]AI SDK 风格的流式消息数组(parts结构),用于 Stream 标签页采集补丁事件
initialOpenbooleanfalse面板初始是否展开
positionPanelPosition"bottom-right"面板停靠与开关位置,见下文「布局与停靠」
hotkeystring \| false"mod+shift+j"切换面板的快捷键;传false关闭快捷键
bufferSizenumber500事件存储(ring buffer)最大保留事件数,超出丢弃最旧事件
reserveSpacebooleantrue面板展开时是否通过<body>padding 为面板预留空间
allowDockTogglebooleantrue是否显示工具栏按钮,允许用户切换底部/右侧停靠(选择持久化到 localStorage)
onEvent(evt: DevtoolsEvent) => void事件回调:每当有新事件入队时触发,参数为最新一条事件

messages的类型为宽松的聊天消息结构(parts?: Array<{ type, text?, data? }>),与@json-render/core的 Spec、Catalog 类型对齐。若你的消息对象结构略有差异,只要parts字段兼容即可被scanMessageParts处理。

五、面板功能:五大标签页与拾取器

组件挂载时通过createPanel注册以下标签页(源码第 137 行:tabs: [specTab(), stateTab(), actionsTab(), streamTab(), catalogTab()]),面板 UI 由@json-render/devtools用原生 DOM + Shadow DOM 隔离实现:

  1. Spec(规范树):以树形展示当前 Spec 的元素结构(rootelementsstate),支持在多个生成之间切换。多渲染器宿主(如每条助手消息产生一个 Spec 的聊天应用)可通过getSpecs提供每代 Spec 列表,Spec 标签页会显示生成切换器(见 packages/devtools/src/panel/types.ts 的SpecEntry)。
  2. State(状态):实时查看/修改渲染器状态。面板通过适配器适配的StateStore读取getSnapshot,状态以 JSON Pointer 路径扁平化展示。
  3. Actions(动作):展示动作分发生命周期——dispatch 与 settle 成对出现,含执行耗时(durationMs)与结果/错误。
  4. Stream(流):采集 AI 流式消息中的 UI 补丁事件,观察 Spec 如何逐步生成。
  5. Catalog(目录):展示当前注册的组件与动作清单及其 schema 说明。

另外还有拾取器(Picker):点击页面上任意由 json-render 渲染的元素,通过data-jr-key属性反查其在 Spec 中的 key,并联动高亮 Spec 树中的对应节点。拾取器与 Spec 标签页通过createSelectionBus共享选中项(选中后调用highlightElement高亮 DOM),其 DOM 几何计算逻辑(含display: contents包裹元素的边界回退计算)见 packages/devtools/src/picker.ts。

六、运行机制与源码原理

1. 生产环境守卫:isProduction()短路

组件函数体第一行即if (isProduction()) return null;isProduction实现于 packages/devtools/src/prod-guard.ts:当process.env.NODE_ENV === "production"时返回true,且用typeof process !== "undefined"守卫了浏览器无process的场景。配合打包器的常量折叠与 tree-shaking,生产构建中整个组件(及其引用的面板、事件存储等模块)都会被剔除。该行为有单元测试覆盖(packages/devtools/src/prod-guard.test.ts),分别验证了非 production、production、NODE_ENV未定义三种情况。

2. 事件存储:带上限的环形缓冲

面板内部createEventStore({ bufferSize })创建事件存储(默认 500 条,见 packages/devtools/src/event-store.ts)。它提供pushsnapshotsubscribeclearsize五个方法;push超过缓冲上限时丢弃最旧事件,snapshot返回全新数组保证调用方可安全当作不可变数据。所有标签页都订阅同一事件存储,事件到达时同步刷新。

3. 动作采集:核心包的 Action Observer

组件在挂载时调用registerActionObserver({ onDispatch, onSettle })(来自@json-render/core,实现见 packages/core/src/action-observer.ts)。Solid 渲染器的ActionProvider会在每次动作执行前后调用notifyActionDispatch/notifyActionSettle,DevTools 借此拿到:

  • dispatch 事件:动作id、名称name、参数params、触发时间at
  • settle 事件:配对id、是否成功ok、耗时durationMs、结果result或错误信息error

观察器以模块级 pub/sub 实现,且每个观察器回调被 try/catch 包裹,DevTools 的异常不会中断动作执行。组件卸载时通过onCleanup反注册。

4. 流式事件采集:scanMessageParts

createEffect监听props.messages,对每条消息的parts调用scanMessageParts扫描(源码第 113–119 行)。seenPartsWeakSet记录已处理对象,保证重复渲染时同一部分不会被重复计入事件流。这是 Stream 标签页数据来源,用于观察 AI 逐步 patch 出 UI 的过程。

5. 与渲染器联动:markDevtoolsActivedata-jr-key

挂载时调用markDevtoolsActive()(实现于 packages/core/src/devtools-flag.ts),这是一个模块级计数器:DevTools 挂载期间计数 > 0,Solid 渲染器检测到isDevtoolsActive()为真后,会给每个渲染的元素包装节点打上data-jr-key属性,拾取器正是靠它把点击的 DOM 节点映射回 Spec key(见 packages/devtools/src/picker.ts 中DEVTOOLS_KEY_ATTR的定义)。未挂载 DevTools 时计数器为 0,渲染器行为与之前完全一致——纯 opt-in 机制。

6. Solid 适配层:桥接 State 上下文

组件通过useStateStore()(来自@json-render/solid,实现在 packages/solid/src/contexts/state.tsx)获取StateContextValue,将其包装为StateStore接口(get/set/update/getSnapshot/subscribe)交给面板核心,实现 State 标签页与渲染器状态的实时同步。注意:在 Solid 中读取可变状态要放在 JSX 表达式、createMemocreateEffect内,Hook 返回的是 accessor(详见 packages/solid/README.md 的「Differences from @json-render/react」一节)。

7. 生命周期管理

onMount中创建面板句柄handle、订阅选中总线;onCleanup中依次执行选中订阅反注册、markDevtoolsActive释放、handle.destroy()(面板从 DOM 移除并清理)。整套生命周期完全遵循 Solid 的组件模型,无需手动管理。

七、布局与停靠:position、reserveSpace 与 allowDockToggle

position接受三种值(定义见 packages/devtools/src/panel/types.ts):

面板停靠浮动开关位置适用场景
bottom-right(默认)底部抽屉右下角常规文档流布局
bottom-left底部抽屉左下角宿主应用右下角已有内容
right右侧全高面板右上角使用100vh/position: fixed; bottom: 0的 app-shell 布局,避免与底部固定元素冲突

两个联动选项:

  • reserveSpace(默认true):面板展开时通过<body>的 padding 为面板预留空间,内容会被推开。对height: 100vhposition: fixed; bottom: 0这类 CSS 无法自适应的布局,面板实际是覆盖(overlay)效果,此时可改传false保持纯覆盖,或让固定元素使用bottom: var(--jr-devtools-offset-bottom, 0)/right: var(--jr-devtools-offset-right, 0)这两个 CSS 自定义属性自行避让。false模式下这两个变量依然会在:root上发布,供应用按需消费。
  • allowDockToggle(默认true):显示工具栏按钮让用户实时切换底部/右侧停靠,选择持久化到 localStorage(key 为__jr_devtools_dock),且一旦设置会覆盖初始position。传false则严格锁定position,工具栏不渲染该按钮,适合布局只兼容一种停靠方式的宿主。

八、自定义事件监听与常见问题

监听事件:传onEvent即可拿到事件流的最新一条:

<JsonRenderDevtools spec={spec()} catalog={catalog} messages={messages()} onEvent={(evt) => { if (evt.kind === "action-settled" && !evt.ok) { console.warn("action failed", evt.name, evt.error); } }} />

DevtoolsEvent类型(含action-dispatchedaction-settled等事件类型)由@json-render/devtools定义,@json-render/devtools-solid会原样 re-export(源码末尾export type { DevtoolsEvent })。

常见问题与建议

  • 生产构建后组件消失:这是预期行为——isProduction()返回true时组件渲染null且被 tree-shake,确保线上零体积、零副作用。
  • 快捷键不生效:检查hotkey是否被显式传为false,或是否与其他应用快捷键冲突。语法为"mod+shift+j"mod在 macOS 上是 Cmd、其余平台是 Ctrl。
  • 面板遮挡底部固定元素:将position改为"right",或把固定元素的bottom/right接上--jr-devtools-offset-bottom/--jr-devtools-offset-right变量。
  • 内存占用:长会话产生海量事件时,调小bufferSize以控制事件存储体积;默认 500 已足够日常调试。

九、License

@json-render/devtools-solid以 Apache-2.0 协议开源(见 package.json)。

总结

@json-render/devtools-solid以极低的接入成本(一个组件、三行 JSX)为 SolidJS 生成式 UI 应用带来完整的调试体验:Spec 树检查、状态实时编辑、动作耗时追踪、AI 流式生成过程回放与 DOM 拾取联动。其背后是「框架无关核心 + 适配器」的架构——@json-render/devtools提供纯 TS 面板与事件存储,@json-render/devtools-solid负责桥接 Solid 的状态上下文与动作观察器,并在生产环境自动无痕退出。无论是调试 AI 聊天 UI 的逐步生成,还是排查状态绑定与动作执行问题,这套工具链都能让你直接「看见」渲染器内部发生了什么。

  • 人工智能
  • AI 应用
  • 前端
  • MCP 服务

【免费下载链接】json-render

The Generative UI framework

项目地址:https://gitcode.com/GitHub_Trending/js/json-render
点击查看免费下载
上一篇:5分钟上手intentrace:Linux系统调用追踪工具安装与快速开始完整教程
下一篇:Azure-Sentinel恶意软件检测:基于行为的威胁识别

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/21 1:16:27

基于STM32的智能小车设计与实现:PWM调速、循迹避障与灭火功能详解

简介&#xff1a;这是一份围绕STM32F103C8T6微控制器的智能小车完整设计方案&#xff0c;面向单片机初学者、嵌入式开发人员以及正在进行课程设计或毕业设计的学生。内容从硬件电路搭建到软件代码实现&#xff0c;系统讲解了PWM调速、红外循迹、红外避障、障碍物跟随、超声波避…

作者头像 李华
网站建设 2026/9/21 1:16:11

SIMCA-P软件安装部署与代谢组学多元统计建模实用指南

简介&#xff1a;SIMCA-P多变量统计分析软件的Windows安装包&#xff0c;面向化学计量学、模式识别、产品质量控制等领域的科研人员与数据分析专家&#xff0c;可用于执行主成分分析、偏最小二乘回归、判别分析等任务&#xff0c;帮助用户高效处理复杂数据集并建立预测模型。压…

作者头像 李华
网站建设 2026/9/21 1:14:56

有源功率因数校正APFC实战:从原理到500W电路设计全解析

简介&#xff1a;面向电力电子与开关电源设计人员&#xff0c;这份doc文档系统讲述有源功率因数校正&#xff08;APFC&#xff09;电路的设计要点&#xff0c;针对整流装置导致的输入电流畸变与谐波污染问题&#xff0c;给出了完整解决方案。资源为单个doc文件&#xff0c;压缩…

作者头像 李华
网站建设 2026/9/21 1:14:18

FreeCAD MCP实战:用自然语言驱动CAD建模

1. 为什么我会盯上 FreeCAD 加 MCP 这套组合第一次听说 MCP 是在一个做 AI Agent 的朋友群里&#xff0c;有人丢了一句“现在连 CAD 都能用嘴画图了”&#xff0c;配了张 FreeCAD 里自动生成法兰盘的截图。我当时第一反应是怀疑——参数化建模这东西&#xff0c;尺寸、约束、特…

作者头像 李华
网站建设 2026/9/21 1:14:15

用Python+Playwright打造跨平台京东自动下单助手

简介&#xff1a;这是一款面向京东购物人群的自动化抢购辅助工具&#xff0c;适用于经常需要蹲守热门商品、应对限时补货场景的用户。工具提供Windows与Mac双平台版本&#xff0c;并基于Python开发&#xff0c;便于对自动化流程进行二次调整&#xff1b;核心能力包括商品库存自…

作者头像 李华
网站建设 2026/9/21 1:14:08

ArcGIS Pro重构OSM路网:从拓扑修复到网络数据集构建

1. 这不是“导入数据”而是重建空间逻辑&#xff1a;为什么OpenStreetMap路网在ArcGIS Pro里总出错你刚装好ArcGIS Pro 3.7&#xff0c;兴冲冲下载了杭州主城区的OpenStreetMap&#xff08;OSM&#xff09;路网数据&#xff0c;用“OSM File Loader”工具一键导入——结果发现&…

作者头像 李华