Search code examples
nuxt.js

Access plugin injections in nuxt middleware


I am currently creating a nuxt module that provides a custom logger for my application that I want to use on server and client side. My idea was to create a plugin in that module that provides the logger instance so that I can use it everywhere. This is the code I wrote for that plugin:

export default defineNuxtPlugin(() => {
  const logger = new Logger()

  return {
    provide: {
      logger,
    },
  }
})

With const { $logger } = useNuxtApp() I am now able to use that logger at least on client side. In my app I created the file server/middleware/log.ts with this content:

export default defineEventHandler(() => {
  const { $logger } = useNuxtApp()
  $logger.info('Middleware called')
})

But this won't work because useNuxtApp cannot be used in a server middleware. Does anyone know how I can provide variables from a nuxt module that I can access in a server middleware?


Solution

  • If you want to use the logger on both the client and server sides, you must use the Nitro Plugins.

    Why do we need a Nitro Plugin?

    When we are talking about server-side there are two layers to keep in mind:

    1. Nuxt App Context (SSR Layer) — where your nuxt.config and defineNuxtPlugin operate, including server-side rendering for HTML. You can use composables like useNuxtApp() here.

    2. Nitro (Server Layer) — which powers server routes (/server/api/*), server middleware (/server/middleware/*), and any serverless/platform-specific deployment functionality.

    Although a Nuxt plugin does run on the server side during SSR, it does not automatically give you access to the same context used by server routes and middleware (the event object in Nitro). If you try to call useNuxtApp() inside a server route or server middleware, it will fail because those routes/middlewares aren’t part of the SSR rendering pipeline.

    So here is a solution for your case:

    1. Create a nitro plugin in server/plugins/logger.ts (you can read more about the hooks available here)
    import {Logger} from "~/logger";
    
    export default defineNitroPlugin((nitroApp) => {
        // Create your logger instance once
        const logger = new Logger()
        // Attach it to the event context before handling each request
        nitroApp.hooks.hook('request', (event) => {
            event.context.logger = logger
        })
    })
    
    
    1. Use it in your server middleware or api routes
    // server/middleware/log.ts
    export default defineEventHandler((event) => {
      // Grab the logger from the event context
      const { logger } = event.context
      logger.info('Middleware called')
    })
    
    1. You can continue to use a standard Nuxt plugin to provide $logger on the client side
    export default defineNuxtPlugin(() => {
      const logger = new Logger()
    
      // grab the logger directly from the class
      return {
        provide: {
          logger,
        },
      }
    })