用途 该技能用于通过 @tanstack/devtools-utils 的工厂函数,为各个前端框架构建 devtools 插件适配器。每个框架拥有对应子路径导出(/react、/vue、/solid、/preact),每个子路径提供两类工厂函数。
主要能力
- createXPlugin:将组件包装为 [Plugin, NoOpPlugin] 元组,便于 tree-shaking。Plugin 返回带有元数据与 render 函数的插件对象;NoOpPlugin 返回相同元数据但渲染空 fragment。
- createXPanel:将基于类的 devtools 核心(mount/unmount)包装为 [Panel, NoOpPanel] 组件元组。Panel 组件创建 <div style="height:100%">,实例化核心类,在挂载时调用 core.mount(el, theme),在清理时调用 core.unmount();NoOpPanel 渲染空 fragment。
关键源文件
- packages/devtools-utils/src/react/plugin.tsx — createReactPlugin
- packages/devtools-utils/src/react/panel.tsx — createReactPanel、DevtoolsPanelProps
- packages/devtools-utils/src/vue/plugin.ts — createVuePlugin(API 不同)
- packages/devtools-utils/src/vue/panel.ts — createVuePanel、DevtoolsPanelProps(含 'system' 主题)
- packages/devtools-utils/src/solid/plugin.tsx — createSolidPlugin
- packages/devtools-utils/src/solid/panel.tsx — createSolidPanel
- packages/devtools-utils/src/solid/class.ts — constructCoreClass(Solid 专用)
- packages/devtools-utils/src/preact/plugin.tsx — createPreactPlugin
- packages/devtools-utils/src/preact/panel.tsx — createPreactPanel
使用方式 DevtoolsPanelProps 类型定义:
// React, Solid, Preact
interface DevtoolsPanelProps {
theme?: 'light' | 'dark'
}
// Vue(注意:包含 'system')
interface DevtoolsPanelProps {
theme?: 'dark' | 'light' | 'system'
}
从框架子路径导入类型:
import type { DevtoolsPanelProps } from '@tanstack/devtools-utils/react'
import type { DevtoolsPanelProps } from '@tanstack/devtools-utils/vue'
import type { DevtoolsPanelProps } from '@tanstack/devtools-utils/solid'
import type { DevtoolsPanelProps } from '@tanstack/devtools-utils/preact'
主要示例(React):
import { createReactPlugin } from '@tanstack/devtools-utils/react'
function MyStorePanel({ theme }: { theme?: 'light' | 'dark' }) {
return <div className={theme}>My Store Devtools</div>
}
const [MyPlugin, NoOpPlugin] = createReactPlugin({
name: 'My Store',
id: 'my-store',
defaultOpen: false,
Component: MyStorePanel,
})
// Tree-shaking: use NoOp in production
const ActivePlugin =
process.env.NODE_ENV === 'development' ? MyPlugin : NoOpPlugin
配合基于类的 Panel:
import {
createReactPanel,
createReactPlugin,
} from '@tanstack/devtools-utils/react'
class MyDevtoolsCore {
mount(el: HTMLElement, theme: 'light' | 'dark') {
/* render into el */
}
unmount() {
/* cleanup */
}
}
const [MyPanel, NoOpPanel] = createReactPanel(MyDevtoolsCore)
const [MyPlugin, NoOpPlugin] = createReactPlugin({
name: 'My Store',
Component: MyPanel,
})
各框架 API 差异 React 与 Preact —— 选项对象:
createReactPlugin({ name, id?, defaultOpen?, Component }) // => [Plugin, NoOpPlugin]
createPreactPlugin({ name, id?, defaultOpen?, Component }) // => [Plugin, NoOpPlugin]
Component 接收 DevtoolsPanelProps(含 theme)。Plugin() 返回 { name, id?, defaultOpen?, render(el, theme) }。Preact 与 React 相同,但使用 Preact JSX 类型与 preact/hooks。
Vue —— 位置参数,非选项对象:
createVuePlugin(name: string, component: DefineComponent) // => [Plugin, NoOpPlugin]
接收 (name, component) 作为独立参数,而非选项对象。Plugin(props) 返回 { name, component, props },透传 props。NoOpPlugin(props) 返回 { name, component: Fragment, props }。Vue 的 DevtoolsPanelProps.theme 也接受 'system'。
Solid —— 与 React 相同的 API,内部实现不同:
createSolidPlugin({ name, id?, defaultOpen?, Component }) // => [Plugin, NoOpPlugin]
与 React 相同的选项对象 API。Component 必须是 Solid 组件函数 (props: DevtoolsPanelProps) => JSX.Element。render 函数内部返回 <Component theme={theme} />,由 Solid 处理响应式。Solid 还从 @tanstack/devtools-utils/solid/class 导出 constructCoreClass,用于构建懒加载的 devtools 核心。
常见错误 严重:在 Vue 适配器中使用 React JSX 模式。Vue 使用位置参数 (name, component),而非选项对象:
// 错误
const [MyPlugin, NoOpPlugin] = createVuePlugin({
name: 'My Plugin',
Component: MyPanel,
})
// 正确
const [MyPlugin, NoOpPlugin] = createVuePlugin('My Plugin', MyPanel)
Vue 插件在调用时也不同——需传入 props:
// 错误
const plugin = MyPlugin()
// 正确
const plugin = MyPlugin({ theme: 'dark' })
严重:Solid 渲染 prop 未包裹在函数中。使用 Solid 组件时,Component 必须是函数引用,而非原始 JSX:
// 错误
createSolidPlugin({
name: 'My Store',
Component: <MyPanel />,
})
// 正确
createSolidPlugin({
name: 'My Store',
Component: (props) => <MyPanel theme={props.theme} />,
})
// 也正确
createSolidPlugin({
name: 'My Store',
Component: MyPanel,
})
高:忽略 NoOp 变体用于生产环境。工厂返回 [Plugin, NoOpPlugin],两者都必须解构使用以实现正确的 tree-shaking:
// 错误
const [MyPlugin] = createReactPlugin({ name: 'Store', Component: MyPanel })
// 正确
const [MyPlugin, NoOpPlugin] = createReactPlugin({
name: 'Store',
Component: MyPanel,
})
const ActivePlugin =
process.env.NODE_ENV === 'development' ? MyPlugin : NoOpPlugin
中:未向 Panel 组件传递 theme prop。DevtoolsPanelProps 包含 theme,devtools 外壳会传递它,以便面板匹配浅色/深色模式。若组件忽略它,面板将不会随主题变化而适配:
// 错误
const Component = () => <div>My Panel</div>
// 正确
const Component = ({ theme }: DevtoolsPanelProps) => (
<div className={theme === 'dark' ? 'dark-mode' : 'light-mode'}>My Panel</div>
)
设计张力 核心架构与框架无关,但每个框架有不同惯用法:React/Preact 使用选项对象,Component 为 JSX 函数组件;Vue 使用位置参数与 DefineComponent,并透传 props;Solid 使用与 React 相同的选项 API,但采用 Solid 的 JSX 与响应式模型。基于 React 模式训练的 Agent 容易把 Vue 写错,务必检查导入路径以确定使用哪种工厂 API。
交叉引用
- devtools-plugin-panel —— 先构建面板组件,再用合适的框架适配器包装。
- devtools-production —— NoOp 变体是从生产包中剥离 devtools 的主要机制。
参考文件
- references/react.md —— 完整 React 工厂 API 与示例
- references/vue.md —— 完整 Vue 工厂 API 与示例(与 React 不同)
- references/solid.md —— 完整 Solid 工厂 API 与示例
- references/preact.md —— 完整 Preact 工厂 API 与示例