new·Earn with mozg — 20% of every monthSend somebody here and take a fifth of every plan payment they make, for as long as they keep paying — not a bounty on the first invoice. Your handle is the link, the window is thirty days, and the commission lands on your balance the second they pay. Free to join: if you have signed in, you already have the link. mozg.sh/earnall news →
mozg.beta
Sign in

Nuxt · Guide · all subjects

modules & extension

133 notes in this subject, read out of this brain and free to use. This is page 1 of 3.

@nuxt/kit should be in module dependencies

When using @nuxt/kit utilities like addServerHandler in a module, @nuxt/kit must be in the module's dependencies in package.json. If moved to peerDependencies, the application's version applies. The module starter sets this up correctly.

Module runtime code portability with nuxt/server

A module whose runtime code imports only from nuxt/server runs under any server builder from v4.6 onwards with no version check and no dependency on h3 or Nitro. Leave nuxt/server external when you bundle; it will be resolved in the Nuxt build to the right server builder utilities.

Supporting Nuxt versions before 4.6 with modules

Supporting Nuxt versions before 4.6 requires registering the portable file and the one you ship today side by side, and Nuxt will pick whichever the application can run, because those projects have no nuxt/server to resolve.

Virtual File System for modules

Nuxt provides a Virtual File System (VFS) that allows modules to add templates to the .nuxt/ directory without writing them to disk.

nuxt/kit helper imports for local modules

When defining local modules, you can import from 'nuxt/kit' as a helper subpath import. This means you do not need to add @nuxt/kit to your project's dependencies. Common imports include: addComponentsDir, addServerHandler, createResolver, and defineNuxtModule.

Local module example: hello module structure

Example local module with defineNuxtModule: export default defineNuxtModule({ meta: { name: 'hello' }, setup () { const resolver = createResolver(import.meta.url); addServerHandler({ route: '/api/hello', handler: resolver.resolve('./runtime/api-route'), }); addComponentsDir({ path: resolver.resolve('./runtime/app/components'), pathPrefix: true, }); } }). This registers an API route at /api/hello and components from the runtime/app/components directory.

Module loading order with numeric prefixes

You can change the order of local modules by adding a number to the front of each directory name, for example: modules/1.first-module/index.ts and modules/2.second-module.ts. This allows explicit control over the execution order.

addComponentsDir module API with pathPrefix

addComponentsDir is a function from nuxt/kit that registers a directory of components within a module. It takes an object with path (the resolved path to the components directory) and pathPrefix (a boolean; when true, it prefixes component exports to avoid conflicts with user code or other modules).

createResolver for module file resolution

createResolver is a function from nuxt/kit that takes import.meta.url and returns a resolver object with a resolve() method. This resolver is used to resolve file paths relative to the module directory, such as resolver.resolve('./runtime/api-route').

addServerHandler module API

addServerHandler is a function from nuxt/kit that registers an API route within a module. It takes an object with route (the API endpoint path as a string) and handler (the resolved path to the handler file).

defineNuxtModule function and meta property

defineNuxtModule is used to define a Nuxt module. It takes a configuration object with a meta property (containing at least a name field) and a setup function that receives the module context.

Module execution sequence

Modules are executed in the following sequence: first, the modules defined in nuxt.config.ts are loaded. Then, modules found in the modules/ directory are executed in alphabetical order.

Nuxt Content features

Nuxt Content provides the following features: render content with built-in components, query content with a MongoDB-like API, use Vue components in Markdown files with the MDC syntax, and automatically generate navigation.

Enable Nuxt Content module

To enable Nuxt Content, install the @nuxt/content module using the command: npx nuxt module add content. This installs the module and adds it to nuxt.config.ts automatically.

Render content with ContentRenderer component

To render content pages, use a catch-all route with the <ContentRenderer> component. The component accepts a value prop containing the page data. Use the useAsyncData composable with queryCollection('content').path(route.path).first() to fetch the content.

Catch-all route example for content

The following example shows how to render content pages using a catch-all route and ContentRenderer component: ```vue <script lang="ts" setup> const route = useRoute() const { data: page } = await useAsyncData(route.path, () => { return queryCollection('content').path(route.path).first() }) </script> <template> <div> <header><!-- ... --></header> <ContentRenderer v-if="page" :value="page" /> <footer><!-- ... --></footer> </div> </template> ```

addComponentsDir for library authors

Library authors can use the addComponentsDir method from @nuxt/kit in a Nuxt module to register a components directory for automatic tree-shaking and component registration.

Example: library author module with addComponentsDir

import { addComponentsDir, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { const resolver = createResolver(import.meta.url) addComponentsDir({ path: resolver.resolve('./components'), prefix: 'awesome', }) }, })

.nuxtrc setups section for module tracking

Nuxt automatically adds a setups section to the .nuxtrc file to track module installation and upgrade state. This section is used internally for module lifecycle hooks and should not be modified manually.

Disabling modules in Nuxt config

Starting in Nuxt v4.3, you can disable a module by setting its config key to `false` in your Nuxt config. This is particularly useful when you want to disable modules inherited from layers. Example: export default defineNuxtConfig({ image: false, })

buildModules is deprecated in Nuxt 3

The `buildModules` property used in Nuxt 2 is deprecated in favor of `modules`. Nuxt modules are now build-time-only.

How to add Nuxt modules to project

Modules are added to the `nuxt.config.ts` file under the `modules` property. The modules array can contain package names (recommended), local module paths, modules with inline options as arrays, or inline module definitions as async functions. Example: export default defineNuxtConfig({ modules: [ '@nuxtjs/example', './modules/example', ['./modules/example', { token: '123' }], async (inlineOptions, nuxt) => { }, ], })

Nuxt modules can be distributed and shared

Nuxt modules can be distributed in npm packages, making it possible for them to be reused across projects and shared with the community.

Nuxt module system purpose

Nuxt provides a module system to extend the framework core and simplify integrations. Nuxt modules are async functions that sequentially run when starting Nuxt in development mode using `nuxt dev` or building a project for production with `nuxt build`. They can override templates, configure webpack loaders, add CSS libraries, and perform many other useful tasks.

@nuxt/a11y module for accessibility development

@nuxt/a11y is a module that surfaces accessibility problems in your components while you develop. It is currently in alpha, so expect its API to change.

Best practices for library exports

Prefer named exports rather than default export to help reduce CJS conflicts. Avoid depending on Node.js built-ins and CommonJS or Node.js-only dependencies as much as possible to make your library usable in Browsers and Edge Workers without needing Nitro polyfills. Use the new exports field with conditional exports in package.json.

Migrating CommonJS to ESM syntax

Update require() usage to import statements. Before: module.exports = function () { } and exports.hello = 'world'. After: export default function () { } and export const hello = 'world'. For imports, change const myLib = require('my-lib') to import myLib from 'my-lib' or const dynamicMyLib = await import('my-lib').then(lib => lib.default || lib)

ESM globals replacement

In ESM Modules, unlike CJS, require, require.resolve, __filename and __dirname globals are not available. Replace __dirname with fileURLToPath(new URL('.', import.meta.url)). Use import { fileURLToPath } from 'node:url' and import { resolveModulePath } from 'exsolve' to handle path resolution.

Library author guide for ESM compatibility

There are two main options to fix ESM compatibility issues: 1) Rename ESM files to end with .mjs (recommended and simplest) and optionally rename CJS files to .cjs. 2) Make the entire library ESM-only by setting "type": "module" in package.json and ensuring the built library uses ESM syntax. The second option means the library can only be consumed in an ESM context.

Conditional exports in package.json

Use the exports field with conditional exports for ESM-compatible library distribution. Example: {"exports": {".": {"import": "./dist/mymodule.mjs"}}}

moduleDependencies example with Tailwind CSS

Example of declaring a module dependency on @nuxtjs/tailwindcss with version constraint and configuration: ```ts import { createResolver, defineNuxtModule } from '@nuxt/kit' const resolver = createResolver(import.meta.url) export default defineNuxtModule<ModuleOptions>({ meta: { name: 'my-module', }, moduleDependencies: { '@nuxtjs/tailwindcss': { version: '>=6', overrides: { exposeConfig: true, }, defaults: { config: { darkMode: 'class', content: { files: [ resolver.resolve('./runtime/components/**/*.{vue,mjs,ts}'), resolver.resolve('./runtime/*.{mjs,js,ts}'), ], }, }, }, }, }, setup (options, nuxt) { nuxt.options.css.push(resolver.resolve('./runtime/assets/styles.css')) }, }) ```

version constraint in moduleDependencies

The version field accepts a semver range. If the resolved module's version does not satisfy the specified range, Nuxt throws an error. Version checks only apply when the dependency can be resolved to a package.json, so they are a no-op for project-local modules.

overrides vs defaults in moduleDependencies

The overrides field provides configuration applied on top of nuxt.options, taking precedence over user configuration. The defaults field provides configuration applied below nuxt.options, where user configuration takes precedence over these defaults.

moduleDependencies configuration structure

Each entry in moduleDependencies uses the module identifier as the key. The value is an object that can contain: version (a semver range for validation), overrides (configuration applied on top of nuxt.options with precedence over user configuration), defaults (configuration applied below nuxt.options with user configuration taking precedence), and optional (boolean indicating whether the module is installed automatically when missing).

Depending on local modules in modules/ directory

When a dependency lives inside the modules/ directory, use a file path relative to the project root to declare the dependency. For example, './modules/my-local-module' or using a Nuxt alias like '~/modules/another-local-module'. A module at modules/foo.ts referencing modules/bar.ts must use './modules/bar', not './bar'. Using a Nuxt alias such as ~/modules/bar avoids ambiguity.

Module identifiers for moduleDependencies

Module dependencies can be declared using an npm package name, a path to a local module directory, or a Nuxt alias such as ~ or @.

moduleDependencies option for declaring module dependencies

The moduleDependencies option allows a Nuxt module to declare dependencies on other modules. Nuxt then ensures those modules are installed in the correct order, validates version constraints, and merges configuration supplied for them. This option replaces the deprecated installModule function.

optional module dependency

When optional is set to true in a moduleDependencies entry, the module is not installed automatically when missing. However, overrides and defaults are still applied if the module is installed elsewhere.

Module starter includes testing playground

The Nuxt module starter includes a playground Nuxt application for testing your module during development, as described in the module getting-started guide.

Manual testing of Nuxt modules with npm pack

To manually test a Nuxt module in another project, use npm pack (or your package manager equivalent) to create a tarball from the module. Then add the module to the test project's package.json as: "my-module": "file:/path/to/tarball.tgz". This allows testing the module as if it were a regular package in other Nuxt applications.

Example E2E test file structure

An E2E test file uses vitest for test framework and @nuxt/test-utils/e2e for utilities. The setup function is called with rootDir pointing to the fixture directory. Tests use $fetch to make requests and expect for assertions. Example: describe('ssr', async () => { await setup({ rootDir: fileURLToPath(new URL('./fixtures/ssr', import.meta.url)) }); it('renders the index page', async () => { const html = await $fetch('/'); expect(html).toContain('<div>ssr</div>') }) })

Nuxt Test Utils for E2E testing modules

Nuxt Test Utils is the recommended library for end-to-end testing of Nuxt modules. It is imported from '@nuxt/test-utils/e2e' and provides utilities like $fetch and setup for testing modules.

Example E2E test fixture setup for modules

A fixture is a minimal Nuxt application used for testing. It is defined in a nuxt.config.ts file inside test/fixtures/[name]/ and imports the module to be tested. Example: import MyModule from '../../../src/module'; export default defineNuxtConfig({ ssr: true, modules: [MyModule,] })

E2E test workflow for Nuxt modules

The E2E testing workflow involves five steps: (1) Create a Nuxt application to be used as a fixture inside test/fixtures/*, (2) Setup Nuxt with this fixture inside your test file using the setup function, (3) Interact with the fixture using utilities from @nuxt/test-utils (e.g. fetching a page with $fetch), (4) Perform checks related to this fixture (e.g. verify HTML content), (5) Repeat for other scenarios.

Module export prefixing best practice

It is highly recommended to prefix module exports (components, composables, server routes) to avoid conflicts with user code or other modules.

Sensitive data warning for public runtime config

Do not expose sensitive module configuration on the public runtime config, such as private API keys, as they will end up in the public bundle and be visible to users.

Modifying Nuxt configuration in modules

Nuxt configuration can be read and altered by modules using the nuxt object in the setup function. Use the logical OR assignment operator (||=) to conditionally create nested objects. For complex alterations, use the defu library to merge configurations.

Adding stylesheets from modules

To inject a stylesheet from a module, push the resolved stylesheet path to nuxt.options.css array using the resolver.

moduleDependencies for module dependencies

If your module depends on other modules, specify them using the moduleDependencies option in the module definition. It is an object where keys are module names and values are configuration objects (can be empty).

Module server route naming conventions

It is highly recommended to prefix module server routes (for example /api/_my-module/hello) to avoid conflicts with user-defined routes. Common paths like /api/auth, /api/login, or /api/user may already be used by the application.

runtime/app/ folder structure for module files

All components, pages, composables and other files that would normally be placed in your app/ folder need to be in runtime/app/ when creating a module. This allows them to be type checked properly.

addComponentsDir utility for bulk component registration

Use addComponentsDir from '@nuxt/kit' to add an entire directory of components as auto-imports. Provide the path property with a resolved path to the components directory.

addComponent utility for module components

Use the addComponent utility from '@nuxt/kit' to add Vue components as auto-imports. Each component requires: name (the component name to use in templates), export (optional, for named exports rather than default), and filePath (path to the component or library). Components can come from the module's runtime directory or from external libraries.

addPlugin utility for modules

Plugins are a common way for a module to add runtime logic. Use the addPlugin utility from '@nuxt/kit' to register plugins from your module. Create a resolver using createResolver(import.meta.url) to resolve relative paths, then call addPlugin(resolver.resolve('./runtime/plugin')) to register the plugin.

Module use cases

Nuxt modules can be used to integrate, enhance or extend Nuxt applications by adding integrations such as Vue plugins, CMS, server routes, components, and logging.

What are Nuxt modules

Nuxt modules are functions that sequentially run when starting Nuxt in development mode using `nuxt dev` or building a project for production with `nuxt build`. With modules, you can encapsulate, properly test, and share custom solutions as npm packages without adding unnecessary boilerplate to your project, or requiring changes to Nuxt itself.

Nuxt customization systems

Nuxt provides configuration and hooks systems that make it possible to customize every aspect of Nuxt and add any integration you might need, such as Vue plugins, CMS, server routes, components, logging, and more.

Register type declarations with prepare:types hook

Use the 'prepare:types' hook for more granular control over type registration. Create a template with addTemplate, then use nuxt.hook('prepare:types', ({ references }) => { references.push({ path: template.dst }) }) to register it.

Add type declarations with addTypeTemplate

Use the addTypeTemplate utility from @nuxt/kit to add a type declaration to the user's project and add a reference to it in the generated nuxt.d.ts file. Pass filename and getContents options. The generated file can augment Nuxt interfaces or provide global types: addTypeTemplate({ filename: 'types/my-module.d.ts', getContents: () => '/* type definitions */' }).

Update virtual files and templates with updateTemplates

Use the updateTemplates utility to reload a template that was previously registered. Pass a filter function to identify the template by filename: updateTemplates({ filter: t => t.filename === 'my-module-feature.mjs' }). This is typically done in response to the 'builder:watch' hook when watching files related to the template.

Give your agent this brain