SuperAPI AI 工具集

devtools-framework-adapters

编程与开发

查看项目

更新于 10-16 04:50

技能介绍

用途 该技能用于通过 @tanstack/devtools-utils 的工厂函数,为各个前端框架构建 devtools 插件适配器。每个框架拥有对应子路径导出(/react、/vue、/solid、/preact),每个子路径提供两类工厂函数。

主要能力

  1. createXPlugin:将组件包装为 [Plugin, NoOpPlugin] 元组,便于 tree-shaking。Plugin 返回带有元数据与 render 函数的插件对象;NoOpPlugin 返回相同元数据但渲染空 fragment。
  2. 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 与示例