UNPKG

@tanstack/devtools-utils

Version:

TanStack Devtools utilities for creating your own devtools.

271 lines (208 loc) • 8.04 kB
# Vue Framework Adapter Reference ## Import ```ts import { createVuePlugin, createVuePanel } from '@tanstack/devtools-utils/vue' import type { DevtoolsPanelProps } from '@tanstack/devtools-utils/vue' ``` ## DevtoolsPanelProps ```ts // NOTE: Vue includes 'system' -- unlike React/Solid/Preact interface DevtoolsPanelProps { theme?: 'dark' | 'light' | 'system' } ``` ## createVuePlugin Creates a `[Plugin, NoOpPlugin]` tuple from a Vue component. **CRITICAL: Vue uses positional arguments `(name, component)`, NOT an options object.** ### Signature ```ts function createVuePlugin<TComponentProps extends Record<string, any>>( name: string, component: DefineComponent<TComponentProps, {}, unknown>, ): readonly [Plugin, NoOpPlugin] ``` ### Parameters | Parameter | Type | Required | Description | | ----------- | ---------------------------------- | -------- | -------------------------------------- | | `name` | `string` | Yes | Display name shown in the devtools tab | | `component` | `DefineComponent<TComponentProps>` | Yes | Vue component to render in the panel | Note: There is **no** `id` or `defaultOpen` parameter. Vue plugins are simpler. ### Return Value A `readonly [Plugin, NoOpPlugin]` tuple. Both are **functions that accept props**: - **`Plugin(props: TComponentProps)`** -- returns `{ name, component, props }` where `component` is your Vue component. - **`NoOpPlugin(props: TComponentProps)`** -- returns `{ name, component: Fragment, props }` where `Fragment` is Vue's built-in fragment (renders nothing visible). **This differs from React/Solid/Preact** where `Plugin()` takes no arguments. ### Source ```ts // packages/devtools-utils/src/vue/plugin.ts import { Fragment } from 'vue' import type { DefineComponent } from 'vue' export function createVuePlugin<TComponentProps extends Record<string, any>>( name: string, component: DefineComponent<TComponentProps, {}, unknown>, ) { function Plugin(props: TComponentProps) { return { name, component, props, } } function NoOpPlugin(props: TComponentProps) { return { name, component: Fragment, props, } } return [Plugin, NoOpPlugin] as const } ``` ### Usage #### Basic ```vue <!-- MyStorePanel.vue --> <script setup lang="ts"> import type { DevtoolsPanelProps } from '@tanstack/devtools-utils/vue' const props = defineProps<DevtoolsPanelProps>() </script> <template> <div :class="props.theme"> <h2>My Store Devtools</h2> </div> </template> ``` ```ts import { createVuePlugin } from '@tanstack/devtools-utils/vue' import MyStorePanel from './MyStorePanel.vue' const [MyPlugin, NoOpPlugin] = createVuePlugin('My Store', MyStorePanel) ``` #### Using the Plugin (Vue-specific -- pass props) ```ts // Vue plugins are called WITH props const plugin = MyPlugin({ theme: 'dark' }) // Returns: { name: 'My Store', component: MyStorePanel, props: { theme: 'dark' } } const noopPlugin = NoOpPlugin({ theme: 'dark' }) // Returns: { name: 'My Store', component: Fragment, props: { theme: 'dark' } } ``` #### Production Tree-Shaking ```ts const [MyPlugin, NoOpPlugin] = createVuePlugin('My Store', MyStorePanel) const ActivePlugin = import.meta.env.DEV ? MyPlugin : NoOpPlugin ``` ## createVuePanel Wraps a class-based devtools core in a Vue `defineComponent`. ### Signature ```ts function createVuePanel< TComponentProps extends DevtoolsPanelProps, TCoreDevtoolsClass extends { mount: (el: HTMLElement, theme?: DevtoolsPanelProps['theme']) => void unmount: () => void }, >( CoreClass: new (props: TComponentProps) => TCoreDevtoolsClass, ): readonly [Panel, NoOpPanel] ``` ### Parameters | Parameter | Type | Required | Description | | ----------- | ------------------------------------------------------------------------------ | -------- | ------------------------------------------------------------------------------------------------ | | `CoreClass` | `new (props: TComponentProps) => { mount(el, theme?): void; unmount(): void }` | Yes | Class constructor. **Note:** Vue's constructor takes `props`, unlike React's no-arg constructor. | ### Return Value A tuple of two Vue `DefineComponent`s: - **`Panel`** -- Accepts `theme` and `devtoolsProps` as props. On `onMounted`, instantiates `CoreClass(devtoolsProps)` and calls `mount(el, theme)`. On `onUnmounted`, calls `unmount()`. Renders a `<div style="height:100%">`. - **`NoOpPanel`** -- Renders `null`. Both components have the type: ```ts DefineComponent<{ theme?: 'dark' | 'light' | 'system' devtoolsProps: TComponentProps }> ``` ### Source ```ts // packages/devtools-utils/src/vue/panel.ts export function createVuePanel< TComponentProps extends DevtoolsPanelProps, TCoreDevtoolsClass extends { mount: (el: HTMLElement, theme?: DevtoolsPanelProps['theme']) => void unmount: () => void }, >(CoreClass: new (props: TComponentProps) => TCoreDevtoolsClass) { const props = { theme: { type: String as () => DevtoolsPanelProps['theme'] }, devtoolsProps: { type: Object as () => TComponentProps }, } const Panel = defineComponent({ props, setup(config) { const devToolRef = ref<HTMLElement | null>(null) const devtools = ref<TCoreDevtoolsClass | null>(null) onMounted(() => { const instance = new CoreClass(config.devtoolsProps as TComponentProps) devtools.value = instance if (devToolRef.value) { instance.mount(devToolRef.value, config.theme) } }) onUnmounted(() => { if (devToolRef.value && devtools.value) { devtools.value.unmount() } }) return () => h('div', { style: { height: '100%' }, ref: devToolRef }) }, }) const NoOpPanel = defineComponent({ props, setup() { return () => null }, }) return [Panel, NoOpPanel] as unknown as [ DefineComponent<{ theme?: DevtoolsPanelProps['theme'] devtoolsProps: TComponentProps }>, DefineComponent<{ theme?: DevtoolsPanelProps['theme'] devtoolsProps: TComponentProps }>, ] } ``` ### Usage ```ts import { createVuePanel, createVuePlugin } from '@tanstack/devtools-utils/vue' class MyDevtoolsCore { constructor(private props: { theme?: string }) {} mount(el: HTMLElement, theme?: 'dark' | 'light' | 'system') { // render into el } unmount() { // cleanup } } // Step 1: Create panel from class const [MyPanel, NoOpPanel] = createVuePanel(MyDevtoolsCore) // Step 2: Create plugin from panel const [MyPlugin, NoOpPlugin] = createVuePlugin('My Store', MyPanel) ``` #### Using the Panel Directly in a Template ```vue <template> <MyPanel theme="dark" :devtools-props="{ /* ... */ }" /> </template> ``` ## Vue-Specific Gotchas 1. **Positional arguments, not options object.** This is the most common mistake. `createVuePlugin('name', Component)`, not `createVuePlugin({ name, Component })`. 2. **Plugin functions accept props.** `MyPlugin(props)` returns `{ name, component, props }`. This differs from React/Solid/Preact where `Plugin()` takes no arguments. 3. **Theme includes `'system'`.** Vue's `DevtoolsPanelProps` accepts `'dark' | 'light' | 'system'`, while all other frameworks only accept `'light' | 'dark'`. 4. **No `id` or `defaultOpen`.** The Vue `createVuePlugin` API only takes `name` and `component`. There is no `id` or `defaultOpen` parameter. 5. **Panel constructor takes props.** `createVuePanel`'s `CoreClass` constructor receives props: `new CoreClass(devtoolsProps)`. React/Preact/Solid constructors take no arguments. 6. **`devtoolsProps` prop on panel.** The Vue panel component has a separate `devtoolsProps` prop for forwarding data to the core class, in addition to the `theme` prop.