本页还没有译文
本页 75 段还没译成Русский,下面显示的是英文原文。Using devtools-utils
还没翻译译自英文(tanstack.com)本页 75 段都还没译
@tanstack/devtools-utils provides factory functions that simplify creating devtools plugins for each framework. Instead of manually wiring up render functions and no-op variants, these helpers produce correctly-typed plugin objects (and their production-safe no-op counterparts) from your components. Each framework has its own subpath export with an API tailored to that framework's conventions.
Installation
npm install @tanstack/devtools-utilsDevtoolsPanelProps
Every panel component receives a theme prop so the panel can match the devtools shell appearance. The interface is defined per-framework in each subpath:
interface DevtoolsPanelProps {
theme?: 'light' | 'dark'
}The Vue and Svelte variants additionally accept
'system'as a theme value.
Import it from the framework-specific subpath:
// React
import type { DevtoolsPanelProps } from '@tanstack/devtools-utils/react'
// Solid
import type { DevtoolsPanelProps } from '@tanstack/devtools-utils/solid'
// Preact
import type { DevtoolsPanelProps } from '@tanstack/devtools-utils/preact'
// Vue
import type { DevtoolsPanelProps } from '@tanstack/devtools-utils/vue'
// Svelte
import type { DevtoolsPanelProps } from '@tanstack/devtools-utils/svelte'
// Angular
import type { DevtoolsPanelProps } from '@tanstack/devtools-utils/angular'React
createReactPlugin
Creates a [Plugin, NoOpPlugin] tuple from a React component and plugin metadata.
Signature:
function createReactPlugin(options: {
name: string
id?: string
defaultOpen?: boolean
Component: (props: DevtoolsPanelProps) => JSX.Element
}): readonly [Plugin, NoOpPlugin]Usage:
import { createReactPlugin } from '@tanstack/devtools-utils/react'
const [MyPlugin, NoOpPlugin] = createReactPlugin({
name: 'My Store',
id: 'my-store',
defaultOpen: false,
Component: ({ theme }) => <MyStorePanel theme={theme} />,
})The returned tuple contains two factory functions:
Plugin()-- returns a plugin object withname,id,defaultOpen, and arenderfunction that renders yourComponentwith the current plugin props.NoOpPlugin()-- returns a plugin object with the same metadata but arenderfunction that renders an empty fragment. Use this for production builds where you want to strip devtools out.
A common pattern for tree-shaking:
const [MyPlugin, NoOpPlugin] = createReactPlugin({ /* ... */ })
const ActivePlugin = process.env.NODE_ENV === 'development' ? MyPlugin : NoOpPlugincreateReactPanel
For library authors shipping a class-based devtools core that exposes mount(el, props) and unmount() methods. This factory wraps that class in a React component that handles mounting into a div, passing the complete plugin props, and cleaning up on unmount.
Signature:
function createReactPanel<
TComponentProps extends DevtoolsPanelProps,
TCoreDevtoolsClass extends {
mount: (el: HTMLElement, props: DevtoolsPanelProps) => void
unmount: () => void
},
>(CoreClass: new () => TCoreDevtoolsClass): readonly [Panel, NoOpPanel]Usage:
import {
createReactPanel,
type DevtoolsPanelProps,
} from '@tanstack/devtools-utils/react'
class MyDevtoolsCore {
mount(el: HTMLElement, props: DevtoolsPanelProps) {
// render your devtools UI into el
}
unmount() {
// cleanup
}
}
const [MyPanel, NoOpPanel] = createReactPanel(MyDevtoolsCore)
// Then use the panel component inside createReactPlugin:
const [MyPlugin, NoOpPlugin] = createReactPlugin({
name: 'My Store',
Component: MyPanel,
})The returned Panel component:
- Creates a
divwithheight: 100%and stores a ref to it. - Instantiates
CoreClasson mount and callscore.mount(el, props). - Calls
core.unmount()on cleanup. - Re-mounts when the plugin props change.
NoOpPanel renders an empty fragment and does nothing.
Preact
createPreactPlugin
Identical API to createReactPlugin, using Preact's JSX types. Import from @tanstack/devtools-utils/preact.
Signature:
function createPreactPlugin(options: {
name: string
id?: string
defaultOpen?: boolean
Component: (props: DevtoolsPanelProps) => JSX.Element
}): readonly [Plugin, NoOpPlugin]Usage:
import { createPreactPlugin } from '@tanstack/devtools-utils/preact'
const [MyPlugin, NoOpPlugin] = createPreactPlugin({
name: 'My Store',
id: 'my-store',
Component: ({ theme }) => <MyStorePanel theme={theme} />,
})The return value and behavior are the same as createReactPlugin -- a [Plugin, NoOpPlugin] tuple where Plugin renders your component and NoOpPlugin renders nothing.
createPreactPanel
Also available for Preact with the same class-based API as createReactPanel:
import { createPreactPanel } from '@tanstack/devtools-utils/preact'
const [MyPanel, NoOpPanel] = createPreactPanel(MyDevtoolsCore)Solid
createSolidPlugin
Same option-object API as React and Preact, using Solid's JSX types. Import from @tanstack/devtools-utils/solid.
Signature:
function createSolidPlugin(options: {
name: string
id?: string
defaultOpen?: boolean
Component: (props: DevtoolsPanelProps) => JSX.Element
}): readonly [Plugin, NoOpPlugin]Usage:
import { createSolidPlugin } from '@tanstack/devtools-utils/solid'
const [MyPlugin, NoOpPlugin] = createSolidPlugin({
name: 'My Store',
id: 'my-store',
Component: (props) => <MyStorePanel theme={props.theme} />,
})createSolidPanel
Solid also provides a class-based panel factory. It uses createSignal and onMount/onCleanup instead of React hooks:
import { createSolidPanel } from '@tanstack/devtools-utils/solid'
const [MyPanel, NoOpPanel] = createSolidPanel(MyDevtoolsCore)Vue
createVuePlugin
The Vue factory has a different API from the JSX-based frameworks. It takes a name string and a Vue DefineComponent as separate arguments rather than an options object.
Signature:
function createVuePlugin<TComponentProps extends Record<string, any>>(
name: string,
component: DefineComponent<TComponentProps, {}, unknown>,
): readonly [Plugin, NoOpPlugin]Usage:
import { createVuePlugin } from '@tanstack/devtools-utils/vue'
import MyStorePanel from './MyStorePanel.vue'
const [MyPlugin, NoOpPlugin] = createVuePlugin('My Store', MyStorePanel)The returned functions differ from the JSX-based variants:
Plugin(props)-- returns{ name, component, props }wherecomponentis your Vue component.NoOpPlugin(props)-- returns{ name, component: Fragment, props }where the component is Vue's built-inFragment(renders nothing visible).
Both accept props that get forwarded to the component.
createVuePanel
For class-based devtools cores, Vue provides createVuePanel. It creates a Vue defineComponent that handles mounting and unmounting the core class:
import { createVuePanel } from '@tanstack/devtools-utils/vue'
const [MyPanel, NoOpPanel] = createVuePanel(MyDevtoolsCore)The panel component accepts theme and devtoolsProps as props. It mounts the core instance into a div element on onMounted and calls unmount() on onUnmounted.
Svelte
createSveltePlugin
The Svelte factory takes the plugin metadata and Svelte component in a configuration object.
Signature:
function createSveltePlugin<TComponentProps extends Record<string, any>>(
config: {
name: string
id?: string
defaultOpen?: boolean
Component: Component<TComponentProps>
},
): readonly [Plugin, NoOpPlugin]Usage:
import { createSveltePlugin } from '@tanstack/devtools-utils/svelte'
import MyStorePanel from './MyStorePanel.svelte'
const [MyPlugin, NoOpPlugin] = createSveltePlugin({
Component: MyStorePanel,
name: 'My Store',
id: 'my-store',
defaultOpen: true,
})The returned functions:
Plugin(props?)-- returns the plugin metadata, component, and forwarded props.NoOpPlugin(props?)-- preserves the plugin metadata and props but replaces the component with one that renders nothing visible.
Both accept an optional props object that gets forwarded to the component on mount.
createSveltePanel
For class-based devtools cores, Svelte provides createSveltePanel. It creates a wrapper that handles mounting and unmounting the core class:
import { createSveltePanel } from '@tanstack/devtools-utils/svelte'
const [MyPanel, NoOpPanel] = createSveltePanel(MyDevtoolsCore)The panel constructs the core without arguments. It creates a div element, passes the complete { theme, devtoolsOpen } plugin props to mount(), and registers unmount() with Svelte's component cleanup lifecycle.
Angular
createAngularPlugin
The Angular factory takes a name string and an Angular component class as separate arguments, similar to the Vue API.
Signature:
function createAngularPlugin(
name: string,
component: Type<any>,
): readonly [Plugin, NoOpPlugin]Usage:
import { createAngularPlugin } from '@tanstack/devtools-utils/angular'
import { MyStorePanelComponent } from './my-store-panel.component'
const [MyPlugin, NoOpPlugin] = createAngularPlugin('My Store', MyStorePanelComponent)The returned functions:
Plugin(inputs?)-- returns{ name, component, inputs }wherecomponentis your Angular component class.NoOpPlugin(inputs?)-- returns{ name, component: NoOpComponent, inputs }where the component is an empty standalone component (renders nothing visible).
Both accept an optional inputs object that gets forwarded to the component via setInput().
createAngularPanel
For class-based devtools cores, Angular provides createAngularPanel. It creates a standalone Angular component that handles mounting and unmounting the core class:
import { createAngularPanel } from '@tanstack/devtools-utils/angular'
const [MyPanel, NoOpPanel] = createAngularPanel(MyDevtoolsCore)The panel component accepts theme and devtoolsProps as signal inputs. It mounts the core instance into a div element using afterNextRender and calls unmount() via DestroyRef.onDestroy.
When to Use Factories vs Manual Plugin Objects
Use the factories when you are building a reusable library plugin that will be published as a package. The factories ensure:
- Consistent plugin object shape across frameworks.
- A matching
NoOpPluginvariant for production tree-shaking. - Correct typing without manual type annotations.
Use manual plugin objects when you are building a one-off internal devtools panel for your application. In that case, passing name and render directly to the devtools configuration is simpler and avoids the extra abstraction:
// Manual approach -- fine for one-off panels
{
name: 'App State',
render: (el, theme) => <MyPanel theme={theme} />,
}The factory approach becomes more valuable as you add id, defaultOpen, and need both a development and production variant of the same plugin.