2

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?

Nicolas D
  • 91
  • 9

1 Answers1

0

You're looking to make a custom Nuxt 3 module

The Nuxt 3 plugins will only work during runtime and modules are now build time only.

I think this section in the docs may solve your issue: Exposing Options to Runtime

Here is an example of how I was able to achieve this (I'm using Nuxt v3.6.1):

import {
    defineNuxtModule,
    useLogger,
    createResolver,
    addImportsDir,
    addRouteMiddleware,
    addTypeTemplate,
} from 'nuxt/kit'
import { $fetch } from 'ofetch'

export default defineNuxtModule({
    meta: {
        // Usually the npm package name of your module
        name: '@nuxtjs/my-module',
        // The key in `nuxt.config` that holds your module options
        configKey: 'my-module',
        // Compatibility constraints
        compatibility: {
            // Semver version of supported nuxt versions
            nuxt: '^3.6.1',
        },
    },

    defaults: {
        // Your Defuault Options
    },
    async setup(options, nuxt) {
        // Create the path resolver
        const resolver = createResolver(import.meta.url)

        // Create the consola logger
        const logger = useLogger('my-module')
        logger.start('Starting...')


        const URL = `some-api/endpoint`
        const data = await $fetch<ResponseType>(URL) // I type my responses
        if (data) { //! I don't know what your response is going to look like
            // You could put these in public or merge existing ones with defu from unjs
            nuxt.options.runtimeConfig.options.myModuleOptions = data
            logger.success('Successfuly Loaded!')
        }
        
        //* Add Feature Specific Composables
        addImportsDir(resolver.resolve('runtime/composables'))

        //* Add Feature Specific Middleware
        addRouteMiddleware({
            name: 'myModuleMiddleware',
            path: resolver.resolve('runtime/middleware/someMiddleware'),
            global: true,
        })

        //* Add the Feature Specific Types
        addTypeTemplate({
            filename: 'types/my-module-types.d.ts',
            src: resolver.resolve('runtime/types.ts'),
            write: true,
        })
    },
})

There actually isn't a lot of documentation for around type templates or middleware in Nuxt 3 so I hope this helps someone.

  • reading from the docs, it's better to defer this to a hook since nuxt will synchronously setup each module. – Horizon Jul 11 '23 at 16:13