Solid Query Devtools 实战指南:安装接入、Floating/Embedded 两种模式与全部配置项解析
Solid Query(TanStack Query 的 Solid 适配层)自带一套专用开发调试工具 @tanstack/solid-query-devtools,用于可视化 Query Cache 内部状态、批量触发重取(refetch)、手动注入错误与观察缓存结构,能显著缩短排查查询状态问题的耗时。读完本文,你将掌握 Devtools 的安装与导入方式、Floating 与 Embedded 两种挂载模式的完整写法、全部 Props 的含义与默认值,并理解它如何基于 Solid 响应式机制与 QueryClient 联动,以及为何无需在构建阶段手动剔除即可安全用于生产环境。本仓库即 TanStack Query 官方 monorepo,源码层面相关实现可参考 devtools.md 对应的 solid-query-devtools 包。
Devtools 能帮你做什么
当你刚开始使用 Solid Query 时,最值得放在手边的就是这套 Devtools:它把查询的整个生命周期——缓存读写、加载/成功/失败状态切换、后台刷新、失效与垃圾回收——以可视化面板的形式呈现出来,并且允许你直接操作查询(例如手动触发 refetch、模拟错误)。官方文档将其定位为“在需要排查时能省下数小时调试时间”的核心工具。
如果你使用 Chrome、Firefox 或 Edge,还可以直接在浏览器官方扩展商店搜索安装 TanStack Query Devtools 浏览器扩展,它提供与框架专用 Devtools 包完全一致的功能,适合需要随时跟随页面一起调试的场合。框架内接入方式仍然是本文介绍的独立 npm 包方案。
安装与导入
Devtools 是与核心库分开的独立包,需要通过包管理器单独安装:
npm i @tanstack/solid-query-devtools
pnpm add @tanstack/solid-query-devtools
yarn add @tanstack/solid-query-devtools
bun add @tanstack/solid-query-devtools
安装完成后导入即可使用:
import { SolidQueryDevtools } from '@tanstack/solid-query-devtools'
从包的依赖声明看,package.json 要求 peer 依赖 @tanstack/solid-query(与 Devtools 版本配套的 workspace 包)以及 solid-js@^1.6.0,运行时代码则内部依赖 @tanstack/query-devtools(跨框架共享的 Devtools 内核)。
只在客户端与开发环境生效:无需手动剔除
官方文档特别强调:默认情况下,Devtools 只有在开发构建中才会真正被挂载,因此不需要在生产构建时手动做 exclude 处理。这句话背后有两层源码机制可以印证:
- 在 src/index.tsx 中,
SolidQueryDevtools与SolidQueryDevtoolsPanel的导出都由solid-js/web的isDev判定:开发环境下走clientOnly(() => import('./devtools'))的动态导入;非开发环境下直接导出一个渲染null的空组件,功能体根本不会被打包进生产产物。 clientOnly(见 clientOnly.tsx,该工具函数借鉴自 solid-start 的 island 实现)在服务端渲染(SSR)期间返回fallback,确保 Devtools 只在浏览器端挂载,不会给 SSR 输出带来任何副作用。
这一行为也有对应测试覆盖:tests/devtools.test.tsx 中通过 mock isDev = false 验证了“生产环境下组件渲染返回 null”。因此你可以放心地把 <SolidQueryDevtools /> 直接放进组件树,无需关心按环境条件渲染。
Floating 模式(浮动悬浮模式)
Floating 模式会把 Devtools 挂载为应用中的固定定位浮动元素,并在屏幕角落渲染一个用于展开/收起面板的切换按钮。切换状态会持久化到 localStorage,页面刷新后依然保持上次的开合状态。
官方建议把组件放在 Solid 应用中尽可能靠上、接近页面根部的位置,这样它才能正常访问到全局状态。典型用法如下:
import { SolidQueryDevtools } from '@tanstack/solid-query-devtools'
function App() {
return (
<QueryClientProvider client={queryClient}>
{/* 应用的其他部分 */}
<SolidQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
)
}
注意:必须把 <SolidQueryDevtools /> 放在 QueryClientProvider 之内,或者通过 client prop 显式传入 QueryClient。否则组件在初始化时调用 useQueryClient 会抛出错误——测试用例将其明确为 'No QueryClient set, use QueryClientProvider to set one'(见 devtools.test.tsx)。
Floating 模式选项
| 选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
initialIsOpen |
boolean |
false |
设为 true 时,Devtools 面板初始即为展开状态 |
buttonPosition |
"top-left" | "top-right" | "bottom-left" | "bottom-right" | "relative" |
"bottom-right" |
用于开关面板的 TanStack 图标的屏幕位置 |
position |
"top" | "bottom" | "left" | "right" |
"bottom" |
Solid Query Devtools 面板展开后停靠的方向 |
client |
QueryClient |
最近上下文中的 client | 传入自定义 QueryClient;不传则使用最近 QueryClientProvider 提供的实例 |
errorTypes |
{ name: string; initializer: (query: Query) => TError }[] |
[] |
预定义一批可在 UI 上手动“投喂”给查询的错误;当你在面板里点击触发某个错误时,initializer 会被调用(传入对应的 query),且必须返回一个 Error |
styleNonce |
string |
无 | 传给注入到 <head> 的 <style> 标签的 nonce,用于配合 CSP(内容安全策略)放行内联样式 |
shadowDOMTarget |
ShadowRoot |
无(样式注入页面 <head>) |
传入 Shadow DOM 根节点后,Devtools 样式会注入到该 shadow DOM 内部而非 light DOM 的 <head> |
theme |
"light" | "dark" | "system" |
"system" |
面板主题 |
hideDisabledQueries |
boolean |
false |
为 true 时,面板中隐藏处于 disabled 状态的查询。该选项在 devtools.tsx 的 DevtoolsOptions 接口中有完整定义,官方文档选项列表中虽未单列,但在源码与底层 @tanstack/query-devtools 中均受支持 |
预定义错误:errorTypes 用法示例
errorTypes 适合用于验证应用对不同错误分支的 UI 表现,例如模拟“鉴权失败”后观察页面是否正确跳转或展示错误态:
const errorTypes = [
{
name: 'Network Error',
initializer: (query) => new Error(`请求失败:${query.queryKey.join('/')}`),
},
{
name: 'Auth Failed',
initializer: () => new Error('Unauthorized'),
},
]
function App() {
return (
<QueryClientProvider client={queryClient}>
<SolidQueryDevtools errorTypes={errorTypes} />
</QueryClientProvider>
)
}
定义之后,你就能在 Devtools 面板中为某条查询一键触发这些错误,用来测试组件对异常数据的处理是否符合预期。
Embedded 模式(内嵌模式)
Embedded 模式会把 Devtools 作为应用内的一个固定元素渲染出来,方便把它整合进你自己开发的工具面板或布局中。与 Floating 模式由面板自行管理开合不同,Embedded 模式的开合由你通过 Solid 的响应式状态自行控制。官方示例使用 createSignal 配合 <Show> 实现一个“打开/关闭面板”按钮:
import { createSignal, Show } from 'solid-js'
import { SolidQueryDevtoolsPanel } from '@tanstack/solid-query-devtools'
function App() {
const [isOpen, setIsOpen] = createSignal(false)
return (
<QueryClientProvider client={queryClient}>
{/* 应用的其他部分 */}
<button
onClick={() => setIsOpen(!isOpen())}
>{`${isOpen() ? 'Close' : 'Open'} the devtools panel`}</button>
<Show when={isOpen()}>
<SolidQueryDevtoolsPanel onClose={() => setIsOpen(false)} />
</Show>
</QueryClientProvider>
)
}
Embedded 模式选项
| 选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
style |
JSX.CSSProperties |
{ height: '500px' } |
面板的自定义样式。例如 { height: '100%' } 或 { height: '100%', width: '100%' } 让面板占满容器 |
onClose |
() => void |
无 | 面板被关闭时回调。内置的关闭按钮会调用它,因此通常用它把外部 isOpen 信号重置为 false |
client |
QueryClient |
最近上下文中的 client | 同 Floating 模式,用于指定自定义 QueryClient |
errorTypes |
{ name: string; initializer: (query: Query) => TError }[] |
[] |
与 Floating 模式一致的预定义错误列表 |
styleNonce |
string |
无 | CSP nonce,作用于注入文档的样式标签 |
shadowDOMTarget |
ShadowRoot |
无(样式注入页面 <head>) |
将样式作用于指定的 Shadow DOM |
theme |
"light" | "dark" | "system" |
"system" |
面板主题 |
hideDisabledQueries |
boolean |
false |
是否在面板中隐藏 disabled 查询,详见 devtoolsPanel.tsx 的 DevtoolsPanelOptions |
从 devtoolsPanel.tsx 的实现细节看,面板容器外层有一个 tsqd-parent-container 类名的包裹节点,其默认样式由源码中 style={{ height: '500px', ...props.style }} 合并而来——因此你传入的 style 中的 height/width 会覆盖默认的 500px。与 Floating 模式内部强制 initialIsOpen: true、固定 buttonPosition: 'bottom-left' 不同,Panel 直接以下一步你希望它保持打开的状态交给外部信号驱动,onClose 则负责把状态同步回去。
底层原理:组件与 Devtools 实例的响应式联动
两个入口组件的源码结构非常清晰,均是对跨框架共享内核 @tanstack/query-devtools 中 TanstackQueryDevtools / TanstackQueryDevtoolsPanel 的薄封装:
- 创建实例时显式传入
queryFlavor: 'Solid Query'、version: '5'以及 Solid Query 的onlineManager,使面板正确识别框架身份与在线状态(见 devtools.tsx)。 - 组件通过
useQueryClient(props.client)解析QueryClient,并用createMemo缓存。 - 每个配置项都对应一个
createEffect,例如setClient、setButtonPosition、setPosition、setInitialIsOpen、setErrorTypes、setTheme等。这意味着Props 中传入的 Solid signal 发生变化时,Devtools 会响应式地同步更新,无需手动刷新面板。 - 组件在
onMount时调用devtools.mount(ref)将面板挂载到真实的 DOM 容器中,并在组件卸载时通过onCleanup(() => devtools.unmount())完成资源清理。
tests/devtools.test.tsx 对上述联动逐一做了验证:包括“未提供 QueryClient 时抛错”“通过 context 或 props 提供 client 均可用”“buttonPosition/position/initialIsOpen/errorTypes/theme 能正确转发到内核实例”“挂载后修改 props 仍能同步”“组件卸载时调用 unmount”,以及“非开发环境渲染返回 null”。如果你要给 Solid Query 集成自定义调试能力,这些测试也是一份很好的参考模板。
真实示例:在应用中接入 Devtools
本仓库自带的 Solid 示例已展示最简接入形态。以 examples/solid/basic/src/index.tsx 为例:应用先创建配置了 24 小时 gcTime 的 queryClient,在 App 组件中把 <SolidQueryDevtools /> 紧跟在 QueryClientProvider 之后渲染,不做任何额外配置即可获得默认 bottom-right 悬浮按钮与底部展开面板;配合示例的 posts 列表/详情切换逻辑,可以直观看到首次加载、缓存命中即显以及后台刷新的全过程。这个例子同样也演示了如何结合 queryKey 缓存判断(queryClient.getQueryData(['post', postId]))来实现“已缓存条目加粗”的交互——这正是 Devtools 面板中 Query Cache 可视化对应的运行时状态。
接入前的基础设施可参考 installation.md 与 quick-start.md,确保 QueryClient、QueryClientProvider 与 useQuery 的使用姿势正确(Solid Query 中这些原语的参数是函数形式,且不支持在响应式上下文外解构返回值)。
最佳实践小结
- 放置位置尽量高:无论 Floating 还是 Embedded 模式,都放在
QueryClientProvider内、靠近应用根部的位置,保证所有查询都能被面板观察到。 - 无需关心生产剔除:
isDev+clientOnly的双重机制保证了生产构建与 SSR 环境零负担,可以始终保留这行代码。 - 合理使用预定义错误:用
errorTypes提前构造鉴权失败、网络异常等分支,在 UI 上做回归验证。 - 进阶场景:涉及 shadow DOM 组件库时用
shadowDOMTarget收敛样式注入;站点启用严格 CSP 且放行内联样式依赖 nonce 时用styleNonce;需要跟随系统外观或与自身品牌风格一致时用theme。 - 自制工具面板:选择 Embedded 模式的
SolidQueryDevtoolsPanel,通过 signal 控制开合,并用style适配容器尺寸。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0629
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python07
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00