devtools について
@json-render/devtools は、json-render アプリ向けのフローティングインスペクタです。React、Vue、Svelte、Solid を使う開発者が仕様、状態、アクション、ストリームイベント、カタログを確認でき、要素ピッカーとドック位置の変更にも対応します。
主な機能
- 01要素ツリーと検証警告の確認
- 02JSON Pointer 状態の表示と編集
- 03アクションの実行と結果の追跡
- 04仕様ストリームのパッチとイベント確認
- 05ページ要素から仕様内の位置を特定
活用シーン
- 01AI 生成 UI のデバッグ
- 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" の場合、ブラウザーに process グローバルがない環境でバンドラーがこの式を置き換える場合も含め、コンポーネントは開発ツールの UI を表示しません。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
ドロップインでの使用
既存の <JSONUIProvider>(または各フレームワークに相当するプロバイダー)の内側で、任意の場所に <JsonRenderDevtools /> を配置します。ほかに必要な設定はありません。
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 パネルを使用するには必須です。messages(UIMessage[]) — AI SDK のuseChatメッセージ。spec データパーツを検索します。initialOpen(boolean) — 開いた状態で開始します。position("bottom-right" | "bottom-left" | "right") — ドックと切り替えボタンの位置です。"bottom-*"は画面下部にドックし、"right"は右端に全高でドックします(すでに100vhまたは固定の下部バーを使用しているアプリシェルに推奨)。hotkey(string | false) — デフォルトは"mod+shift+j"です。bufferSize(number) — イベントリングバッファーの上限。デフォルトは 500 です。reserveSpace(boolean, defaulttrue) —trueの場合、bodyにpadding-bottom/padding-rightを適用し、パネルがホストアプリを押し出します。パネルを純粋なオーバーレイとして表示するにはfalseを設定します。allowDockToggle(boolean, defaulttrue) — ツールバーボタンを表示し、ユーザーがパネルを下部ドックと右側ドックの間で切り替えられるようにします。ユーザーの選択はlocalStorageに保存され、次回以降のマウントではpositionより優先されます。ドック位置をpositionに固定するにはfalseを渡します。onEvent((DevtoolsEvent) => void) — 任意のイベントフックです。
パネル
- Spec —
spec.rootをルートとする要素ツリー。props/表示状態/イベント/watcher の詳細と、統合されたvalidateSpecの警告を表示します。 - State — すべての JSON Pointer パスを表示し、
store.setでその場で編集できます。 - Actions — ディスパッチされたアクションのタイムライン(名前、パラメーター、結果/エラー、所要時間)を表示します。
- Stream — spec パッチ、テキストチャンク、トークン使用量、ライフサイクルマーカーを生成ごとにまとめて表示します。
- Catalog — カタログで宣言されたコンポーネントとアクションを、prop のチップとともに表示します。
ピッカー(ツールバー)
要素ピッカーはタブではなく、パネルヘッダーのツールバーボタン(Chrome DevTools 風)です。クリックしてピックモードを有効にし、ページ上のレンダリング済み要素をクリックすると、その要素にフォーカスした状態で Spec タブに移動します。キャンセルするには Esc を押します。
スペースの確保とドッキング
パネルは下端または右端にドッキングできます。デフォルトでは、ユーザーはツールバーボタンで2つを切り替えられます(選択は 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 は、現在アクティブな端に対応する後方互換用エイリアスとして維持されています。)
1ページ上の複数のレンダラー(例:チャット)
1つの <JsonRenderDevtools /> で、多数の <Renderer /> インスタンスを同時に調査できます。たとえば、アシスタントの各メッセージがそれぞれの spec をレンダリングするチャットや、複数の独立したウィジェットで構成されるダッシュボードなどです。手順は次のとおりです。
- トップレベルの
<JSONUIProvider>を1つだけ使うことで、すべてのレンダラーが1つの状態ストアとアクションディスパッチャーを共有します。Devtools はこのプロバイダー内に配置し、プロバイダーを通じてすべてを確認します。 - レンダラーごとに spec を設定し、状態は共有する — 各アシスタントメッセージは、独自の
StateProviderでラップせず、<Renderer spec={msgSpec} registry={registry} />を直接レンダリングします。異なるメッセージの状態パスが衝突しないようにしてください。 - ターンごとに状態を名前空間化する — ソースが AI ストリームの場合、エージェントに一意の
messageIdを渡し、すべての要素キー(<id>-root)と状態パス(/<id>/count)にその ID を接頭辞として付けるようにします。 spec={latest}とmessages={all}を渡す —specは Spec パネルに表示する内容を決定します(通常は最新のアシスタントメッセージの spec)。一方、messagesは Stream パネルにすべてのターンのパッチを渡します。- アクションとピッカーはすでにグローバルです —
registerActionObserverはツリー内の任意のActionProviderからのディスパッチをキャプチャし、data-jr-keyはレンダラー自体によって設定されるため、どのメッセージが要素を生成したかにかかわらず、レンダリングされたすべての要素で Pick を使えます。
この方法で構成された AI チャットの完全な例は 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 を返します。
サーバーサイドのストリームタップ
API ルートで spec のパッチをキャプチャし、イベントをサーバー側に永続化するか、独自のテレメトリに流し込みます。
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 から spec キーを特定できるようにします。レイアウトへの影響はありません。