All quizzesHard
Module & Build Internals — Series 3
Preview — 3 of 10 questions
What does writing a custom driver let a Nitro app do, beyond using one of unstorage's existing built-in drivers?
javascript
// A minimal custom driver for a hypothetical proprietary KV service
import { defineDriver } from 'unstorage'
export default defineDriver((options) => {
const client = new ProprietaryKVClient(options.apiKey)
return {
async getItem(key) {
return await client.get(key)
},
async setItem(key, value) {
await client.put(key, value)
},
async removeItem(key) {
await client.delete(key)
},
}
})Aunstorage (the storage abstraction underlying useStorage, covered elsewhere for cross-request server caching) ships with drivers for common backends (Redis, filesystem, memory, various cloud KV services), but any storage backend can be supported by implementing the same small driver interface (getItem/setItem/removeItem, plus optional extras) against that backend's own client library — letting useStorage work transparently against a genuinely proprietary or niche storage service that has no official driver, while every other part of the app that uses useStorage (caching, session data) never needs to know or care which specific driver is actually configured underneath
BCustom drivers can only be used for local development — production deployments are restricted to unstorage's officially bundled drivers
CThis is unnecessary — useStorage can only ever target the filesystem or memory, regardless of what driver configuration is provided
DCustom drivers require rewriting every useStorage call site throughout the app to use a completely different, driver-specific API
What do these module-authoring functions let a module generate, that a normal file in the consuming apps own source tree couldnt?
javascript
// A custom Nuxt module
import { defineNuxtModule, addTemplate, addTypeTemplate } from '@nuxt/kit'
export default defineNuxtModule({
setup(options, nuxt) {
addTemplate({
filename: 'my-module-config.mjs',
getContents: () => `export const config = ${JSON.stringify(options)}`,
})
addTypeTemplate({
filename: 'my-module-config.d.ts',
getContents: () => `export declare const config: ${JSON.stringify(options)}`,
})
},
})AaddTemplate/addTypeTemplate write real, permanent files directly into the consuming app's own source tree, indistinguishable from a file the app's own developer created by hand
BaddTemplate and addTypeTemplate are two names for the exact same function — one is simply deprecated in favor of the other
CThese functions can only generate content for Nuxt's own internal build tooling; they have no way to produce anything importable by the consuming app's actual code
DThese functions generate virtual files — content that exists only in Nuxt's build-time module resolution (in the .nuxt build directory), computed dynamically from the module's actual runtime options, rather than something the module needs to ship as a static file or the consuming app needs to create manually. This lets a module generate configuration, types, or other content that's specifically tailored to how that particular consuming app configured the module (the options passed to it), computed fresh at build time — impossible to express as a single static file shipped with the module, since the actual content depends on per-app configuration
What does hooking into render:html let this plugin do that isn't otherwise expressible through useHead or normal component rendering?
javascript
// server/plugins/inline-critical-css.ts
export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook('render:html', (html, { event }) => {
const criticalCss = computeCriticalCssForRoute(event.path)
html.head.push(`<style>${criticalCss}</style>`)
})
})Arender:html only fires for error pages — it has no effect on normal, successful page renders
BThis hook fires after the entire page has already been fully rendered into its final HTML string pieces (head, body, etc.), giving direct, low-level access to inject or modify raw HTML content right before it's sent to the client — something that's a genuinely different capability from useHead (which manages structured head tags, computed from within component code, not arbitrary raw HTML injected post-render) or normal component rendering (which produces the page's actual content, not this kind of cross-cutting, render-pipeline-level insertion). This is exactly the mechanism something like critical-CSS inlining (computing and injecting page-specific CSS directly into the response, calculated from server-side knowledge of the current route) needs — logic that doesn't naturally belong inside any single page component, but needs to affect literally every rendered response
CThis hook can only add content to the <body>; the <head> section is immutable once component rendering has completed
DnitroApp.hooks.hook('render:html', ...) runs once at server startup, not per-request — event.path would always be undefined since no request is actually in progress
Sign up free to play
Answer all 10 questions (7 more), see explanations for every answer, and track your score.