Skip to content

Commit e0fbfc5

Browse files
committed
feat(vue-query-devtools): Add VueQueryDevtoolsPanel support
1 parent c14a17d commit e0fbfc5

21 files changed

+333
-29
lines changed

docs/config.json

+4
Original file line numberDiff line numberDiff line change
@@ -983,6 +983,10 @@
983983
{
984984
"label": "Persister",
985985
"to": "framework/vue/examples/persister"
986+
},
987+
{
988+
"label": "Devtools Embedded Panel",
989+
"to": "framework/vue/examples/devtools-panel"
986990
}
987991
]
988992
},

docs/framework/vue/devtools.md

+33-1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ bun add @tanstack/vue-query-devtools
3838

3939
By default, Vue Query Devtools are only included in bundles when `process.env.NODE_ENV === 'development'`, so you don't need to worry about excluding them during a production build.
4040

41+
## Floating Mode
42+
43+
@todo: blabla
44+
4145
Devtools will be mounted as a fixed, floating element in your app and provide a toggle in the corner of the screen to show and hide the devtools. This toggle state will be stored and remembered in localStorage across reloads.
4246

4347
Place the following code as high in your Vue app as you can. The closer it is to the root of the page, the better it will work!
@@ -57,9 +61,10 @@ import { VueQueryDevtools } from '@tanstack/vue-query-devtools'
5761

5862
- `initialIsOpen: Boolean`
5963
- Set this `true` if you want the dev tools to default to being open.
60-
- `buttonPosition?: "top-left" | "top-right" | "bottom-left" | "bottom-right"`
64+
- `buttonPosition?: "top-left" | "top-right" | "bottom-left" | "bottom-right" | "relative"`
6165
- Defaults to `bottom-right`.
6266
- The position of the React Query logo to open and close the devtools panel.
67+
- If `relative`, the button is placed in the location that you render the devtools.
6368
- `position?: "top" | "bottom" | "left" | "right"`
6469
- Defaults to `bottom`.
6570
- The position of the React Query devtools panel.
@@ -73,6 +78,33 @@ import { VueQueryDevtools } from '@tanstack/vue-query-devtools'
7378
- Default behavior will apply the devtool's styles to the head tag within the DOM.
7479
- Use this to pass a shadow DOM target to the devtools so that the styles will be applied within the shadow DOM instead of within the head tag in the light DOM.
7580

81+
## Embedded Mode
82+
83+
@todo: blabla
84+
85+
### Options
86+
87+
- `style?: React.CSSProperties`
88+
- Custom styles for the devtools panel
89+
- Default: `{ height: '500px' }`
90+
- Example: `{ height: '100%' }`
91+
- Example: `{ height: '100%', width: '100%' }`
92+
- `onClose?: () => unknown`
93+
- Callback function that is called when the devtools panel is closed
94+
- `client?: QueryClient`,
95+
- Use this to use a custom QueryClient. Otherwise, the one from the nearest context will be used.
96+
- `errorTypes?: { name: string; initializer: (query: Query) => TError}[]`
97+
- Use this to predefine some errors that can be triggered on your queries. Initializer will be called (with the specific query) when that error is toggled on from the UI. It must return an Error.
98+
- `styleNonce?: string`
99+
- Use this to pass a nonce to the style tag that is added to the document head. This is useful if you are using a Content Security Policy (CSP) nonce to allow inline styles.
100+
- `shadowDOMTarget?: ShadowRoot`
101+
- Default behavior will apply the devtool's styles to the head tag within the DOM.
102+
- Use this to pass a shadow DOM target to the devtools so that the styles will be applied within the shadow DOM instead of within the head tag in the light DOM.
103+
104+
## Devtools in production
105+
106+
@todo: blabla
107+
76108
## Traditional Devtools
77109

78110
Vue Query will seamlessly integrate with the [Official Vue devtools](https://github.com/vuejs/devtools-next), adding custom inspector and timeline events.
+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
node_modules
2+
.DS_Store
3+
dist
4+
dist-ssr
5+
*.local
6+
7+
package-lock.json
8+
yarn.lock
9+
pnpm-lock.yaml

examples/vue/devtools-panel/README.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Basic example
2+
3+
To run this example:
4+
5+
- `npm install` or `yarn` or `pnpm i` or `bun i`
6+
- `npm run dev` or `yarn dev` or `pnpm dev` or `bun dev`
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>TanStack Query Vue Devtools Panel Example App</title>
7+
</head>
8+
<body>
9+
<div id="app"></div>
10+
<script type="module" src="/src/main.ts"></script>
11+
</body>
12+
</html>
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"name": "@tanstack/query-example-vue-devtools-panel",
3+
"private": true,
4+
"type": "module",
5+
"scripts": {
6+
"dev": "vite",
7+
"build": "vite build",
8+
"preview": "vite preview"
9+
},
10+
"dependencies": {
11+
"@tanstack/vue-query": "^5.54.1",
12+
"@tanstack/vue-query-devtools": "^5.54.1",
13+
"vue": "^3.4.27",
14+
"vue-demi": "^0.14.10"
15+
},
16+
"devDependencies": {
17+
"@vitejs/plugin-vue": "^5.1.1",
18+
"typescript": "5.3.3",
19+
"vite": "^5.3.5"
20+
}
21+
}
+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<script lang="ts">
2+
import { defineComponent } from 'vue'
3+
import { useQuery } from '@tanstack/vue-query'
4+
import { VueQueryDevtoolsPanel } from '@tanstack/vue-query-devtools'
5+
6+
export default defineComponent({
7+
name: 'App',
8+
components: { VueQueryDevtoolsPanel },
9+
setup() {
10+
const { data, error, isFetching, isPending } = useQuery({
11+
queryKey: ['repoData'],
12+
async queryFn() {
13+
return await fetch('https://api.github.com/repos/Tanstack/query').then(
14+
(response) => response.json(),
15+
)
16+
},
17+
})
18+
19+
return {
20+
data,
21+
error,
22+
isFetching,
23+
isPending,
24+
}
25+
},
26+
})
27+
</script>
28+
29+
// @todo: add button to switch between open & close devtools panel
30+
31+
<template>
32+
<template v-if="isPending"> Loading... </template>
33+
<template v-else-if="error">
34+
'An error has occurred: {{ error.message }}
35+
</template>
36+
<template v-else>
37+
<h1>{{ data.name }}</h1>
38+
<p>{{ data.description }}</p>
39+
<strong>👀 {{ data.subscribers_count }}</strong>
40+
<strong>✨ {{ data.stargazers_count }}</strong>
41+
<strong>🍴 {{ data.forks_count }}</strong>
42+
<div>{{ isFetching ? 'Updating...' : '' }}</div>
43+
</template>
44+
<VueQueryDevtoolsPanel />
45+
</template>
+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { createApp } from 'vue'
2+
import { VueQueryPlugin } from '@tanstack/vue-query'
3+
4+
import App from './App.vue'
5+
6+
createApp(App).use(VueQueryPlugin).mount('#app')
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
declare module '*.vue' {
2+
import { DefineComponent } from 'vue'
3+
const component: DefineComponent<{}, {}, any>
4+
export default component
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export interface Post {
2+
userId: number
3+
id: number
4+
title: string
5+
body: string
6+
}
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"compilerOptions": {
3+
"target": "esnext",
4+
"module": "esnext",
5+
"moduleResolution": "node",
6+
"strict": true,
7+
"jsx": "preserve",
8+
"sourceMap": true,
9+
"resolveJsonModule": true,
10+
"esModuleInterop": true,
11+
"lib": ["esnext", "dom"],
12+
"types": ["vite/client"]
13+
},
14+
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.vue"]
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { defineConfig } from 'vite'
2+
import vue from '@vitejs/plugin-vue'
3+
4+
export default defineConfig({
5+
plugins: [vue()],
6+
optimizeDeps: {
7+
exclude: ['@tanstack/vue-query', 'vue-demi'],
8+
},
9+
})

packages/react-query-devtools/src/ReactQueryDevtools.tsx

+5-5
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,23 @@ import type { QueryClient } from '@tanstack/react-query'
1111

1212
export interface DevtoolsOptions {
1313
/**
14-
* Set this true if you want the dev tools to default to being open
14+
* Set this true if you want the dev tools to default to being open.
1515
*/
1616
initialIsOpen?: boolean
1717
/**
1818
* The position of the React Query logo to open and close the devtools panel.
19-
* 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'
20-
* Defaults to 'bottom-right'.
19+
* 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'relative'
20+
* @default 'bottom-right'
2121
*/
2222
buttonPosition?: DevtoolsButtonPosition
2323
/**
2424
* The position of the React Query devtools panel.
2525
* 'top' | 'bottom' | 'left' | 'right'
26-
* Defaults to 'bottom'.
26+
* @default 'bottom'
2727
*/
2828
position?: DevtoolsPosition
2929
/**
30-
* Custom instance of QueryClient
30+
* Custom instance of QueryClient.
3131
*/
3232
client?: QueryClient
3333
/**

packages/react-query-devtools/src/ReactQueryDevtoolsPanel.tsx

+3-5
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import type { QueryClient } from '@tanstack/react-query'
77

88
export interface DevtoolsPanelOptions {
99
/**
10-
* Custom instance of QueryClient
10+
* Custom instance of QueryClient.
1111
*/
1212
client?: QueryClient
1313
/**
@@ -22,17 +22,15 @@ export interface DevtoolsPanelOptions {
2222
* Use this so you can attach the devtool's styles to specific element in the DOM.
2323
*/
2424
shadowDOMTarget?: ShadowRoot
25-
2625
/**
27-
* Custom styles for the devtools panel
26+
* Custom styles for the devtools panel.
2827
* @default { height: '500px' }
2928
* @example { height: '100%' }
3029
* @example { height: '100%', width: '100%' }
3130
*/
3231
style?: React.CSSProperties
33-
3432
/**
35-
* Callback function that is called when the devtools panel is closed
33+
* Callback function that is called when the devtools panel is closed.
3634
*/
3735
onClose?: () => unknown
3836
}

packages/vue-query-devtools/package.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,12 @@
5454
"eslint-plugin-vue": "^9.27.0",
5555
"vite": "^5.3.5",
5656
"vue": "^3.4.27",
57+
"vue-demi": "^0.14.10",
5758
"vue-tsc": "^2.0.26"
5859
},
5960
"peerDependencies": {
6061
"@tanstack/vue-query": "workspace:^",
61-
"vue": "^3.3.0"
62+
"vue": "^3.3.0",
63+
"vue-demi": "^0.14.0"
6264
}
6365
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<script setup lang="ts">
2+
import { onlineManager, useQueryClient } from '@tanstack/vue-query'
3+
import { TanstackQueryDevtoolsPanel } from '@tanstack/query-devtools'
4+
import { onMounted, onScopeDispose, ref, watchEffect } from 'vue'
5+
import { reactive } from 'vue-demi'
6+
import type { DevtoolsPanelOptions } from './types'
7+
8+
const props = defineProps<DevtoolsPanelOptions>()
9+
10+
const styleObject = reactive({
11+
height: '500px',
12+
...props.style,
13+
})
14+
15+
const div = ref<HTMLElement>()
16+
const client = props.client || useQueryClient()
17+
const devtools = new TanstackQueryDevtoolsPanel({
18+
client,
19+
queryFlavor: 'Vue Query',
20+
version: '5',
21+
onlineManager,
22+
buttonPosition: 'bottom-left',
23+
position: 'bottom',
24+
initialIsOpen: true,
25+
errorTypes: props.errorTypes,
26+
styleNonce: props.styleNonce,
27+
shadowDOMTarget: props.shadowDOMTarget,
28+
onClose: props.onClose,
29+
})
30+
31+
watchEffect(() => {
32+
devtools.setOnClose(props.onClose ?? (() => {}))
33+
devtools.setErrorTypes(props.errorTypes || [])
34+
})
35+
36+
onMounted(() => {
37+
devtools.mount(div.value as HTMLElement)
38+
})
39+
40+
onScopeDispose(() => {
41+
devtools.unmount()
42+
})
43+
</script>
44+
45+
<template>
46+
<div :style="styleObject" className="tsqd-parent-container" ref="div"></div>
47+
</template>
+12-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
1-
import devtools from './devtools.vue'
1+
import Devtools from './VueQueryDevtools.vue'
2+
import DevtoolsPanel from './VueQueryDevtoolsPanel.vue'
23
import type { DefineComponent } from 'vue'
3-
import type { DevtoolsOptions } from './types'
4+
import type { DevtoolsOptions, DevtoolsPanelOptions } from './types'
45

56
export const VueQueryDevtools = (
67
process.env.NODE_ENV !== 'development'
78
? function () {
89
return null
910
}
10-
: devtools
11+
: Devtools
1112
) as DefineComponent<DevtoolsOptions, {}, unknown>
13+
14+
export const VueQueryDevtoolsPanel = (
15+
process.env.NODE_ENV !== 'development'
16+
? function () {
17+
return null
18+
}
19+
: DevtoolsPanel
20+
) as DefineComponent<DevtoolsPanelOptions, {}, unknown>
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1-
import devtools from './devtools.vue'
1+
import Devtools from './VueQueryDevtools.vue'
2+
import DevtoolsPanel from './VueQueryDevtoolsPanel.vue'
23

3-
export default devtools
4+
export const VueQueryDevtools = Devtools
5+
export const VueQueryDevtoolsPanel = DevtoolsPanel

0 commit comments

Comments
 (0)