Make UseFetch Options konfigurable

I want to provide some way to let users of my plugin to configure useFetch options. I want that users can set things like getCachedData. It should be possible via the nuxt config, but I think I can't define functions and complicated stuff here that get's passed down to the actuall plugin place or can I?
26 Replies
kapa.ai
kapa.ai4w ago
Hi @Samuelreichoer. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- You are correct that passing functions (like getCachedData) directly from nuxt.config is not recommended or supported in Nuxt, as config files are serialized and cannot safely transport functions to runtime. This is a known convention in Nuxt, and there is discussion in the Nuxt repository about preferring runtime hooks or other mechanisms over passing functions from config to runtime code. For example, in the context of view transitions, Nuxt maintainers suggest using hooks for runtime configuration rather than passing functions via nuxt.config, to better align with Nuxt’s conventions and avoid serialization issues feat(nuxt): add View Transitions Types support. If you want users of your plugin to configure useFetch options such as getCachedData, the recommended approach is to expose a runtime hook or composable that users can call in their application code, rather than expecting them to define such logic in nuxt.config. This way, users can provide functions and more complex logic safely at runtime. In summary:
- You cannot (and should not) pass functions like getCachedData via nuxt.config. - Prefer exposing a runtime API (such as a composable or Nuxt hook) for users to provide such options. - This approach is consistent with Nuxt’s conventions and avoids issues with serialization between config and runtime. If you need to provide default options, you can set them in your plugin code, and allow users to override them via runtime hooks or composables. There is no explicit documentation in the knowledge sources about a built-in way to pass functions from nuxt.config to useFetch, and the sources recommend against it. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai4w ago
<@1065266379382587422> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Samuelreichoer
SamuelreichoerOP4w ago
How can I provide my own hooks? @kapa.ai How can I provide my own hooks?
kapa.ai
kapa.ai4w ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- To provide your own hooks in a Nuxt module, you can define custom hooks and allow other modules or parts of your application to subscribe to them. The recommended pattern is to call these hooks in the module's setup, specifically after all modules have run, typically using the module:done hook. This ensures that other modules have had a chance to register their callbacks before your hook is triggered. Here’s a summary of the approach: - Define your custom hook name (e.g., my-module:custom-hook). - Allow other modules to subscribe to your hook using nuxt.hook('my-module:custom-hook', callback). - Call your custom hook in your module, ideally in module:done, so all subscribers are registered. This pattern is now documented in the Nuxt docs and is the recommended way for modules to expose integration points for other modules or user code:
Adds a small section to describe custom hooks and that hooks that could be subscribed to by other modules should be called in module:done.
docs: add section on custom hooks for Nuxt modules Example:
// In your module
export default defineNuxtModule({
setup(options, nuxt) {
nuxt.hook('module:done', () => {
nuxt.callHook('my-module:custom-hook', options)
})
}
})

// In another module or app code
nuxt.hook('my-module:custom-hook', (options) => {
// Do something with options
})
// In your module
export default defineNuxtModule({
setup(options, nuxt) {
nuxt.hook('module:done', () => {
nuxt.callHook('my-module:custom-hook', options)
})
}
})

// In another module or app code
nuxt.hook('my-module:custom-hook', (options) => {
// Do something with options
})
This ensures your hooks are extensible and follow Nuxt’s best practices. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai4w ago
<@1065266379382587422> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Samuelreichoer
SamuelreichoerOP4w ago
Wenn ich jetzt zum Beispiel useFetch Options hier definen will, wie könnte dann ein User einen custom hook benutzen? @kapa.ai Wenn ich jetzt zum Beispiel useFetch Options hier definen will, wie könnte dann ein User einen custom hook benutzen?
kapa.ai
kapa.ai4w ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- Um es einem User zu ermöglichen, eigene useFetch-Optionen (wie z.B. getCachedData) per Custom Hook zu setzen, würdest du in deinem Modul einen eigenen Hook definieren und diesen nach module:done aufrufen. Andere Module oder die App selbst können dann auf diesen Hook reagieren und z.B. eine Funktion für getCachedData bereitstellen. Ein Beispiel-Workflow, basierend auf den Nuxt-Konventionen: 1. In deinem Modul:
Du rufst nach module:done deinen eigenen Hook auf und übergibst die aktuellen Optionen.
// In deinem Modul
export default defineNuxtModule({
setup(options, nuxt) {
nuxt.hook('module:done', () => {
nuxt.callHook('my-module:use-fetch-options', options)
})
}
})

// In deinem Modul
export default defineNuxtModule({
setup(options, nuxt) {
nuxt.hook('module:done', () => {
nuxt.callHook('my-module:use-fetch-options', options)
})
}
})

2. Im Projekt des Users:
Der User kann in nuxt.config oder in einem eigenen Modul auf deinen Hook reagieren und eigene Optionen (z.B. getCachedData) setzen:
// In nuxt.config oder eigenem Modul
export default defineNuxtModule({
setup(options, nuxt) {
nuxt.hook('my-module:use-fetch-options', (options) => {
options.getCachedData = (key) => {
// eigene Caching-Logik
}
})
}
})

// In nuxt.config oder eigenem Modul
export default defineNuxtModule({
setup(options, nuxt) {
nuxt.hook('my-module:use-fetch-options', (options) => {
options.getCachedData = (key) => {
// eigene Caching-Logik
}
})
}
})

Wichtig:
- Die eigentliche Logik (wie getCachedData) wird so zur Laufzeit gesetzt und nicht über die nuxt.config direkt serialisiert, was den Nuxt-Konventionen entspricht. - Diese Vorgehensweise ist in den Nuxt-Dokumenten und PRs als empfohlener Weg für Custom Hooks beschrieben docs: add section on custom hooks for Nuxt modules. Falls du ein konkretes Beispiel für useFetch-Optionen suchst, findest du in den Quellen auch Hinweise, wie getCachedData als Funktion übergeben werden kann – aber eben nicht direkt über die nuxt.config, sondern über einen Hook oder eine Runtime-API feat(nuxt): custom cache support for data fetching composables. Fazit:
User können über einen von dir bereitgestellten Hook zur Laufzeit eigene useFetch-Optionen wie getCachedData setzen. Das ist der empfohlene Weg in Nuxt. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai4w ago
<@1065266379382587422> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Samuelreichoer
SamuelreichoerOP4w ago
@kapa.ai Ich habe jetzt das hier: export interface ModuleHooks { 'query-api:fetch-options': (options: typeof globalThis.$fetch) => void } export default defineNuxtModule<Required<CraftCmsOptions>>({ meta: { name: '@query-api/nuxt', configKey: 'craftcms', compatibility: { nuxt: '>=3.0.0', }, }, // Default configuration options of the Nuxt module defaults: defaultCraftOptions, setup(options, nuxt) { nuxt.hook('modules:done', async () => { const options = {} await nuxt.callHook('query-api:fetch-options', options) }) }, }) Bekomme aber bei await nuxt.callHook('query-api:fetch-options', options) einen ts error: Argument of type '"query-api:fetch-options"' is not assignable to parameter of type 'HookKeys<NuxtHooks>'.ts(2345)
kapa.ai
kapa.ai4w ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- Der TypeScript-Fehler
Argument of type '"query-api:fetch-options"' is not assignable to parameter of type 'HookKeys<NuxtHooks>'.ts(2345)
tritt auf, weil Nuxt standardmäßig nur die bekannten (vordefinierten) Hook-Namen typisiert. Damit dein eigener Hook-Typ (query-api:fetch-options) erkannt wird, musst du das Nuxt-Hook-Typing erweitern (augmentieren). Das Vorgehen ist in den Nuxt-Dokumenten und Issues beschrieben:
Du musst das Interface NuxtHooks (bzw. RuntimeNuxtHooks oder das relevante Hooks-Interface) per TypeScript-Declaration-Merging erweitern, damit dein Custom Hook typisiert ist und TypeScript keinen Fehler mehr wirft.
Das ist ein bekanntes Muster und wird z.B. in nuxtApp.hook types not recognized erklärt:
this is by design - you need to augment the RuntimeNuxtHooks.
So geht’s: 1. Type Augmentation in einer .d.ts Datei (z.B. types/query-api-hooks.d.ts):
import type { NuxtHooks } from 'nuxt/schema'

declare module 'nuxt/schema' {
interface NuxtHooks {
'query-api:fetch-options': (options: any) => void
}
}

import type { NuxtHooks } from 'nuxt/schema'

declare module 'nuxt/schema' {
interface NuxtHooks {
'query-api:fetch-options': (options: any) => void
}
}

(Passe ggf. den Typ von options an.) 2. Danach erkennt TypeScript deinen Hook-Namen und der Fehler verschwindet. Wichtig:
- Die Knowledge Sources beschreiben explizit, dass du das Typing augmentieren musst, wenn du eigene Hooks verwendest nuxtApp.hook types not recognized. - Ohne diese Erweiterung kennt TypeScript deinen Hook nicht und gibt den genannten Fehler aus. Zusammengefasst:
Erweitere das Nuxt-Hooks-Interface per Declaration Merging, dann kannst du deinen Custom Hook typisiert und ohne Fehler verwenden. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai4w ago
<@1065266379382587422> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Samuelreichoer
SamuelreichoerOP4w ago
@kapa.ai wie kann ich jetzt auf den hook zugreifen?
kapa.ai
kapa.ai4w ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- Um auf deinen eigenen Hook (z.B. 'query-api:fetch-options') zuzugreifen, kannst du in einem anderen Modul oder in der App selbst mit nuxt.hook('query-api:fetch-options', callback) darauf reagieren. Das bedeutet, du registrierst eine Callback-Funktion, die ausgeführt wird, wenn dein Modul den Hook mit nuxt.callHook('query-api:fetch-options', options) aufruft. Beispiel:
// In einem anderen Modul oder in nuxt.config.ts
export default defineNuxtModule({
setup(options, nuxt) {
nuxt.hook('query-api:fetch-options', (options) => {
// Hier kannst du die Optionen anpassen, z.B.:
options.getCachedData = (key) => {
// Eigene Caching-Logik
}
})
}
})
// In einem anderen Modul oder in nuxt.config.ts
export default defineNuxtModule({
setup(options, nuxt) {
nuxt.hook('query-api:fetch-options', (options) => {
// Hier kannst du die Optionen anpassen, z.B.:
options.getCachedData = (key) => {
// Eigene Caching-Logik
}
})
}
})
Das Vorgehen entspricht dem empfohlenen Muster für Custom Hooks in Nuxt, wie es in den Knowledge Sources beschrieben ist docs: add section on custom hooks for Nuxt modules. Falls du den Hook in der App selbst nutzen möchtest, kannst du das ebenfalls in einem Plugin oder in der nuxt.config tun, solange du Zugriff auf das nuxt-Objekt hast. Wichtig:
- Die Registrierung des Hooks muss vor dem Aufruf von callHook erfolgen, also typischerweise im Setup eines Moduls oder Plugins. - Die Knowledge Sources beschreiben dieses Muster für Custom Hooks, aber zeigen kein vollständiges Beispiel für die App-Ebene. Das Prinzip bleibt aber gleich. Wenn du weitere Details brauchst, wie du das in einer bestimmten Datei (z.B. nuxt.config oder Plugin) machst, gib gerne Bescheid! ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai4w ago
<@1065266379382587422> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Samuelreichoer
SamuelreichoerOP4w ago
@kapa.ai wie bekomme ich types von den useFetch Options, eigentlich müssten die useAsyncData Options damit auch kompatibel sein
kapa.ai
kapa.ai4w ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- Die Knowledge Sources enthalten keine vollständige, explizite Dokumentation darüber, wie du direkt an die Typen der useFetch-Options gelangst. Es gibt jedoch Hinweise darauf, dass die Typen von useFetch und useAsyncData eng miteinander verbunden sind, da useFetch intern useAsyncData verwendet und beide ähnliche Options-Objekte akzeptieren. In den Quellen wird beispielsweise gezeigt, dass du für eigene Wrapper um useFetch den Typ UseFetchOptions aus nuxt/app importieren kannst:
import type { UseFetchOptions } from 'nuxt/app'
import type { UseFetchOptions } from 'nuxt/app'
How to properly wrap useFetch to access reactivity? Part 1 Außerdem wird in den Knowledge Sources bestätigt, dass useFetch und useAsyncData sehr ähnliche (teils identische) Optionen akzeptieren, da useFetch ein spezialisierter Wrapper um useAsyncData ist Which to use: $fetch, useAsyncData or useFetch for GET and POST requests in Nuxt 3? Part 3. Fazit:
- Die Typen für useFetch-Optionen erhältst du mit import type { UseFetchOptions } from 'nuxt/app'. - Diese Optionen sind weitgehend kompatibel mit den useAsyncData-Optionen, da useFetch intern useAsyncData nutzt. Eine vollständige, offizielle Typendokumentation ist in den Knowledge Sources nicht enthalten, aber die genannten Hinweise bestätigen das Vorgehen. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai4w ago
<@1065266379382587422> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Samuelreichoer
SamuelreichoerOP4w ago
@kapa.ai ich hab zum Beispiel die Funktion, wo ich die options rein parsen will function fetchFn<ResT>(url: string) { const authToken = useCraftAuthToken() return useAsyncData<ResT>(craftcms:${url}, () => $fetch(url, { headers: { Authorization: authToken, }, }), ) }
kapa.ai
kapa.ai4w ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- Um deine Funktion so zu gestalten, dass du useFetch- oder useAsyncData-Optionen typisiert und flexibel übergeben kannst, solltest du den Typ UseFetchOptions aus nuxt/app importieren. Die Knowledge Sources zeigen, dass dies der empfohlene Weg ist, um Optionen für useFetch (und damit auch für useAsyncData, da sie kompatibel sind) zu typisieren How to properly wrap useFetch to access reactivity? Part 1. Ein Beispiel, wie du das machen kannst:
import type { UseFetchOptions } from 'nuxt/app'

function fetchFn<ResT>(url: string, options: UseFetchOptions<ResT> = {}) {
const authToken = useCraftAuthToken()
return useAsyncData<ResT>(
`craftcms:${url}`,
() => $fetch(url, {
headers: {
Authorization: authToken,
...(options.headers || {}),
},
...options,
})
)
}
import type { UseFetchOptions } from 'nuxt/app'

function fetchFn<ResT>(url: string, options: UseFetchOptions<ResT> = {}) {
const authToken = useCraftAuthToken()
return useAsyncData<ResT>(
`craftcms:${url}`,
() => $fetch(url, {
headers: {
Authorization: authToken,
...(options.headers || {}),
},
...options,
})
)
}
Hinweise: - Du kannst die Optionen so an $fetch weiterreichen und ggf. eigene Header oder andere Optionen mergen. - Die Knowledge Sources bestätigen, dass die Typen von useFetch und useAsyncData kompatibel sind, da useFetch ein Wrapper um useAsyncData ist Which to use: $fetch, useAsyncData or useFetch for GET and POST requests in Nuxt 3? Part 3. Falls du spezielle Optionen von useAsyncData (wie z.B. lazy, server, etc.) nutzen willst, solltest du diese ggf. separat behandeln, da sie nicht direkt an $fetch weitergegeben werden können. Fazit:
Nutze UseFetchOptions aus nuxt/app für die Typisierung der Options, das ist der empfohlene Weg laut Knowledge Sources. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai4w ago
<@1065266379382587422> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Samuelreichoer
SamuelreichoerOP4w ago
@kapa.ai nein ich möchte die options über den hook rein geben
kapa.ai
kapa.ai4w ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- Die Knowledge Sources beschreiben das Muster, wie du Optionen (z.B. für useFetch oder useAsyncData) per Custom Hook zur Laufzeit einspeisen kannst. Das Vorgehen ist: 1. Du definierst in deinem Modul einen Hook, z.B. 'query-api:fetch-options'. 2. Beim Aufruf deiner Funktion (z.B. fetchFn) erzeugst du ein leeres Options-Objekt und rufst den Hook auf, damit andere Module/Plugins dieses Objekt befüllen können. 3. Danach verwendest du die befüllten Optionen in deinem useAsyncData-Aufruf. Ein Beispiel, wie das aussehen kann (angepasst an deine fetchFn):
// Annahme: Du hast das Typing für den Hook wie oben beschrieben augmentiert

function fetchFn<ResT>(url: string) {
const authToken = useCraftAuthToken()
const nuxtApp = useNuxtApp()
const options: Record<string, any> = {}

// Hook aufrufen, damit andere Module Optionen einfügen können
nuxtApp.callHook('query-api:fetch-options', options)

return useAsyncData<ResT>(
`craftcms:${url}`,
() => $fetch(url, {
headers: {
Authorization: authToken,
...(options.headers || {}),
},
...options,
})
)
}
// Annahme: Du hast das Typing für den Hook wie oben beschrieben augmentiert

function fetchFn<ResT>(url: string) {
const authToken = useCraftAuthToken()
const nuxtApp = useNuxtApp()
const options: Record<string, any> = {}

// Hook aufrufen, damit andere Module Optionen einfügen können
nuxtApp.callHook('query-api:fetch-options', options)

return useAsyncData<ResT>(
`craftcms:${url}`,
() => $fetch(url, {
headers: {
Authorization: authToken,
...(options.headers || {}),
},
...options,
})
)
}
Wie der User den Hook nutzt:
// In einem Modul oder Plugin
export default defineNuxtModule({
setup(_options, nuxt) {
nuxt.hook('query-api:fetch-options', (options) => {
options.getCachedData = (key) => {
// Eigene Caching-Logik
}
// Weitere Optionen setzen
})
}
})
// In einem Modul oder Plugin
export default defineNuxtModule({
setup(_options, nuxt) {
nuxt.hook('query-api:fetch-options', (options) => {
options.getCachedData = (key) => {
// Eigene Caching-Logik
}
// Weitere Optionen setzen
})
}
})
Wichtig:
- Die Knowledge Sources bestätigen, dass dieses Muster für Custom Hooks in Nuxt empfohlen ist docs: add section on custom hooks for Nuxt modules. - Die eigentliche Typisierung der Optionen kannst du flexibel halten, da die Knowledge Sources keine strikte Typisierung für dieses Pattern vorgeben. Fazit:
Du kannst Optionen über einen Custom Hook zur Laufzeit einspeisen lassen, indem du ein Options-Objekt erzeugst, den Hook aufrufst und danach die befüllten Optionen verwendest. Das ist das empfohlene Nuxt-Muster für solche Anwendungsfälle. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai4w ago
<@1065266379382587422> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Samuelreichoer
SamuelreichoerOP4w ago
@kapa.ai Das verstehe ich nicht, befüllt die Zeile nuxtApp.callHook('query-api:fetch-options', options) die options variable darüber?
kapa.ai
kapa.ai4w ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- Die Zeile
nuxtApp.callHook('query-api:fetch-options', options)
nuxtApp.callHook('query-api:fetch-options', options)
ruft alle registrierten Callback-Funktionen für den Hook 'query-api:fetch-options' auf und übergibt dabei das options-Objekt als Referenz.
Das bedeutet:
Alle Callback-Funktionen, die sich auf diesen Hook registriert haben (z.B. mit nuxt.hook('query-api:fetch-options', (options) => { ... })), bekommen genau dieses Objekt und können es verändern oder mit weiteren Properties befüllen. Das ist das empfohlene Muster in Nuxt für Custom Hooks:
...that hooks that could be subscribed to by other modules should be called in module:done
docs: add section on custom hooks for Nuxt modules Beispiel:
// In deinem Modul
const options = {}
await nuxtApp.callHook('query-api:fetch-options', options)
// Nach dem Aufruf sind alle Änderungen, die in den Hook-Callbacks gemacht wurden, in options enthalten
// In deinem Modul
const options = {}
await nuxtApp.callHook('query-api:fetch-options', options)
// Nach dem Aufruf sind alle Änderungen, die in den Hook-Callbacks gemacht wurden, in options enthalten
Fazit:
Ja, die Zeile befüllt das options-Objekt mit allen Änderungen, die in den registrierten Hook-Callbacks gemacht werden. Das Objekt wird per Referenz übergeben und kann so von außen erweitert werden. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai4w ago
<@1065266379382587422> Kapa.ai is still learning and improving, please let me know how I did by reacting below.

Did you find this page helpful?