From 45ffd1247cfadbfb510c42e4b20b33a2cee415e6 Mon Sep 17 00:00:00 2001 From: Damian Osipiuk Date: Tue, 7 Nov 2023 00:01:14 +0100 Subject: [PATCH 1/6] feat(vue-query): component based vue devtools - Vue3 only --- examples/vue/basic/package.json | 1 + examples/vue/basic/src/App.vue | 4 +- packages/vue-query-devtools/.eslintrc.cjs | 12 ++ packages/vue-query-devtools/package.json | 62 ++++++++++ packages/vue-query-devtools/src/devtools.vue | 40 +++++++ packages/vue-query-devtools/src/index.ts | 11 ++ packages/vue-query-devtools/src/production.ts | 3 + .../vue-query-devtools/src/shims-vue.d.ts | 6 + packages/vue-query-devtools/src/types.ts | 33 ++++++ packages/vue-query-devtools/tsconfig.json | 9 ++ packages/vue-query-devtools/vite.config.js | 29 +++++ packages/vue-query-devtools/vitest.config.ts | 12 ++ pnpm-lock.yaml | 107 +++++++++++++++++- scripts/config.js | 5 + 14 files changed, 331 insertions(+), 3 deletions(-) create mode 100644 packages/vue-query-devtools/.eslintrc.cjs create mode 100644 packages/vue-query-devtools/package.json create mode 100644 packages/vue-query-devtools/src/devtools.vue create mode 100644 packages/vue-query-devtools/src/index.ts create mode 100644 packages/vue-query-devtools/src/production.ts create mode 100644 packages/vue-query-devtools/src/shims-vue.d.ts create mode 100644 packages/vue-query-devtools/src/types.ts create mode 100644 packages/vue-query-devtools/tsconfig.json create mode 100644 packages/vue-query-devtools/vite.config.js create mode 100644 packages/vue-query-devtools/vitest.config.ts diff --git a/examples/vue/basic/package.json b/examples/vue/basic/package.json index 10244dd465..958afb1f49 100644 --- a/examples/vue/basic/package.json +++ b/examples/vue/basic/package.json @@ -9,6 +9,7 @@ }, "dependencies": { "@tanstack/vue-query": "^5.0.0", + "@tanstack/vue-query-devtools": "^5.0.0", "vue": "^3.3.0" }, "devDependencies": { diff --git a/examples/vue/basic/src/App.vue b/examples/vue/basic/src/App.vue index c8275e1840..5a9b09d3bf 100644 --- a/examples/vue/basic/src/App.vue +++ b/examples/vue/basic/src/App.vue @@ -1,12 +1,13 @@ + + diff --git a/packages/vue-query-devtools/src/index.ts b/packages/vue-query-devtools/src/index.ts new file mode 100644 index 0000000000..39c4912e86 --- /dev/null +++ b/packages/vue-query-devtools/src/index.ts @@ -0,0 +1,11 @@ +import devtools from './devtools.vue' +import type { DefineComponent } from 'vue' +import type { DevtoolsOptions } from './types' + +export const VueQueryDevtools = ( + process.env.NODE_ENV !== 'development' + ? function () { + return null + } + : devtools +) as DefineComponent diff --git a/packages/vue-query-devtools/src/production.ts b/packages/vue-query-devtools/src/production.ts new file mode 100644 index 0000000000..11cd60bd96 --- /dev/null +++ b/packages/vue-query-devtools/src/production.ts @@ -0,0 +1,3 @@ +import devtools from './devtools.vue' + +export default devtools diff --git a/packages/vue-query-devtools/src/shims-vue.d.ts b/packages/vue-query-devtools/src/shims-vue.d.ts new file mode 100644 index 0000000000..b07a05969e --- /dev/null +++ b/packages/vue-query-devtools/src/shims-vue.d.ts @@ -0,0 +1,6 @@ +declare module '*.vue' { + import type { DefineComponent } from 'vue' + + const component: DefineComponent<{}, {}, any> + export default component +} diff --git a/packages/vue-query-devtools/src/types.ts b/packages/vue-query-devtools/src/types.ts new file mode 100644 index 0000000000..fa350a4120 --- /dev/null +++ b/packages/vue-query-devtools/src/types.ts @@ -0,0 +1,33 @@ +import type { + DevToolsErrorType, + DevtoolsButtonPosition, + DevtoolsPosition, +} from '@tanstack/query-devtools' +import type { QueryClient } from '@tanstack/vue-query' + +export interface DevtoolsOptions { + /** + * Set this true if you want the dev tools to default to being open + */ + initialIsOpen?: boolean + /** + * The position of the React Query logo to open and close the devtools panel. + * 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' + * Defaults to 'bottom-left'. + */ + buttonPosition?: DevtoolsButtonPosition + /** + * The position of the React Query devtools panel. + * 'top' | 'bottom' | 'left' | 'right' + * Defaults to 'bottom'. + */ + position?: DevtoolsPosition + /** + * Custom instance of QueryClient + */ + client?: QueryClient + /** + * Use this so you can define custom errors that can be shown in the devtools. + */ + errorTypes?: Array +} diff --git a/packages/vue-query-devtools/tsconfig.json b/packages/vue-query-devtools/tsconfig.json new file mode 100644 index 0000000000..22796613f9 --- /dev/null +++ b/packages/vue-query-devtools/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "noEmit": false, + "emitDeclarationOnly": true, + "outDir": "dist" + }, + "include": ["src/**/*.ts", "src/**/*.vue", "shims-vue.d.ts"] +} diff --git a/packages/vue-query-devtools/vite.config.js b/packages/vue-query-devtools/vite.config.js new file mode 100644 index 0000000000..1a5c090954 --- /dev/null +++ b/packages/vue-query-devtools/vite.config.js @@ -0,0 +1,29 @@ +import { resolve } from 'path' +import { defineConfig } from 'vite' +import vuePlugin from '@vitejs/plugin-vue' + +export default defineConfig({ + plugins: [vuePlugin()], + build: { + lib: { + // Could also be a dictionary or array of multiple entry points + entry: [ + resolve(__dirname, 'src/index.ts'), + resolve(__dirname, 'src/production.ts'), + ], + formats: ['es'], + }, + rollupOptions: { + // make sure to externalize deps that shouldn't be bundled + // into your library + external: ['vue'], + output: { + // Provide global variables to use in the UMD build + // for externalized deps + globals: { + vue: 'Vue', + }, + }, + }, + }, +}) diff --git a/packages/vue-query-devtools/vitest.config.ts b/packages/vue-query-devtools/vitest.config.ts new file mode 100644 index 0000000000..d7af60d17e --- /dev/null +++ b/packages/vue-query-devtools/vitest.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from 'vitest/config' + +export default defineConfig({ + test: { + name: 'vue-query-devtools', + dir: './src', + watch: false, + setupFiles: ['test-setup.ts'], + environment: 'jsdom', + coverage: { provider: 'istanbul' }, + }, +}) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bf87c7714d..0539eb1811 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1306,6 +1306,9 @@ importers: '@tanstack/vue-query': specifier: ^5.0.0 version: link:../../../packages/vue-query + '@tanstack/vue-query-devtools': + specifier: ^5.0.0 + version: link:../../../packages/vue-query-devtools vue: specifier: ^3.3.0 version: 3.3.0 @@ -1860,6 +1863,28 @@ importers: specifier: npm:vue@2.7 version: /vue@2.7.0 + packages/vue-query-devtools: + dependencies: + '@tanstack/query-devtools': + specifier: workspace:* + version: link:../query-devtools + devDependencies: + '@tanstack/vue-query': + specifier: workspace:* + version: link:../vue-query + '@vitejs/plugin-vue': + specifier: ^4.4.0 + version: 4.4.0(vite@4.4.11)(vue@3.3.0) + vite: + specifier: ^4.4.4 + version: 4.4.11(@types/node@18.18.0) + vue: + specifier: ^3.3.0 + version: 3.3.0 + vue-tsc: + specifier: ^1.8.21 + version: 1.8.21(typescript@5.2.2) + packages: /@aashutoshrathi/word-wrap@1.2.6: @@ -9380,6 +9405,17 @@ packages: vite: 4.4.11(@types/node@18.18.0) vue: 3.3.0 + /@vitejs/plugin-vue@4.4.0(vite@4.4.11)(vue@3.3.0): + resolution: {integrity: sha512-xdguqb+VUwiRpSg+nsc2HtbAUSGak25DXYvpQQi4RVU1Xq1uworyoH/md9Rfd8zMmPR/pSghr309QNcftUVseg==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + vite: ^4.0.0 + vue: ^3.2.25 + dependencies: + vite: 4.4.11(@types/node@18.18.0) + vue: 3.3.0 + dev: true + /@vitest/coverage-istanbul@0.33.0(vitest@0.33.0): resolution: {integrity: sha512-DGv6ybomCbLFGlNOGHgVCsaqHPWJWLp8JPrwzZo8I4vZ/O3muqTyZq5R52CZl0ENqgjFGWjra7yNPFUgxKf5pw==} peerDependencies: @@ -9434,6 +9470,25 @@ packages: pretty-format: 29.7.0 dev: true + /@volar/language-core@1.10.10: + resolution: {integrity: sha512-nsV1o3AZ5n5jaEAObrS3MWLBWaGwUj/vAsc15FVNIv+DbpizQRISg9wzygsHBr56ELRH8r4K75vkYNMtsSNNWw==} + dependencies: + '@volar/source-map': 1.10.10 + dev: true + + /@volar/source-map@1.10.10: + resolution: {integrity: sha512-GVKjLnifV4voJ9F0vhP56p4+F3WGf+gXlRtjFZsv6v3WxBTWU3ZVeaRaEHJmWrcv5LXmoYYpk/SC25BKemPRkg==} + dependencies: + muggle-string: 0.3.1 + dev: true + + /@volar/typescript@1.10.10: + resolution: {integrity: sha512-4a2r5bdUub2m+mYVnLu2wt59fuoYWe7nf0uXtGHU8QQ5LDNfzAR0wK7NgDiQ9rcl2WT3fxT2AA9AylAwFtj50A==} + dependencies: + '@volar/language-core': 1.10.10 + path-browserify: 1.0.1 + dev: true + /@vue/compiler-core@3.3.0: resolution: {integrity: sha512-iYvUFe9/tIXNI1FyDCQYhkwJI5M9htqeCGfdZ2LiR+ZqVQE6KAH2+qUPdXixjMPUL36LdpVIBTNhxstx5RRhEw==} dependencies: @@ -9487,6 +9542,25 @@ packages: resolution: {integrity: sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q==} dev: false + /@vue/language-core@1.8.21(typescript@5.2.2): + resolution: {integrity: sha512-dKQJc1xfWIZfv6BeXyxz3SSNrC7npJpDIN/VOb1rodAm4o247TElrXOHYAJdV9x1KilaEUo3YbnQE+WA3vQwMw==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@volar/language-core': 1.10.10 + '@volar/source-map': 1.10.10 + '@vue/compiler-dom': 3.3.0 + '@vue/shared': 3.3.0 + computeds: 0.0.1 + minimatch: 9.0.3 + muggle-string: 0.3.1 + typescript: 5.2.2 + vue-template-compiler: 2.7.15 + dev: true + /@vue/reactivity-transform@3.3.0: resolution: {integrity: sha512-Pli2ClOXOEMG2AExCfUwiPQQo7U7zcRlnZLb6FI9ns/nEiQ9KLJJYD3wAuJHSx0VXLhACaINd/1VbMeKfa8GhQ==} dependencies: @@ -12017,6 +12091,10 @@ packages: transitivePeerDependencies: - supports-color + /computeds@0.0.1: + resolution: {integrity: sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==} + dev: true + /concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} @@ -12829,6 +12907,10 @@ packages: resolution: {integrity: sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==} dev: false + /de-indent@1.0.2: + resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==} + dev: true + /debug@2.6.9(supports-color@6.1.0): resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} peerDependencies: @@ -15968,7 +16050,6 @@ packages: /he@1.2.0: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true - dev: false /headers-polyfill@3.3.0: resolution: {integrity: sha512-5e57etwBpNcDc0b6KCVWEh/Ro063OxPvzVimUdM0/tsYM/T7Hfy3kknIGj78SFTOhNd8AZY41U8mOHoO4LzmIQ==} @@ -19971,6 +20052,10 @@ packages: - supports-color dev: false + /muggle-string@0.3.1: + resolution: {integrity: sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==} + dev: true + /multicast-dns-service-types@1.1.0: resolution: {integrity: sha512-cnAsSVxIDsYt0v7HmC0hWZFwwXSh+E6PgCrREDuN/EsjgLwA5XRmlMHhSiDPrt6HxY1gTivEa/Zh7GtODoLevQ==} dev: false @@ -20960,7 +21045,6 @@ packages: /path-browserify@1.0.1: resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} - dev: false /path-dirname@1.0.2: resolution: {integrity: sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==} @@ -26968,6 +27052,25 @@ packages: vue: 3.3.0 dev: false + /vue-template-compiler@2.7.15: + resolution: {integrity: sha512-yQxjxMptBL7UAog00O8sANud99C6wJF+7kgbcwqkvA38vCGF7HWE66w0ZFnS/kX5gSoJr/PQ4/oS3Ne2pW37Og==} + dependencies: + de-indent: 1.0.2 + he: 1.2.0 + dev: true + + /vue-tsc@1.8.21(typescript@5.2.2): + resolution: {integrity: sha512-gc9e+opdeF0zKixaadXT5v2s+x+77oqpuza/vwqDhdDyEeLZUOmZaVeb9noZpkdhFaLq7t7ils/7lFU8E/Hgew==} + hasBin: true + peerDependencies: + typescript: '*' + dependencies: + '@volar/typescript': 1.10.10 + '@vue/language-core': 1.8.21(typescript@5.2.2) + semver: 7.5.4 + typescript: 5.2.2 + dev: true + /vue@2.6.0: resolution: {integrity: sha512-QSKHpmV17wqDmS5jVCc8X9LyTcCCQP4M1RTRpLBO+hRveePduJaGz1FGjVpRVcE6cKYbhsooz6RW7GWLGNjKGg==} dev: true diff --git a/scripts/config.js b/scripts/config.js index acd8d1ae95..12d32a7700 100644 --- a/scripts/config.js +++ b/scripts/config.js @@ -98,6 +98,11 @@ export const packages = [ packageDir: 'packages/vue-query', entries: ['main', 'module', 'types'], }, + { + name: '@tanstack/vue-query-devtools', + packageDir: 'packages/vue-query-devtools', + entries: ['main', 'module', 'types'], + }, ] /** From 90a2dcbebf208ac9f1cb1af7f0014e8ec1ef0b3f Mon Sep 17 00:00:00 2001 From: Damian Osipiuk Date: Tue, 7 Nov 2023 00:09:42 +0100 Subject: [PATCH 2/6] fix: add `main` entry --- packages/vue-query-devtools/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/vue-query-devtools/package.json b/packages/vue-query-devtools/package.json index f5decd858f..9a21ed5938 100644 --- a/packages/vue-query-devtools/package.json +++ b/packages/vue-query-devtools/package.json @@ -17,6 +17,7 @@ "type": "module", "types": "dist/index.d.ts", "module": "dist/index.js", + "main": "dist/index.js", "exports": { ".": { "types": "./dist/index.d.ts", @@ -26,7 +27,7 @@ "types": "./dist/production.d.ts", "default": "./dist/production.js" }, - "./build/production.js": { + "./dist/production.js": { "types": "./dist/production.d.ts", "default": "./dist/production.js" }, From 8281d40d698a2b07f5ed3f5f9d720bb801a2e9ae Mon Sep 17 00:00:00 2001 From: Damian Osipiuk Date: Tue, 7 Nov 2023 00:20:38 +0100 Subject: [PATCH 3/6] fix: proper files specifier --- packages/vue-query-devtools/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vue-query-devtools/package.json b/packages/vue-query-devtools/package.json index 9a21ed5938..030e7cb865 100644 --- a/packages/vue-query-devtools/package.json +++ b/packages/vue-query-devtools/package.json @@ -35,7 +35,7 @@ }, "sideEffects": false, "files": [ - "build", + "dist", "src" ], "scripts": { From a190de30efe9d5ebe23cbd12bdd9170ef3e9a4be Mon Sep 17 00:00:00 2001 From: Damian Osipiuk Date: Tue, 7 Nov 2023 00:27:57 +0100 Subject: [PATCH 4/6] chore: remove scripts --- packages/vue-query-devtools/package.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/vue-query-devtools/package.json b/packages/vue-query-devtools/package.json index 030e7cb865..027b78754c 100644 --- a/packages/vue-query-devtools/package.json +++ b/packages/vue-query-devtools/package.json @@ -42,8 +42,6 @@ "clean": "rimraf ./build && rimraf ./coverage", "test:eslint": "eslint --ext .ts,.tsx ./src", "test:types": "tsc", - "test:lib": "vitest run --coverage", - "test:lib:dev": "pnpm run test:lib --watch", "test:build": "publint --strict", "build": "vite build && vue-tsc" }, From f8afdc85b79c4076b27eeca874dccbf7d306832c Mon Sep 17 00:00:00 2001 From: Damian Osipiuk Date: Tue, 7 Nov 2023 00:28:07 +0100 Subject: [PATCH 5/6] docs: update docs link --- packages/vue-query/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vue-query/README.md b/packages/vue-query/README.md index 4d24a42a5c..867d01a0e7 100644 --- a/packages/vue-query/README.md +++ b/packages/vue-query/README.md @@ -13,7 +13,7 @@ Support for Vue 2.x via [vue-demi](https://github.com/vueuse/vue-demi) # Documentation -Visit https://tanstack.com/query/v4/docs/adapters/vue-query +Visit https://tanstack.com/query/latest/docs/vue/overview # Quick Features From e4e9ea304ea42720fa53aa7510f55f90c96a0325 Mon Sep 17 00:00:00 2001 From: Damian Osipiuk Date: Tue, 7 Nov 2023 09:18:23 +0100 Subject: [PATCH 6/6] docs: component devtools --- docs/vue/devtools.md | 49 ++++++++++++++++++++ packages/vue-query-devtools/src/devtools.vue | 1 + packages/vue-query-devtools/src/types.ts | 4 ++ 3 files changed, 54 insertions(+) diff --git a/docs/vue/devtools.md b/docs/vue/devtools.md index f6a93fb085..2cb20971fb 100644 --- a/docs/vue/devtools.md +++ b/docs/vue/devtools.md @@ -11,3 +11,52 @@ The only thing you need to do is to install the official **[Vue Devtools](https: Vue Query will seamlessly integrate with the official devtools, adding custom inspector and timeline events. Devtool code will be treeshaken from production bundles by default. + +## Component based Devtools (Vue 3) + +You can embeed devtools component into your page by using dedicated package. +Component based devtools are using the same framework-agnostic implementation, have more features and are updated more frequently. + +The devtools component is a separate package that you need to install: + +```bash +$ npm i @tanstack/vue-query-devtools +# or +$ pnpm add @tanstack/vue-query-devtools +# or +$ yarn add @tanstack/vue-query-devtools +``` + +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. + +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. + +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! + +```vue + + + +``` + +### Options + +- `initialIsOpen: Boolean` + - Set this `true` if you want the dev tools to default to being open +- `buttonPosition?: "top-left" | "top-right" | "bottom-left" | "bottom-right"` + - Defaults to `bottom-left` + - The position of the React Query logo to open and close the devtools panel +- `position?: "top" | "bottom" | "left" | "right"` + - Defaults to `bottom` + - The position of the React Query devtools panel +- `client?: QueryClient`, + - Use this to use a custom QueryClient. Otherwise, the one from the nearest context will be used. +- `errorTypes?: { name: string; initializer: (query: Query) => TError}` + - 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. +- `styleNonce?: string` + - 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. diff --git a/packages/vue-query-devtools/src/devtools.vue b/packages/vue-query-devtools/src/devtools.vue index c5abb96d44..4f6937c38b 100644 --- a/packages/vue-query-devtools/src/devtools.vue +++ b/packages/vue-query-devtools/src/devtools.vue @@ -17,6 +17,7 @@ const devtools = new TanstackQueryDevtools({ position: props.position, initialIsOpen: props.initialIsOpen, errorTypes: props.errorTypes, + styleNonce: props.styleNonce, }) watchEffect(() => { diff --git a/packages/vue-query-devtools/src/types.ts b/packages/vue-query-devtools/src/types.ts index fa350a4120..87673849e1 100644 --- a/packages/vue-query-devtools/src/types.ts +++ b/packages/vue-query-devtools/src/types.ts @@ -30,4 +30,8 @@ export interface DevtoolsOptions { * Use this so you can define custom errors that can be shown in the devtools. */ errorTypes?: Array + /** + * 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. + */ + styleNonce?: string }