关于 devtools
@json-render/devtools 为 json-render 应用提供悬浮式检查面板,面向使用 React、Vue、Svelte 或 Solid 的开发者。它集中查看规范、状态、动作、流事件和目录,并支持元素拾取与面板停靠。
主要功能
- 01检查元素树及验证警告
- 02查看和编辑 JSON Pointer 状态
- 03追踪动作调用及结果
- 04查看规范流补丁和事件
- 05拾取页面元素并定位规范
适用场景
- 01调试 AI 生成的界面
- 02检查状态绑定和动作调用
- 03跟踪多轮流式生成
- 04在不同框架应用中检查渲染器
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ vercel-labs/ json-render --skill devtools安装后在 Claude Code 中输入/devtools确认已加载。
详细介绍
@json-render/devtools
适用于 json-render 应用的浮动检查器面板。与框架无关的核心,以及针对各框架的适配器(React、Vue、Svelte、Solid)。
对生产环境安全:当 process.env.NODE_ENV === "production" 时,组件不会渲染 devtools UI,包括打包工具在浏览器中替换该表达式但不存在全局 process 的情况。未打包且没有 process.env 的环境会保留开发行为。
安装
安装核心包,以及与宿主应用渲染器相匹配的适配器。
# React
npm install @json-render/devtools @json-render/devtools-react
# Vue
npm install @json-render/devtools @json-render/devtools-vue
# Svelte
npm install @json-render/devtools @json-render/devtools-svelte
# Solid
npm install @json-render/devtools @json-render/devtools-solid
即插即用
将 <JsonRenderDevtools /> 放在现有 <JSONUIProvider>(或对应框架的等效组件)内的任意位置。无需进行其他配置。
React
import { JsonRenderDevtools } from "@json-render/devtools-react";
<JSONUIProvider registry={registry} handlers={handlers}>
<Renderer spec={spec} registry={registry} />
<JsonRenderDevtools spec={spec} catalog={catalog} messages={messages} />
</JSONUIProvider>;
Vue
<script setup>
import { JsonRenderDevtools } from "@json-render/devtools-vue";
</script>
<template>
<JSONUIProvider :registry="registry">
<Renderer :spec="spec" :registry="registry" />
<JsonRenderDevtools :spec="spec" :catalog="catalog" :messages="messages" />
</JSONUIProvider>
</template>
Svelte
<script>
import { JsonRenderDevtools } from "@json-render/devtools-svelte";
</script>
<JSONUIProvider {registry}>
<Renderer {spec} {registry} />
<JsonRenderDevtools {spec} {catalog} {messages} />
</JSONUIProvider>
Solid
import { JsonRenderDevtools } from "@json-render/devtools-solid";
<JSONUIProvider registry={registry}>
<Renderer spec={spec()} registry={registry} />
<JsonRenderDevtools
spec={spec()}
catalog={catalog}
messages={messages()}
/>
</JSONUIProvider>;
控件
- 浮动切换按钮显示在右下角。
- 快捷键:
Ctrl/Cmd+Shift+J(可通过hotkeyprop 配置)。 - 抽屉大小可调整;高度会保存到 localStorage。
Props
spec(Spec | null) — 当前 spec。catalog(Catalog | null) — catalog 定义;Catalog 面板必需。messages(UIMessage[]) — AI SDKuseChat消息;会扫描其中的 spec 数据部分。initialOpen(boolean) — 初始时打开。position("bottom-right" | "bottom-left" | "right") — 停靠位置和切换按钮所在角落。"bottom-*"停靠在底部;"right"停靠在右侧边缘并占满高度(推荐用于已使用100vh或固定底栏的应用外壳)。hotkey(string | false) — 默认为"mod+shift+j"。bufferSize(number) — 事件环形缓冲区上限,默认为 500。reserveSpace(boolean,默认为true) — 为true时,面板会通过在body上应用padding-bottom/padding-right来推动宿主应用。设为false可使面板保持纯叠加层。allowDockToggle(boolean,默认为true) — 显示工具栏按钮,让用户在底部停靠和右侧停靠之间切换面板。用户的选择会保存到localStorage,并在后续挂载时覆盖position。传入false可将停靠位置锁定为position。onEvent((DevtoolsEvent) => void) — 可选的事件回调。
面板
- Spec — 以
spec.root为根的元素树;显示 props/可见性/事件/监听器详情;集成validateSpec警告。 - State — 所有 JSON Pointer 路径;可通过
store.set直接编辑。 - Actions — 已分发操作的时间线(名称、参数、结果/错误、耗时)。
- Stream — 按生成过程分组显示 spec 补丁、文本块、令牌用量和生命周期标记。
- Catalog — catalog 中声明的组件和操作,并显示属性标签。
选择器(工具栏)
元素选择器是面板标题栏中的工具栏按钮(类似 Chrome DevTools),不是选项卡。点击按钮启用选择模式,然后点击页面中任意已渲染的元素,即可跳转到 Spec 选项卡并聚焦该元素。按 Esc 取消。
预留空间与停靠
面板可以停靠在底部或右侧边缘。默认情况下,用户可以通过工具栏按钮在两种位置间切换(选择会保存到 localStorage)。如果宿主应用只支持一种停靠位置,请设置 allowDockToggle={false}——按钮会隐藏,停靠位置会锁定为 position。
选择适合布局的初始停靠位置:
- 底部停靠(默认) — 最适合文档、营销和内容流网站,以及采用
height: 100%链的应用外壳(html { height: 100% }→body { height: 100% }→.app { height: 100% })。面板会将其高度写入--jr-devtools-offset-bottom,并为body应用对应的padding-bottom,因此非固定内容会自然腾出空间。 - 右侧停靠(
position="right")— 推荐用于采用100vh或position: fixed; bottom: 0的应用外壳布局。右侧停靠完全避开底部边缘,并将其宽度写入--jr-devtools-offset-right。
采用 100vh、position: fixed 或 position: sticky 的应用可以使用已发布的 CSS 自定义属性,为特定元素预留空间:
.composer { bottom: var(--jr-devtools-offset-bottom, 0); }
.sidebar { right: var(--jr-devtools-offset-right, 0); }
.app-shell { height: calc(100vh - var(--jr-devtools-offset-bottom, 0)); }
如果自动添加到 body 的内边距导致特定布局出现问题,请传入 reserveSpace={false},让面板仅作为覆盖层显示——CSS 自定义属性仍会发布,因此你仍可手动预留空间。
(--jr-devtools-offset 会作为兼容旧版本的别名,指向当前启用的边缘。)
单页上的多个渲染器(例如聊天)
单个 <JsonRenderDevtools /> 可以同时检查多个 <Renderer /> 实例——例如,每条助手消息都渲染自己的规范的聊天,或由多个独立组件构成的仪表板。具体做法:
- 使用一个顶层
<JSONUIProvider>,让每个渲染器共享同一个状态存储和操作分发器。Devtools 位于此 Provider 内部,可通过它查看所有内容。 - 每个渲染器使用各自的规范,共享状态 — 每条助手消息都直接渲染
<Renderer spec={msgSpec} registry={registry} />,而不是用自己的StateProvider包裹。不同消息的状态路径不得冲突。 - 按轮次为状态添加命名空间 — 如果数据源是 AI 流,请为 Agent 提供唯一的
messageId,并要求每个元素键(<id>-root)和状态路径(/<id>/count)都以此为前缀。 - 传入
spec={latest}+messages={all}—spec驱动 Spec 面板(通常是最新助手消息的规范),而messages则为 Stream 面板提供每一轮的补丁。 - 操作和选择器已经是全局的 —
registerActionObserver会捕获树中任何ActionProvider的分发操作,渲染器自身会写入data-jr-key,因此 Pick 可作用于每个已渲染元素,无论它由哪条消息生成。
请参阅 examples/devtools,了解按此方式接入的完整 AI 聊天示例。
命令式 API(仅限 React)
import { useJsonRenderDevtools } from "@json-render/devtools-react";
const devtools = useJsonRenderDevtools();
devtools?.open();
devtools?.toggle();
devtools?.recordEvent({ kind: "stream-text", at: Date.now(), text: "hi" });
在生产环境中或组件挂载前会返回 null。
服务端流拦截器
在 API 路由处捕获规范补丁,以便事件在服务端持久保存,或流入你自己的遥测系统。
import { tapJsonRenderStream, createEventStore } from "@json-render/devtools";
import { pipeJsonRender } from "@json-render/core";
const events = createEventStore({ bufferSize: 1000 });
const tapped = tapJsonRenderStream(result.toUIMessageStream(), events);
writer.merge(pipeJsonRender(tapped));
YAML 等效项:tapYamlStream。
实现原理
- 通过 Shadow DOM 隔离的面板 — 面板样式不会泄漏到宿主应用,反之亦然。
- 环形缓冲事件存储 — 对 devtools 事件日志(状态变更、操作分发、流补丁等)设有容量上限。
- 操作观察器注册表 — 每个框架的
ActionProvider都会通过@json-render/core中的notifyActionDispatch/notifyActionSettle报告;devtools 则通过registerActionObserver订阅。 - 为选择器标记元素 — devtools 挂载期间,
ElementRenderer会将每个已渲染元素包在<span data-jr-key="..." style="display:contents">中,以便选择器将 DOM 映射到规范键。不会影响布局。