Skip to content

Commit 4054048

Browse files
authored
feat!: implement advanced plugin hook (#20)
1 parent e02313b commit 4054048

19 files changed

+1714
-446
lines changed

README.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -123,14 +123,17 @@ In `vue-query.config.ts` :
123123
```ts
124124
import { library } from "@example/libray"
125125

126-
export default defineVueQueryPluginCallback((vueQueryOptions) => {
127-
console.log(vueQueryOptions) // You can access the queryClient here
128-
return { provide: { library, test: console } }
126+
export default defineVueQueryPluginHook(({ queryClient, nuxt }) => {
127+
console.log(queryClient, nuxt) // You can access the queryClient here
128+
return {
129+
pluginReturn: { provide: { library, test: console } }, // nuxt plugin return value
130+
vueQueryPluginOptions: { queryClient } // You can pass dynamic options
131+
}
129132
})
130133
```
131134

132-
This callback will be run _directly_ after the Vue Query plugin is installed, so you can use it to `provide` something.
133-
This can be useful if you want to configure something that needs the `queryClient` or you want to provide a library in the same plugin.
135+
This hook will be run within the nuxt plugin installed by the module, so you can use it to `provide` something or replace the vue query options.
136+
This can be useful if you need to run custom logic when the `queryClient` is being installed.
134137

135138
## 📦 Contributing
136139

packages/vue-query-nuxt/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@
5353
"dev": "nuxi dev"
5454
},
5555
"peerDependencies": {
56-
"@tanstack/vue-query": "^4.32.4",
57-
"nuxt": "3.6.5"
56+
"@tanstack/vue-query": "*",
57+
"nuxt": "*"
5858
},
5959
"dependencies": {
6060
"@nuxt/kit": "3.6.5",

packages/vue-query-nuxt/src/module.ts

Lines changed: 36 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { existsSync } from "node:fs"
2-
import { addImports, addPlugin, addTemplate, createResolver, defineNuxtModule, updateTemplates, useLogger } from "@nuxt/kit"
2+
import { addImports, addPlugin, addTemplate, addTypeTemplate, createResolver, defineNuxtModule, updateTemplates, useLogger } from "@nuxt/kit"
33
import { defu } from "defu"
44
import { generateCode, loadFile } from "magicast"
55
import { transform } from "esbuild"
66
import { NAME, type VueQueryOptions, configKey, defaults } from "./runtime/utils"
77

88
declare module "@nuxt/schema" {
99
interface PublicRuntimeConfig {
10-
[configKey]: VueQueryOptions
10+
vueQuery: VueQueryOptions
1111
}
1212
}
1313

@@ -33,52 +33,53 @@ export default defineNuxtModule<VueQueryOptions>({
3333
addPlugin(resolve("./runtime/plugin"))
3434

3535
// 3. Add composable
36-
addImports([{ name: "defineVueQueryPluginCallback", from: resolve("./runtime/composables/defineVueQueryPluginCallback") }])
36+
addImports([{ name: "defineVueQueryPluginHook", from: resolve("./runtime/composables/defineVueQueryPluginHook") }])
3737

38-
const filename = "internal.vue-query-plugin-callback.mjs"
38+
const filename = "internal.vue-query-plugin-hook.mjs"
3939

40-
// 4. Write pluginCallback() to .nuxt
41-
const getContents = async () => {
42-
if (existsSync(resolve(nuxt.options.rootDir, "vue-query.config.ts"))) {
43-
const configFile = resolve(nuxt.options.rootDir, "vue-query.config.ts")
44-
const file = await loadFile(configFile)
45-
if (file.exports.pluginCallback || file.exports.default) {
46-
logger.success("Found vue-query.config.ts file")
47-
if (!file.exports.pluginCallback) file.exports.pluginCallback = file.exports.default
48-
delete file.exports.default
49-
const { code } = generateCode(file) // We extract it with magicast...
50-
const shaked = await transform(code, { treeShaking: true, loader: "ts" }) // ...we clean it with esbuild.
51-
return shaked.code
40+
// 4. Write pluginHook() to .nuxt
41+
addTemplate({
42+
filename,
43+
write: true,
44+
getContents: async () => {
45+
if (existsSync(resolve(nuxt.options.rootDir, "vue-query.config.ts"))) {
46+
const configFile = resolve(nuxt.options.rootDir, "vue-query.config.ts")
47+
const file = await loadFile(configFile)
48+
if (file.exports.pluginHook || file.exports.default) {
49+
logger.success("Found vue-query.config.ts file")
50+
if (!file.exports.pluginHook) file.exports.pluginHook = file.exports.default
51+
delete file.exports.default
52+
const { code } = generateCode(file) // We extract it with magicast...
53+
const shaked = await transform(code, { treeShaking: true, loader: "ts" }) // ...we clean it with esbuild.
54+
return shaked.code
55+
}
56+
else {
57+
logger.error("Found vue-query.config.ts file, but it does not export a `pluginHook`.")
58+
}
5259
}
5360
else {
54-
logger.error("Found vue-query.config.ts file, but it does not export a `pluginCallback`.")
61+
logger.info("No vue-query.config.ts file found.")
5562
}
63+
return "export function pluginHook() { return { pluginReturn: null, vueQueryPluginOptions: null}}"
5664
}
57-
else {
58-
logger.info("No vue-query.config.ts file found.")
59-
}
60-
return "export function pluginCallback() {}"
61-
}
62-
addTemplate({ filename, write: true, getContents })
63-
// 4. Add types for the plugin callback.
64-
const advancedTypes = "types/vue-query-nuxt-advanced.d.ts"
65-
addTemplate({
66-
filename: advancedTypes,
65+
})
66+
67+
// 4. Augment NuxtApp with the pluginHook return type (for provide)
68+
addTypeTemplate({
69+
filename: "types/vue-query-nuxt-advanced.d.ts",
70+
write: true,
6771
getContents: () => `
68-
type PluginCallbackResult = Awaited<ReturnType<typeof import(".nuxt/${filename}").pluginCallback>>
69-
70-
type AddPrefix<T> = {
72+
type PluginHookResult = Awaited<ReturnType<typeof import(".nuxt/${filename}").pluginHook>["pluginReturn"]>
73+
74+
type AddDollarPrefix<T> = {
7175
[K in keyof T['provide'] as \`$\${string & K}\`]: T['provide'][K]
7276
}
73-
77+
7478
declare module '#app' {
75-
interface NuxtApp extends AddPrefix<PluginCallbackResult> {}
79+
interface NuxtApp extends AddDollarPrefix<PluginHookResult> {}
7680
}
7781
export { }`
7882
})
79-
nuxt.hook("prepare:types", ({ references }) => {
80-
references.push({ path: advancedTypes })
81-
})
8283

8384
// 5. Auto - reload the config
8485
nuxt.hook("builder:watch", async (event, path) => {

packages/vue-query-nuxt/src/runtime/composables/defineVueQueryPluginCallback.ts

Lines changed: 0 additions & 7 deletions
This file was deleted.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import type { PluginHookParameters, PluginHookReturn } from "../types"
2+
3+
// @note the generic is needed to augment NuxtApp with the return type
4+
export function defineVueQueryPluginHook<T extends PluginHookReturn>(callback: (pluginHookParameters: PluginHookParameters) => T) {
5+
return callback
6+
}

packages/vue-query-nuxt/src/runtime/plugin.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
import type { DehydratedState } from "@tanstack/vue-query"
22
import { QueryClient, VueQueryPlugin, dehydrate, hydrate } from "@tanstack/vue-query"
33
import { getVueQueryOptions } from "./utils"
4+
import { pluginHook } from "#build/internal.vue-query-plugin-hook"
45
import { defineNuxtPlugin, useRuntimeConfig, useState } from "#imports"
5-
import { pluginCallback } from "#build/internal.vue-query-plugin-callback"
66

77
export default defineNuxtPlugin((nuxt) => {
88
const { stateKey, queryClientOptions, vueQueryPluginOptions } = getVueQueryOptions(useRuntimeConfig())
99
const vueQueryState = useState<DehydratedState | null>(stateKey)
1010
const queryClient = new QueryClient(queryClientOptions)
1111

12-
nuxt.vueApp.use(VueQueryPlugin, { queryClient, ...vueQueryPluginOptions })
12+
// The plugin hook is replaced by the user provided vue-query.config.ts and allow advanced modifications
13+
const { pluginReturn, vueQueryPluginOptions: hookOptions } = pluginHook({ queryClient, nuxt })
14+
15+
nuxt.vueApp.use(VueQueryPlugin, { queryClient, ...vueQueryPluginOptions, ...hookOptions })
1316

1417
if (process.server) {
1518
nuxt.hooks.hook("app:rendered", () => {
@@ -21,5 +24,5 @@ export default defineNuxtPlugin((nuxt) => {
2124
hydrate(queryClient, vueQueryState.value)
2225
})
2326
}
24-
return pluginCallback({ queryClient })
27+
return pluginReturn
2528
})
Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1-
import { type QueryClient } from "@tanstack/vue-query"
1+
import type { NuxtApp } from "nuxt/app"
2+
import type { QueryClient, VueQueryPluginOptions } from "@tanstack/vue-query"
23

3-
export type ReturnedByPlugin =
4+
export type NuxtPluginReturn =
45
| void
56
| Promise<void>
67
| Promise<{ provide?: Record<string, unknown> | undefined }>
78
| { provide?: Record<string, unknown> | undefined }
89

9-
export interface PluginCallbackParameters {
10+
export interface PluginHookParameters {
11+
nuxt: NuxtApp
1012
queryClient: QueryClient
1113
}
14+
15+
export interface PluginHookReturn { pluginReturn: NuxtPluginReturn; vueQueryPluginOptions?: VueQueryPluginOptions }

packages/vue-query-nuxt/src/runtime/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const composables = [
1717
type VueQueryComposables = typeof composables[number]
1818
export interface VueQueryOptions {
1919
stateKey: string
20-
autoImports: VueQueryComposables[] | [] | false
20+
autoImports: VueQueryComposables[] | false
2121
queryClientOptions: QueryClientConfig | undefined
2222
vueQueryPluginOptions: VueQueryPluginOptions
2323
}
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
import type { PluginCallbackParameters, ReturnedByPlugin } from "./types"
1+
import type { PluginHookParameters, PluginHookReturn } from "./types"
22

33
// "#build/internal.vue-query-plugin-callback will resolve to this file when building the library.
44
// The actual function will be defined by the user and injected in the .nuxt directory.
55
// Typescript will resolve this type regardless
66

77
// eslint-disable-next-line unused-imports/no-unused-vars
8-
export const pluginCallback = (pluginCallbackParameters: PluginCallbackParameters): ReturnedByPlugin => ({})
8+
export function pluginHook(pluginHookParameters: PluginHookParameters): PluginHookReturn {
9+
return { pluginReturn: {}, vueQueryPluginOptions: {} }
10+
}
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { createHooks } from "@wundergraph/vue-query"
22

3-
export default defineVueQueryPluginCallback(({ queryClient }) => {
3+
export default defineVueQueryPluginHook(({ queryClient, nuxt }) => {
4+
nuxt.vueApp.use({ install: () => { } })
45
queryClient.setQueryData(["todos"], [{ id: 1, todo: "Hello" }, { id: 2, todo: "World" }])
5-
return { provide: { createHooks, test: console } }
6+
return { pluginReturn: { provide: { createHooks, test: console } } }
67
})

0 commit comments

Comments
 (0)