Module & Build Internals — Series 2

Preview — 3 of 10 questions

How does a file in server/middleware/ differ from a normal route handler in server/api/, in terms of when and how often it runs?

javascript
// server/middleware/request-logger.ts
export default defineEventHandler((event) => {
  console.log(`${event.node.req.method} ${event.node.req.url}`)
  // no return value — doesn't produce a response itself
})
AFiles in server/middleware/ run on every single incoming request to the Nitro server, regardless of which route is being requested, and regardless of whether that route even exists — unlike a server/api/ handler, which only runs when a request specifically matches its own route path; a middleware handler typically doesn't return a response body itself (as shown, logging and letting the request continue) but can also short-circuit the request (e.g., by throwing or sending a response early) before it ever reaches the matching route handler
Bserver/middleware/ files only run for requests that also match a route in server/api/ — a request to a non-API path never triggers them
Cserver/middleware/ and server/api/ are two different names for identical behavior — a file's effect depends only on its exported function, not its directory
DOnly one file may exist in server/middleware/ at a time — Nuxt throws a build error if more than one is present

Why would a custom Nuxt module call installModule('@nuxtjs/tailwindcss') from inside its own setup(), instead of just documenting that consumers should add Tailwind separately?

javascript
// modules/my-design-system/module.ts
import { defineNuxtModule, installModule } from '@nuxt/kit'

export default defineNuxtModule({
  async setup(options, nuxt) {
    await installModule('@nuxtjs/tailwindcss', { /* preset config */ })
    // ... register this design system's own components/composables ...
  },
})
AinstallModule() only works for modules published to npm — it can't be used for another module already present in the same monorepo
BinstallModule() merely adds a comment to the consuming app's nuxt.config.ts reminding the developer to install the dependency manually — it doesn't actually apply the module
CinstallModule() programmatically activates another Nuxt module as part of this module's own setup, applying its full effects (config merging, plugin/component registration, build hooks) as though the consuming app had listed it directly in its own modules array — this lets a higher-level module (a design system, a starter kit) bundle and configure a dependency module with a specific preset automatically, rather than requiring every consumer to separately discover, install, and correctly configure that dependency themselves
DinstallModule() runs the target module in complete isolation, sandboxed from the rest of the app's Nuxt context — its effects don't actually apply to the consuming app

Why does enabling experimental.asyncContext let a deeply-nested composable access the current request's event object without it being explicitly passed down as an argument through every intermediate function call?

javascript
// nuxt.config.ts
export default defineNuxtConfig({
  experimental: { asyncContext: true },
})
AasyncContext makes every composable a singleton shared across all concurrent requests — useRequestEvent() returns whichever request happened to call it most recently, globally
BasyncContext uses Node.js's AsyncLocalStorage to associate request-scoped context with the entire async call chain handling one specific request, so any code running as part of handling that request — no matter how deeply nested through awaited async calls — can retrieve the correct request-specific context without it being threaded through as an explicit function parameter at every level; without this, request-scoped access to the current event in deeply-nested async composable chains is unreliable or requires manually passing the event down everywhere
CasyncContext has no relation to concurrency or request scoping — it only affects whether async/await syntax is allowed inside composables
DasyncContext works by storing the current event in a plain global variable, which is safe because Nitro only ever handles one request at a time

Sign up free to play

Answer all 10 questions (7 more), see explanations for every answer, and track your score.