devtools

devtools

热门

适用于任何 json-render 应用的开箱即用开发者面板(Inspector Panel)。当用户需要调试生成式 UI(Generative UI)、查看 spec 树结构、在运行时修改状态、跟踪已触发的 action、实时监听流式 patch、浏览 Catalog 目录,或使用元素选择器拾取 DOM 节点以查找对应的 spec key 时使用。触发词包括“添加 devtools”、“调试 json-render”、“查看 spec”、“为什么这个元素没渲染”、“查看运行时状态”,以及针对 `@json-render/devtools` 监听流或捕获 action 日志的请求。

1.6万Star
852Fork
更新于 2026/7/8
SKILL.md
只读
名称
devtools
描述

适用于任何 json-render 应用的开箱即用开发者面板(Inspector Panel)。当用户需要调试生成式 UI(Generative UI)、查看 spec 树结构、在运行时修改状态、跟踪已触发的 action、实时监听流式 patch、浏览 Catalog 目录,或使用元素选择器拾取 DOM 节点以查找对应的 spec key 时使用。触发词包括“添加 devtools”、“调试 json-render”、“查看 spec”、“为什么这个元素没渲染”、“查看运行时状态”,以及针对 `@json-render/devtools` 监听流或捕获 action 日志的请求。

@json-render/devtools

适用于 json-render 应用的悬浮调试面板。核心库具备框架无关特性(Framework-agnostic),并提供适配各个框架的 Adapter(React、Vue、Svelte、Solid)。

生产环境安全:当 NODE_ENV === "production" 时,组件会直接渲染为 null

安装

安装核心包以及与宿主应用渲染器匹配的 Adapter。

# 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>(或各框架对应 Provider)内部的任意位置即可,无需额外接线配置。

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(可通过 hotkey prop 自定义)。
  • 抽屉面板支持调整大小;高度会自动持久化到 localStorage。

Props 属性

  • spec (Spec | null) — 当前 spec。
  • catalog (Catalog | null) — catalog 定义;Catalog 面板必需参数。
  • messages (UIMessage[]) — AI SDK 的 useChat 消息数组;用于解析提取其中的 spec 数据片段。
  • initialOpen (boolean) — 初始状态是否打开面板。
  • position ("bottom-right" | "bottom-left" | "right") — 停靠位置与切换按钮所在角。"bottom-*" 停靠在底部;"right" 停靠在右侧边缘全高展示(推荐已使用 100vh 或固定底部栏的应用 Shell 使用)。
  • 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/可见性/事件/监听器(watchers)详情;内置 validateSpec 校验警告提示。
  • State — 展示每个 JSON Pointer 路径,支持通过 store.set 进行内联编辑。
  • Actions — 已触发 action 的时间线(显示名称、参数、结果/报错、执行耗时)。
  • Stream — 按生成批次分组展示 spec patch、文本 Chunk、Token 使用量及生命周期标记。
  • Catalog — 目录中声明的组件与 action,带 prop 状态标签(chips)。

元素拾取器 Picker(工具栏)

元素拾取器是面板顶部工具栏中的一个按钮(类似 Chrome DevTools 风格),而不是独立的标签页。点击激活拾取模式后,点击页面中任意已渲染的元素,视图会自动跳转至 Spec 标签页并定位聚焦该元素。按 Esc 键可取消拾取。

空间预留与停靠策略

面板支持停靠在底部或右侧边缘,默认情况下用户可以通过工具栏按钮在这两种模式间切换(选择结果会持久化至 localStorage)。如果宿主应用仅兼容某一种停靠方式,可设置 allowDockToggle={false},此时按钮隐藏且停靠位置锁定为 position

根据你的页面布局选择初始停靠方式:

  • 底部停靠(默认) — 最适合文档/营销/内容流类网站,以及采用 height: 100% 链式继承的应用 Shell(即 html { height: 100% }body { height: 100% }.app { height: 100% })。面板会将自身高度写入 --jr-devtools-offset-bottom 并给 body 施加对应的 padding-bottom,使非固定定位的内容自动留出空间。
  • 右侧停靠position="right") — 推荐使用了 100vhposition: fixed; bottom: 0 的应用 Shell 布局使用。右侧停靠完全规避了底部边缘冲突,会将宽度写入 --jr-devtools-offset-right

使用了 100vhposition: fixedposition: 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 上加 padding 对特定布局造成了干扰,可以设置 reserveSpace={false} 让面板变为纯悬浮遮罩 — CSS 自定义属性依然会正常发布,方便你手动预留空间。

--jr-devtools-offset 作为兼容性保留别名,始终指向当前生效边缘的偏移量。)

单页面多渲染器场景(例如 AI Chat 对话)

单个 <JsonRenderDevtools /> 可以同时调试多个 <Renderer /> 实例 — 例如在 AI 聊天中,每条 Assistant 消息都渲染各自的 spec,或者由多个独立 Widget 组成的仪表盘等。实现方案如下:

  1. 顶层统一配置 <JSONUIProvider> — 确保所有 Renderer 共享同一个状态 Store 和 Action 派发器。Devtools 放置在该 Provider 内部即可捕获全局数据。
  2. Spec 按渲染器隔离,State 共享 — 每条 Assistant 消息直接渲染 <Renderer spec={msgSpec} registry={registry} />,不要外面包裹独立的 StateProvider。不同消息的状态路径切记不能冲突。
  3. 按对话 Turn 对 State 做命名空间隔离 — 数据源为 AI 流时,为 Agent 传入唯一的 messageId,并要求所有元素 Key(<id>-root)和 State 路径(/<id>/count)必须以该 messageId 为前缀。
  4. 传入 spec={latest} + messages={all}spec 用于驱动 Spec 面板(通常传入最新的 Assistant 消息 spec),而 messages 则为 Stream 面板提供每一轮对话的 patch 增量。
  5. Actions 与 Picker 本身即是全局生效registerActionObserver 会自动捕获组件树中任意 ActionProvider 派发的动作,且渲染器自身会自动注入 data-jr-key,因此无论元素由哪一条消息生成, Picker 都能正常工作。

完整实现方案请参考 examples/devtools 示例。

命令式 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

服务端流式监听(Stream Tap)

在 API Route 路由处理中捕获 spec patch,从而将事件持久化到服务端或接入自定义的数据埋点系统中。

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 隔离面板 — 面板样式采用 Shadow DOM 隔离,绝对不会污染宿主应用样式,反之亦然。
  • 环形缓冲区事件 Store — 定长记录 devtools 事件日志(状态变更、action 派发、流式 patch 等)。
  • Action Observer 注册表 — 各框架的 ActionProvider 通过 @json-render/core 中的 notifyActionDispatch / notifyActionSettle 进行上报;devtools 通过 registerActionObserver 完成事件订阅。
  • Picker 元素标记 — 当 devtools 挂载时,ElementRenderer 会用 <span data-jr-key="..." style="display:contents"> 包裹每个已渲染元素,从而让 Picker 建立 DOM 到 spec key 的映射关系,且完全不影响页面布局。