I have a web app in Nuxt 3 that is being migrated from Nuxt 2. We also have a companion API that handles all data fetching from databases. When starting the webserver, the nuxt app must fetch a JSON object with some settings (stuff required for start up and some constant variables to use as runtime params) from this API. These values can be different per deployment and only change when the API and the app are updated (meaning both will need to be restarted). I do not want to fetch this data in a plugin everytime a user enters the app because the call will always yield the same result. The current Nuxt 2 config looks like this:
// nuxt.config.js (Nuxt 2)
export default async () => {
const result = await someAsyncCall()
return {
// actual config, use result in runtime parameters here, exposed under this.$config
}
}
According to the migration guide (https://nuxt.com/docs/migration/configuration#async-configuration) this way of working is now deprecated in Nuxt 3 and it's recommended to use Nuxt hooks but I cannot find the correct way to achieve this. The goal is to have the app fetch this json data once on start up and to make this data available for use everywhere. I have tried the following approaches:
// This is the Nuxt 3 equivalent, but it's deprecated and for some reason it calls the data twice:
// nuxt.config.ts
export default async () => {
const result = await someAsyncCall()
return defineNuxtConfig({
runtimeConfig:{
// use result here
}
})
}
// This doesn't update the runtime config
//nuxt.config.ts
export default defineNuxtConfig({
runtimeConfig: {
public: {
myparam: ''
}
},
hooks: {
ready: async (nuxt) => { // not sure if 'ready' is available at deploy since it's a build hook anyway
console.log('READY')
const settings = await getRuntimeConfig()
nuxt.options.runtimeConfig.public.myparam = settings
}
},
})
// It's not allowed to import from nuxt.config.ts so this doesn't work.
// nuxt.config.ts
export const settings = {}
export default defineNuxtConfig({
hooks: {
ready: async (nuxt) => {
console.log('READY')
const _settings = await getRuntimeConfig()
settings = _settings
}
},
})
// myPlugin.ts
import { settings } from 'nuxt.config' // not allowed
export default defineNuxtPlugin(() => {
return { provide: { settings } }
})
I also checked https://nuxt.com/docs/api/advanced/hooks but nothing seems suited. How can I achieve the desired result?
A cascade of Nuxt 3/UnJS features must be used to achieve this.
Nuxt 3 uses alot of UnJS stuff under the hood so no additional packages are required.
Goal: Fetch data from an external API once on start up before users start interacting with the app.
1. Create a Nitro plugin
Nitro plugins are auto-registered (filename ordering) and run synchronously on the first nitro initialization. I was able to use a plugin to fetch data when the server started, even if there was no client. Fetch the data and make it available in Nitro using the storage layer (with memory driver).
Nuxt 3 Server Plugin Docs - Nitro Plugin Docs - Nitro Storage Layer Docs
2. Create a "bridge" between Nitro and Nuxt to pass the data using an API route
I first tried to add the result of the API call to the runtime parameters but runtime parameters are read only on the server side. We also cannot use
useStorage
on the "app" side of our project.This means we need to set up an API route in
/server/api/
to act as a bridge. Don't worry: since we're on the server, Nuxt will call this function without performing an actual HTTP request. I'm also usingcachedEventHandler
, butEventHandler
is also fine. Be sure to check out the options forcachedEventHandler
if you use it.Nuxt server route docs
3. Create a Nuxt plugin
Here, we'll provide a helper that returns the value of the API route. Since we use
useFetch
which uses$fetch
we won't actually perform a HTTP request. We'll call the nitro route directly as a function since this happens on the server.Nuxt plugin docs
4. Access settings from your app
EDIT2: Updating with final answer.