From 99dcfc701251844b84a9c3c38b64eb1cef3f84a9 Mon Sep 17 00:00:00 2001 From: n0099 Date: Fri, 23 May 2025 22:25:14 +0000 Subject: [PATCH 01/11] feat: allow passing `DehydrateOptions` as nuxt module option to `dehydrate()` --- packages/vue-query-nuxt/src/runtime/plugin.ts | 4 ++-- packages/vue-query-nuxt/src/runtime/utils.ts | 8 +++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/vue-query-nuxt/src/runtime/plugin.ts b/packages/vue-query-nuxt/src/runtime/plugin.ts index a6562c9a..2159cf52 100644 --- a/packages/vue-query-nuxt/src/runtime/plugin.ts +++ b/packages/vue-query-nuxt/src/runtime/plugin.ts @@ -5,7 +5,7 @@ import { pluginHook } from "#build/internal.vue-query-plugin-hook" import { defineNuxtPlugin, useRuntimeConfig, useState } from "#imports" export default defineNuxtPlugin((nuxt) => { - const { stateKey, queryClientOptions, vueQueryPluginOptions } = getVueQueryOptions(useRuntimeConfig()) + const { stateKey, queryClientOptions, vueQueryPluginOptions, dehydrateOptions } = getVueQueryOptions(useRuntimeConfig()) const vueQueryState = useState(stateKey) const queryClient = new QueryClient(queryClientOptions) @@ -16,7 +16,7 @@ export default defineNuxtPlugin((nuxt) => { if (import.meta.server) { nuxt.hooks.hook("app:rendered", () => { - vueQueryState.value = dehydrate(queryClient) + vueQueryState.value = dehydrate(queryClient, dehydrateOptions) }) } diff --git a/packages/vue-query-nuxt/src/runtime/utils.ts b/packages/vue-query-nuxt/src/runtime/utils.ts index 074ad144..1c5ba1d7 100644 --- a/packages/vue-query-nuxt/src/runtime/utils.ts +++ b/packages/vue-query-nuxt/src/runtime/utils.ts @@ -1,4 +1,4 @@ -import type { QueryClientConfig, VueQueryPluginOptions } from "@tanstack/vue-query" +import type { QueryClientConfig, VueQueryPluginOptions, DehydrateOptions } from "@tanstack/vue-query" import type { RuntimeConfig } from "nuxt/schema" export const NAME = "vue-query-nuxt" as const @@ -19,7 +19,8 @@ export interface ModuleOptions { stateKey: string autoImports: VueQueryComposables | false queryClientOptions: QueryClientConfig | undefined - vueQueryPluginOptions: VueQueryPluginOptions + vueQueryPluginOptions: VueQueryPluginOptions, + dehydrateOptions: DehydrateOptions } export const defaults: ModuleOptions = { @@ -28,7 +29,8 @@ export const defaults: ModuleOptions = { queryClientOptions: { defaultOptions: { queries: { staleTime: 5000 } } }, - vueQueryPluginOptions: {} + vueQueryPluginOptions: {}, + dehydrateOptions: {} } export function getVueQueryOptions(config: RuntimeConfig) { return config.public[configKey] as ModuleOptions From 6f7dfce99c0075665e4f2cf8c5aca5068d1abe40 Mon Sep 17 00:00:00 2001 From: n0099 Date: Sun, 25 May 2025 20:32:45 +0000 Subject: [PATCH 02/11] fix: workaround for cannot pass function to module config: https://github.com/nuxt/nuxt/issues/20933 --- packages/vue-query-nuxt/src/runtime/plugin.ts | 14 +++++++++++--- packages/vue-query-nuxt/src/runtime/utils.ts | 3 ++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/packages/vue-query-nuxt/src/runtime/plugin.ts b/packages/vue-query-nuxt/src/runtime/plugin.ts index 2159cf52..058f5af4 100644 --- a/packages/vue-query-nuxt/src/runtime/plugin.ts +++ b/packages/vue-query-nuxt/src/runtime/plugin.ts @@ -1,6 +1,6 @@ -import type { DehydratedState } from "@tanstack/vue-query" +import type { DehydratedState, DehydrateOptions } from "@tanstack/vue-query" import { QueryClient, VueQueryPlugin, dehydrate, hydrate } from "@tanstack/vue-query" -import { getVueQueryOptions } from "./utils" +import { getVueQueryOptions, dehydrateOptionKeys } from "./utils" import { pluginHook } from "#build/internal.vue-query-plugin-hook" import { defineNuxtPlugin, useRuntimeConfig, useState } from "#imports" @@ -16,7 +16,15 @@ export default defineNuxtPlugin((nuxt) => { if (import.meta.server) { nuxt.hooks.hook("app:rendered", () => { - vueQueryState.value = dehydrate(queryClient, dehydrateOptions) + vueQueryState.value = dehydrate(queryClient, dehydrateOptionKeys.reduce((newDehydrateOptions, key) => { + if (dehydrateOptions[key] !== undefined) { + // https://stackoverflow.com/questions/64408632/typescript-inconsistent-check-for-undefined-why-do-i-need-an-exclamation-poin + // https://stackoverflow.com/questions/60077761/typescript-null-check-doesnt-work-inside-array-map-function/60077855#60077855 + const narrowedValue = dehydrateOptions[key] + newDehydrateOptions[key] = () => narrowedValue + } + return newDehydrateOptions + }, {})) }) } diff --git a/packages/vue-query-nuxt/src/runtime/utils.ts b/packages/vue-query-nuxt/src/runtime/utils.ts index 1c5ba1d7..9ab9d388 100644 --- a/packages/vue-query-nuxt/src/runtime/utils.ts +++ b/packages/vue-query-nuxt/src/runtime/utils.ts @@ -15,12 +15,13 @@ const composables = [ ] as const type VueQueryComposables = typeof composables +export const dehydrateOptionKeys = ['shouldDehydrateMutation', 'shouldDehydrateQuery', 'shouldRedactErrors'] as Array; export interface ModuleOptions { stateKey: string autoImports: VueQueryComposables | false queryClientOptions: QueryClientConfig | undefined vueQueryPluginOptions: VueQueryPluginOptions, - dehydrateOptions: DehydrateOptions + dehydrateOptions: { [P in typeof dehydrateOptionKeys[number]]?: boolean } } export const defaults: ModuleOptions = { From b36330e74c8a7dbcd948b83b3ad5804650c6ac37 Mon Sep 17 00:00:00 2001 From: n0099 Date: Mon, 26 May 2025 00:29:10 +0000 Subject: [PATCH 03/11] Revert "fix: workaround for cannot pass function to module config: https://github.com/nuxt/nuxt/issues/20933" This reverts commit 6f7dfce99c0075665e4f2cf8c5aca5068d1abe40. --- packages/vue-query-nuxt/src/runtime/plugin.ts | 14 +++----------- packages/vue-query-nuxt/src/runtime/utils.ts | 3 +-- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/packages/vue-query-nuxt/src/runtime/plugin.ts b/packages/vue-query-nuxt/src/runtime/plugin.ts index 058f5af4..2159cf52 100644 --- a/packages/vue-query-nuxt/src/runtime/plugin.ts +++ b/packages/vue-query-nuxt/src/runtime/plugin.ts @@ -1,6 +1,6 @@ -import type { DehydratedState, DehydrateOptions } from "@tanstack/vue-query" +import type { DehydratedState } from "@tanstack/vue-query" import { QueryClient, VueQueryPlugin, dehydrate, hydrate } from "@tanstack/vue-query" -import { getVueQueryOptions, dehydrateOptionKeys } from "./utils" +import { getVueQueryOptions } from "./utils" import { pluginHook } from "#build/internal.vue-query-plugin-hook" import { defineNuxtPlugin, useRuntimeConfig, useState } from "#imports" @@ -16,15 +16,7 @@ export default defineNuxtPlugin((nuxt) => { if (import.meta.server) { nuxt.hooks.hook("app:rendered", () => { - vueQueryState.value = dehydrate(queryClient, dehydrateOptionKeys.reduce((newDehydrateOptions, key) => { - if (dehydrateOptions[key] !== undefined) { - // https://stackoverflow.com/questions/64408632/typescript-inconsistent-check-for-undefined-why-do-i-need-an-exclamation-poin - // https://stackoverflow.com/questions/60077761/typescript-null-check-doesnt-work-inside-array-map-function/60077855#60077855 - const narrowedValue = dehydrateOptions[key] - newDehydrateOptions[key] = () => narrowedValue - } - return newDehydrateOptions - }, {})) + vueQueryState.value = dehydrate(queryClient, dehydrateOptions) }) } diff --git a/packages/vue-query-nuxt/src/runtime/utils.ts b/packages/vue-query-nuxt/src/runtime/utils.ts index 9ab9d388..1c5ba1d7 100644 --- a/packages/vue-query-nuxt/src/runtime/utils.ts +++ b/packages/vue-query-nuxt/src/runtime/utils.ts @@ -15,13 +15,12 @@ const composables = [ ] as const type VueQueryComposables = typeof composables -export const dehydrateOptionKeys = ['shouldDehydrateMutation', 'shouldDehydrateQuery', 'shouldRedactErrors'] as Array; export interface ModuleOptions { stateKey: string autoImports: VueQueryComposables | false queryClientOptions: QueryClientConfig | undefined vueQueryPluginOptions: VueQueryPluginOptions, - dehydrateOptions: { [P in typeof dehydrateOptionKeys[number]]?: boolean } + dehydrateOptions: DehydrateOptions } export const defaults: ModuleOptions = { From 84958af1b08cf8e2ed88b04b511d19188bb38e9c Mon Sep 17 00:00:00 2001 From: n0099 Date: Mon, 26 May 2025 00:40:04 +0000 Subject: [PATCH 04/11] Revert "feat: allow passing `DehydrateOptions` as nuxt module option to `dehydrate()`" This reverts commit 99dcfc701251844b84a9c3c38b64eb1cef3f84a9. --- packages/vue-query-nuxt/src/runtime/plugin.ts | 4 ++-- packages/vue-query-nuxt/src/runtime/utils.ts | 8 +++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/packages/vue-query-nuxt/src/runtime/plugin.ts b/packages/vue-query-nuxt/src/runtime/plugin.ts index 2159cf52..a6562c9a 100644 --- a/packages/vue-query-nuxt/src/runtime/plugin.ts +++ b/packages/vue-query-nuxt/src/runtime/plugin.ts @@ -5,7 +5,7 @@ import { pluginHook } from "#build/internal.vue-query-plugin-hook" import { defineNuxtPlugin, useRuntimeConfig, useState } from "#imports" export default defineNuxtPlugin((nuxt) => { - const { stateKey, queryClientOptions, vueQueryPluginOptions, dehydrateOptions } = getVueQueryOptions(useRuntimeConfig()) + const { stateKey, queryClientOptions, vueQueryPluginOptions } = getVueQueryOptions(useRuntimeConfig()) const vueQueryState = useState(stateKey) const queryClient = new QueryClient(queryClientOptions) @@ -16,7 +16,7 @@ export default defineNuxtPlugin((nuxt) => { if (import.meta.server) { nuxt.hooks.hook("app:rendered", () => { - vueQueryState.value = dehydrate(queryClient, dehydrateOptions) + vueQueryState.value = dehydrate(queryClient) }) } diff --git a/packages/vue-query-nuxt/src/runtime/utils.ts b/packages/vue-query-nuxt/src/runtime/utils.ts index 1c5ba1d7..074ad144 100644 --- a/packages/vue-query-nuxt/src/runtime/utils.ts +++ b/packages/vue-query-nuxt/src/runtime/utils.ts @@ -1,4 +1,4 @@ -import type { QueryClientConfig, VueQueryPluginOptions, DehydrateOptions } from "@tanstack/vue-query" +import type { QueryClientConfig, VueQueryPluginOptions } from "@tanstack/vue-query" import type { RuntimeConfig } from "nuxt/schema" export const NAME = "vue-query-nuxt" as const @@ -19,8 +19,7 @@ export interface ModuleOptions { stateKey: string autoImports: VueQueryComposables | false queryClientOptions: QueryClientConfig | undefined - vueQueryPluginOptions: VueQueryPluginOptions, - dehydrateOptions: DehydrateOptions + vueQueryPluginOptions: VueQueryPluginOptions } export const defaults: ModuleOptions = { @@ -29,8 +28,7 @@ export const defaults: ModuleOptions = { queryClientOptions: { defaultOptions: { queries: { staleTime: 5000 } } }, - vueQueryPluginOptions: {}, - dehydrateOptions: {} + vueQueryPluginOptions: {} } export function getVueQueryOptions(config: RuntimeConfig) { return config.public[configKey] as ModuleOptions From 90fe9ca349f64a4442e0a1de77c5d843392e95e4 Mon Sep 17 00:00:00 2001 From: n0099 Date: Mon, 26 May 2025 00:46:27 +0000 Subject: [PATCH 05/11] feat: allow returning `HydrateOptions` & `DehydrateOptions` in `virtual:pluginHook.ts` --- packages/vue-query-nuxt/src/runtime/plugin.ts | 6 +++--- packages/vue-query-nuxt/src/runtime/types.ts | 4 ++-- packages/vue-query-nuxt/src/runtime/virtual:pluginHook.ts | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/vue-query-nuxt/src/runtime/plugin.ts b/packages/vue-query-nuxt/src/runtime/plugin.ts index a6562c9a..769d09f2 100644 --- a/packages/vue-query-nuxt/src/runtime/plugin.ts +++ b/packages/vue-query-nuxt/src/runtime/plugin.ts @@ -10,17 +10,17 @@ export default defineNuxtPlugin((nuxt) => { const queryClient = new QueryClient(queryClientOptions) // The plugin hook is replaced by the user provided vue-query.config.ts and allow advanced modifications - const { pluginReturn, vueQueryPluginOptions: hookOptions } = pluginHook({ queryClient, nuxt }) + const { pluginReturn, vueQueryPluginOptions: hookOptions, hydrateOptions, dehydrateOptions } = pluginHook({ queryClient, nuxt }) nuxt.vueApp.use(VueQueryPlugin, { queryClient, ...vueQueryPluginOptions, ...hookOptions }) if (import.meta.server) { nuxt.hooks.hook("app:rendered", () => { - vueQueryState.value = dehydrate(queryClient) + vueQueryState.value = dehydrate(queryClient, dehydrateOptions) }) } - if (import.meta.client) hydrate(queryClient, vueQueryState.value) + if (import.meta.client) hydrate(queryClient, vueQueryState.value, hydrateOptions) return pluginReturn }) diff --git a/packages/vue-query-nuxt/src/runtime/types.ts b/packages/vue-query-nuxt/src/runtime/types.ts index 66369801..030a91ac 100644 --- a/packages/vue-query-nuxt/src/runtime/types.ts +++ b/packages/vue-query-nuxt/src/runtime/types.ts @@ -1,5 +1,5 @@ import type { NuxtApp } from "nuxt/app" -import type { QueryClient, VueQueryPluginOptions } from "@tanstack/vue-query" +import type { DehydrateOptions, HydrateOptions, QueryClient, VueQueryPluginOptions } from "@tanstack/vue-query" export type NuxtPluginReturn = | void @@ -13,4 +13,4 @@ export interface PluginHookParameters { queryClient: QueryClient } -export interface PluginHookReturn { pluginReturn: NuxtPluginReturn; vueQueryPluginOptions?: VueQueryPluginOptions } +export interface PluginHookReturn { pluginReturn: NuxtPluginReturn; vueQueryPluginOptions?: VueQueryPluginOptions, hydrateOptions?: HydrateOptions, dehydrateOptions?: DehydrateOptions } diff --git a/packages/vue-query-nuxt/src/runtime/virtual:pluginHook.ts b/packages/vue-query-nuxt/src/runtime/virtual:pluginHook.ts index dc2ee619..ddb11ac0 100644 --- a/packages/vue-query-nuxt/src/runtime/virtual:pluginHook.ts +++ b/packages/vue-query-nuxt/src/runtime/virtual:pluginHook.ts @@ -6,5 +6,5 @@ import type { PluginHookParameters, PluginHookReturn } from "./types" // eslint-disable-next-line unused-imports/no-unused-vars export function pluginHook(pluginHookParameters: PluginHookParameters): PluginHookReturn { - return { pluginReturn: {}, vueQueryPluginOptions: {} } + return { pluginReturn: {}, vueQueryPluginOptions: {}, hydrateOptions: {}, dehydrateOptions: {} } } From 6ee7a5d69ecef044070078744dc0710759a46ed4 Mon Sep 17 00:00:00 2001 From: n0099 Date: Mon, 26 May 2025 01:51:55 +0000 Subject: [PATCH 06/11] feat: better api of `PluginHookReturn.pluginReturn` --- packages/vue-query-nuxt/src/module.ts | 2 +- packages/vue-query-nuxt/src/runtime/plugin.ts | 3 ++- packages/vue-query-nuxt/src/runtime/types.ts | 15 ++++++++------- .../src/runtime/virtual:pluginHook.ts | 2 +- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/packages/vue-query-nuxt/src/module.ts b/packages/vue-query-nuxt/src/module.ts index 2b70e03d..e04283ed 100644 --- a/packages/vue-query-nuxt/src/module.ts +++ b/packages/vue-query-nuxt/src/module.ts @@ -56,7 +56,7 @@ export default defineNuxtModule({ else { logger.info("No vue-query.config.ts file found.") } - return "export function pluginHook() { return { pluginReturn: null, vueQueryPluginOptions: null}}" + return "export function pluginHook() { return {} }" } }) diff --git a/packages/vue-query-nuxt/src/runtime/plugin.ts b/packages/vue-query-nuxt/src/runtime/plugin.ts index 769d09f2..7bd4a5d6 100644 --- a/packages/vue-query-nuxt/src/runtime/plugin.ts +++ b/packages/vue-query-nuxt/src/runtime/plugin.ts @@ -22,5 +22,6 @@ export default defineNuxtPlugin((nuxt) => { if (import.meta.client) hydrate(queryClient, vueQueryState.value, hydrateOptions) - return pluginReturn + if (pluginReturn !== undefined) return pluginReturn + return; }) diff --git a/packages/vue-query-nuxt/src/runtime/types.ts b/packages/vue-query-nuxt/src/runtime/types.ts index 030a91ac..5d137f7c 100644 --- a/packages/vue-query-nuxt/src/runtime/types.ts +++ b/packages/vue-query-nuxt/src/runtime/types.ts @@ -1,11 +1,7 @@ -import type { NuxtApp } from "nuxt/app" +import type { NuxtApp, Plugin } from "nuxt/app" import type { DehydrateOptions, HydrateOptions, QueryClient, VueQueryPluginOptions } from "@tanstack/vue-query" -export type NuxtPluginReturn = -| void -| Promise -| Promise<{ provide?: Record | undefined }> -| { provide?: Record | undefined } +export type NuxtPluginReturn = ReturnType // NuxtApp & _NuxtApp are different so we use any export interface PluginHookParameters { @@ -13,4 +9,9 @@ export interface PluginHookParameters { queryClient: QueryClient } -export interface PluginHookReturn { pluginReturn: NuxtPluginReturn; vueQueryPluginOptions?: VueQueryPluginOptions, hydrateOptions?: HydrateOptions, dehydrateOptions?: DehydrateOptions } +export interface PluginHookReturn { + pluginReturn?: NuxtPluginReturn, + vueQueryPluginOptions?: VueQueryPluginOptions, + hydrateOptions?: HydrateOptions, + dehydrateOptions?: DehydrateOptions +} diff --git a/packages/vue-query-nuxt/src/runtime/virtual:pluginHook.ts b/packages/vue-query-nuxt/src/runtime/virtual:pluginHook.ts index ddb11ac0..2ce92681 100644 --- a/packages/vue-query-nuxt/src/runtime/virtual:pluginHook.ts +++ b/packages/vue-query-nuxt/src/runtime/virtual:pluginHook.ts @@ -6,5 +6,5 @@ import type { PluginHookParameters, PluginHookReturn } from "./types" // eslint-disable-next-line unused-imports/no-unused-vars export function pluginHook(pluginHookParameters: PluginHookParameters): PluginHookReturn { - return { pluginReturn: {}, vueQueryPluginOptions: {}, hydrateOptions: {}, dehydrateOptions: {} } + return {} } From b453fcd75883e9a19d0f6c1b6fd8f84104072709 Mon Sep 17 00:00:00 2001 From: n0099 Date: Tue, 27 May 2025 02:24:46 +0000 Subject: [PATCH 07/11] feat: (de)serialize any instances of `Error` in `QueryState.error` while (de)hydrating --- packages/vue-query-nuxt/package.json | 3 ++- packages/vue-query-nuxt/src/runtime/plugin.ts | 27 +++++++++++++++++-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/packages/vue-query-nuxt/package.json b/packages/vue-query-nuxt/package.json index 5dbddf51..4184f8a8 100644 --- a/packages/vue-query-nuxt/package.json +++ b/packages/vue-query-nuxt/package.json @@ -62,7 +62,8 @@ "@nuxt/kit": "^3.11.2", "defu": "^6.1.4", "esbuild": "^0.20.2", - "magicast": "^0.3.4" + "magicast": "^0.3.4", + "serialize-error": "^12.0.0" }, "devDependencies": { "@nuxt/module-builder": "^0.5.5" diff --git a/packages/vue-query-nuxt/src/runtime/plugin.ts b/packages/vue-query-nuxt/src/runtime/plugin.ts index 7bd4a5d6..bcab1d96 100644 --- a/packages/vue-query-nuxt/src/runtime/plugin.ts +++ b/packages/vue-query-nuxt/src/runtime/plugin.ts @@ -1,5 +1,6 @@ import type { DehydratedState } from "@tanstack/vue-query" import { QueryClient, VueQueryPlugin, dehydrate, hydrate } from "@tanstack/vue-query" +import { isErrorLike, deserializeError, serializeError } from 'serialize-error'; import { getVueQueryOptions } from "./utils" import { pluginHook } from "#build/internal.vue-query-plugin-hook" import { defineNuxtPlugin, useRuntimeConfig, useState } from "#imports" @@ -14,13 +15,35 @@ export default defineNuxtPlugin((nuxt) => { nuxt.vueApp.use(VueQueryPlugin, { queryClient, ...vueQueryPluginOptions, ...hookOptions }) + type Dehydrated = ReturnType + type QueryOrMutations = Dehydrated['queries'] | Dehydrated['mutations'] if (import.meta.server) { nuxt.hooks.hook("app:rendered", () => { - vueQueryState.value = dehydrate(queryClient, dehydrateOptions) + const serializeErrors = (queryOrMutations: T): T => queryOrMutations + .filter(queryOrMutation => queryOrMutation.state.error instanceof Error) + .map(queryOrMutation => { + queryOrMutation.state.error = serializeError(queryOrMutation.state.error) as Error | null + return queryOrMutation + }) as T + const dehydrated = dehydrate(queryClient, dehydrateOptions) + dehydrated.queries = serializeErrors(dehydrated.queries) + dehydrated.mutations = serializeErrors(dehydrated.mutations) + vueQueryState.value = dehydrated }) } - if (import.meta.client) hydrate(queryClient, vueQueryState.value, hydrateOptions) + if (import.meta.client) { + const deserializeErrors = (queryOrMutations: T): T => queryOrMutations + .filter(queryOrMutation => isErrorLike(queryOrMutation.state.error)) + .map(queryOrMutation => { + queryOrMutation.state.error = deserializeError(queryOrMutation.state.error) + return queryOrMutation + }) as T + const dehydrated = vueQueryState.value + dehydrated.queries = deserializeErrors(dehydrated.queries) + dehydrated.mutations = deserializeErrors(dehydrated.mutations) + hydrate(queryClient, dehydrated, hydrateOptions) + } if (pluginReturn !== undefined) return pluginReturn return; From 843764a3d45c6c891479c3a26f791a1d287550f1 Mon Sep 17 00:00:00 2001 From: n0099 Date: Tue, 27 May 2025 02:32:54 +0000 Subject: [PATCH 08/11] fix: not (de)serialize `QueryState.fetchFailureReason` and `MutationState.failureReason` while (de)hydrating --- packages/vue-query-nuxt/src/runtime/plugin.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/vue-query-nuxt/src/runtime/plugin.ts b/packages/vue-query-nuxt/src/runtime/plugin.ts index bcab1d96..771f5c78 100644 --- a/packages/vue-query-nuxt/src/runtime/plugin.ts +++ b/packages/vue-query-nuxt/src/runtime/plugin.ts @@ -22,7 +22,12 @@ export default defineNuxtPlugin((nuxt) => { const serializeErrors = (queryOrMutations: T): T => queryOrMutations .filter(queryOrMutation => queryOrMutation.state.error instanceof Error) .map(queryOrMutation => { - queryOrMutation.state.error = serializeError(queryOrMutation.state.error) as Error | null + const state = queryOrMutation.state + state.error = serializeError(state.error) as Error | null + if ('fetchFailureReason' in state) + state.fetchFailureReason = serializeError(state.fetchFailureReason) as Error | null + if ('failureReason' in state) + state.failureReason = serializeError(state.failureReason) as Error | null return queryOrMutation }) as T const dehydrated = dehydrate(queryClient, dehydrateOptions) @@ -36,7 +41,12 @@ export default defineNuxtPlugin((nuxt) => { const deserializeErrors = (queryOrMutations: T): T => queryOrMutations .filter(queryOrMutation => isErrorLike(queryOrMutation.state.error)) .map(queryOrMutation => { - queryOrMutation.state.error = deserializeError(queryOrMutation.state.error) + const state = queryOrMutation.state + state.error = deserializeError(state.error) + if ('fetchFailureReason' in state) + state.fetchFailureReason = deserializeError(state.fetchFailureReason) + if ('failureReason' in state) + state.failureReason = deserializeError(state.failureReason) return queryOrMutation }) as T const dehydrated = vueQueryState.value From 811583c56687281e1fb925e0713cc2531922d25e Mon Sep 17 00:00:00 2001 From: n0099 Date: Tue, 27 May 2025 02:34:02 +0000 Subject: [PATCH 09/11] feat: add `PluginHookReturn.(de)serializeErrorOptions` --- packages/vue-query-nuxt/src/runtime/plugin.ts | 21 ++++++++++++------- packages/vue-query-nuxt/src/runtime/types.ts | 5 ++++- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/packages/vue-query-nuxt/src/runtime/plugin.ts b/packages/vue-query-nuxt/src/runtime/plugin.ts index 771f5c78..3232557e 100644 --- a/packages/vue-query-nuxt/src/runtime/plugin.ts +++ b/packages/vue-query-nuxt/src/runtime/plugin.ts @@ -11,7 +11,14 @@ export default defineNuxtPlugin((nuxt) => { const queryClient = new QueryClient(queryClientOptions) // The plugin hook is replaced by the user provided vue-query.config.ts and allow advanced modifications - const { pluginReturn, vueQueryPluginOptions: hookOptions, hydrateOptions, dehydrateOptions } = pluginHook({ queryClient, nuxt }) + const { + pluginReturn, + vueQueryPluginOptions: hookOptions, + hydrateOptions, + dehydrateOptions, + serializeErrorOptions, + deserializeErrorOptions + } = pluginHook({ queryClient, nuxt }) nuxt.vueApp.use(VueQueryPlugin, { queryClient, ...vueQueryPluginOptions, ...hookOptions }) @@ -23,11 +30,11 @@ export default defineNuxtPlugin((nuxt) => { .filter(queryOrMutation => queryOrMutation.state.error instanceof Error) .map(queryOrMutation => { const state = queryOrMutation.state - state.error = serializeError(state.error) as Error | null + state.error = serializeError(state.error, serializeErrorOptions) as Error | null if ('fetchFailureReason' in state) - state.fetchFailureReason = serializeError(state.fetchFailureReason) as Error | null + state.fetchFailureReason = serializeError(state.fetchFailureReason, serializeErrorOptions) as Error | null if ('failureReason' in state) - state.failureReason = serializeError(state.failureReason) as Error | null + state.failureReason = serializeError(state.failureReason, serializeErrorOptions) as Error | null return queryOrMutation }) as T const dehydrated = dehydrate(queryClient, dehydrateOptions) @@ -42,11 +49,11 @@ export default defineNuxtPlugin((nuxt) => { .filter(queryOrMutation => isErrorLike(queryOrMutation.state.error)) .map(queryOrMutation => { const state = queryOrMutation.state - state.error = deserializeError(state.error) + state.error = deserializeError(state.error, deserializeErrorOptions) if ('fetchFailureReason' in state) - state.fetchFailureReason = deserializeError(state.fetchFailureReason) + state.fetchFailureReason = deserializeError(state.fetchFailureReason, deserializeErrorOptions) if ('failureReason' in state) - state.failureReason = deserializeError(state.failureReason) + state.failureReason = deserializeError(state.failureReason, deserializeErrorOptions) return queryOrMutation }) as T const dehydrated = vueQueryState.value diff --git a/packages/vue-query-nuxt/src/runtime/types.ts b/packages/vue-query-nuxt/src/runtime/types.ts index 5d137f7c..a3efabcb 100644 --- a/packages/vue-query-nuxt/src/runtime/types.ts +++ b/packages/vue-query-nuxt/src/runtime/types.ts @@ -1,5 +1,6 @@ import type { NuxtApp, Plugin } from "nuxt/app" import type { DehydrateOptions, HydrateOptions, QueryClient, VueQueryPluginOptions } from "@tanstack/vue-query" +import type { Options } from "serialize-error" export type NuxtPluginReturn = ReturnType @@ -13,5 +14,7 @@ export interface PluginHookReturn { pluginReturn?: NuxtPluginReturn, vueQueryPluginOptions?: VueQueryPluginOptions, hydrateOptions?: HydrateOptions, - dehydrateOptions?: DehydrateOptions + dehydrateOptions?: DehydrateOptions, + serializeErrorOptions?: Options, + deserializeErrorOptions?: Options } From a8a2c4970e151601a69e3e0af8dca1c4c04b8340 Mon Sep 17 00:00:00 2001 From: n0099 Date: Thu, 29 May 2025 00:39:51 +0000 Subject: [PATCH 10/11] fix: always (de)hydrate query/mutation without error fix: only (de)serialize `state.fetchFailureReason` and `state.failureReason` when it is or like error --- packages/vue-query-nuxt/src/runtime/plugin.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/vue-query-nuxt/src/runtime/plugin.ts b/packages/vue-query-nuxt/src/runtime/plugin.ts index 3232557e..701827e7 100644 --- a/packages/vue-query-nuxt/src/runtime/plugin.ts +++ b/packages/vue-query-nuxt/src/runtime/plugin.ts @@ -27,13 +27,13 @@ export default defineNuxtPlugin((nuxt) => { if (import.meta.server) { nuxt.hooks.hook("app:rendered", () => { const serializeErrors = (queryOrMutations: T): T => queryOrMutations - .filter(queryOrMutation => queryOrMutation.state.error instanceof Error) .map(queryOrMutation => { const state = queryOrMutation.state - state.error = serializeError(state.error, serializeErrorOptions) as Error | null - if ('fetchFailureReason' in state) + if (state.error instanceof Error) + state.error = serializeError(state.error, serializeErrorOptions) as Error | null + if ('fetchFailureReason' in state && state.fetchFailureReason instanceof Error) state.fetchFailureReason = serializeError(state.fetchFailureReason, serializeErrorOptions) as Error | null - if ('failureReason' in state) + if ('failureReason' in state && state.failureReason instanceof Error) state.failureReason = serializeError(state.failureReason, serializeErrorOptions) as Error | null return queryOrMutation }) as T @@ -46,13 +46,13 @@ export default defineNuxtPlugin((nuxt) => { if (import.meta.client) { const deserializeErrors = (queryOrMutations: T): T => queryOrMutations - .filter(queryOrMutation => isErrorLike(queryOrMutation.state.error)) .map(queryOrMutation => { const state = queryOrMutation.state - state.error = deserializeError(state.error, deserializeErrorOptions) - if ('fetchFailureReason' in state) + if (isErrorLike(state.error)) + state.error = deserializeError(state.error, deserializeErrorOptions) + if ('fetchFailureReason' in state && isErrorLike(state.fetchFailureReason)) state.fetchFailureReason = deserializeError(state.fetchFailureReason, deserializeErrorOptions) - if ('failureReason' in state) + if ('failureReason' in state && isErrorLike(state.failureReason)) state.failureReason = deserializeError(state.failureReason, deserializeErrorOptions) return queryOrMutation }) as T From 4dbdab11b72040d3f78009f409281fe8bd473136 Mon Sep 17 00:00:00 2001 From: n0099 Date: Thu, 12 Jun 2025 11:44:58 +0000 Subject: [PATCH 11/11] fix: set option `useToJSON: false` when (de)serializing error --- packages/vue-query-nuxt/src/runtime/plugin.ts | 11 ++++++++--- packages/vue-query-nuxt/src/runtime/types.ts | 4 ++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/packages/vue-query-nuxt/src/runtime/plugin.ts b/packages/vue-query-nuxt/src/runtime/plugin.ts index 701827e7..9bab5d4a 100644 --- a/packages/vue-query-nuxt/src/runtime/plugin.ts +++ b/packages/vue-query-nuxt/src/runtime/plugin.ts @@ -1,6 +1,6 @@ import type { DehydratedState } from "@tanstack/vue-query" import { QueryClient, VueQueryPlugin, dehydrate, hydrate } from "@tanstack/vue-query" -import { isErrorLike, deserializeError, serializeError } from 'serialize-error'; +import { isErrorLike, deserializeError, serializeError, type Options } from 'serialize-error' import { getVueQueryOptions } from "./utils" import { pluginHook } from "#build/internal.vue-query-plugin-hook" import { defineNuxtPlugin, useRuntimeConfig, useState } from "#imports" @@ -16,9 +16,14 @@ export default defineNuxtPlugin((nuxt) => { vueQueryPluginOptions: hookOptions, hydrateOptions, dehydrateOptions, + ...pluginHookReturn + } = pluginHook({ queryClient, nuxt }) + let { serializeErrorOptions, deserializeErrorOptions - } = pluginHook({ queryClient, nuxt }) + } = pluginHookReturn + serializeErrorOptions = { ...serializeErrorOptions, useToJSON: false } as Options + deserializeErrorOptions = { ...deserializeErrorOptions, useToJSON: false } as Options nuxt.vueApp.use(VueQueryPlugin, { queryClient, ...vueQueryPluginOptions, ...hookOptions }) @@ -63,5 +68,5 @@ export default defineNuxtPlugin((nuxt) => { } if (pluginReturn !== undefined) return pluginReturn - return; + return }) diff --git a/packages/vue-query-nuxt/src/runtime/types.ts b/packages/vue-query-nuxt/src/runtime/types.ts index a3efabcb..57a2619c 100644 --- a/packages/vue-query-nuxt/src/runtime/types.ts +++ b/packages/vue-query-nuxt/src/runtime/types.ts @@ -15,6 +15,6 @@ export interface PluginHookReturn { vueQueryPluginOptions?: VueQueryPluginOptions, hydrateOptions?: HydrateOptions, dehydrateOptions?: DehydrateOptions, - serializeErrorOptions?: Options, - deserializeErrorOptions?: Options + serializeErrorOptions?: Omit, + deserializeErrorOptions?: Omit }