The complete solution to build and ship Nuxt modules.
- Compatible with Nuxt 3 and Nuxt Kit
- Unified build with tsdown
- Automated build config using last module spec
- Typescript and ESM support
- Auto generated types and shims for
@nuxt/schema
We recommend to checkout the Nuxt modules author guide before starting with the module-builder.
If you're upgrading a module from v1, follow the upgrade guide.
For a user to use a module generated from module-builder, it's recommended they have:
- Node.js >= 18.x. Latest Node LTS preferred
- Nuxt 3+.
Get started with our module starter:
npm create nuxt -- -t module my-moduleThe module builder requires a special project structure. You can check out the module template.
The entrypoint for module definition.
A default export using defineNuxtModule and ModuleOptions type export is expected.
You could also optionally export ModuleHooks or ModuleRuntimeHooks to annotate any custom hooks the module uses.
import { defineNuxtModule } from '@nuxt/kit'
export interface ModuleOptions {
apiKey: string
}
export interface ModuleHooks {
'my-module:init': any
}
export interface ModuleRuntimeHooks {
'my-module:runtime-hook': any
}
export interface ModuleRuntimeConfig {
PRIVATE_NAME: string
}
export interface ModulePublicRuntimeConfig {
NAME: string
}
export default defineNuxtModule<ModuleOptions>({
meta: {
name: 'my-module',
configKey: 'myModule'
},
defaults: {
apiKey: 'test'
},
async setup (moduleOptions, nuxt) {
// Write module logic in setup function
}
})Any runtime file and code that we need to provide by module including plugins, composables and server api, should be in this directory.
Each file is transpiled individually to dist/runtime/.
A minimum package.json should look like this:
{
"name": "my-module",
"license": "MIT",
"version": "1.0.0",
"exports": {
".": {
"types": "./dist/types.d.mts",
"import": "./dist/module.mjs"
}
},
"main": "./dist/module.mjs",
"typesVersions": {
"*": {
".": [
"./dist/types.d.mts"
]
}
},
"files": [
"dist"
],
"scripts": {
"prepack": "nuxt-module-build build"
},
"dependencies": {
"@nuxt/kit": "latest"
},
"devDependencies": {
"@nuxt/module-builder": "latest",
"tsdown": "^0.23.7"
}
}tsdown is a peer dependency, so install it alongside @nuxt/module-builder.
Module builder is a preset for tsdown. See src/build/build.ts for the options it passes to tsdown.
To build entrypoints other than src/module, list them in the build.entries field of package.json:
{
"build": {
"entries": [
"./src/utils"
]
}
}Warning
build.config.ts and the unbuild field of package.json are deprecated.
The build still applies their entries, externals, replace, rollup.replace, and sourcemap options,
and the build:before, rollup:done, and build:done hooks. mkdist:* hooks are ignored, a few options
are accepted at their defaults, and any other option fails the build. Import defineBuildConfig from
@nuxt/module-builder instead of unbuild. See Build configuration
in the upgrade guide for the full list.
Module builder generates dist files in dist/ directory:
module.mjs: Module entrypoint build fromsrc/modulemodule.json: Module meta extracted frommodule.mjs+package.jsontypes.d.mts: Exported types in addition to shims fornuxt.configauto completion.runtime/*: Individually transpiled files- JavaScript and
.tsfiles are transpiled to.js, with their types extracted to a.d.tsfile of the same name .vuefiles are transpiled to.vue, with their types extracted to.vue.d.tsand.d.vue.tsfiles.cssfiles have their nesting flattened, and are vendor-prefixed and minified.scssand.sassfiles are compiled to.csswith the module'ssassorsass-embedded;_partials aren't emitted- Other files are copied as they are
- JavaScript and
The runtime build is a rolldown plugin, transpileDir, exported from @nuxt/module-builder/rolldown. Use it in any tsdown or rolldown build that transpiles a directory file by file instead of bundling it:
// tsdown.config.ts
import { defineConfig } from 'tsdown'
import { transpileDir } from '@nuxt/module-builder/rolldown'
export default defineConfig({
entry: ['src/index.ts'],
plugins: [
transpileDir({ srcDir: 'src/runtime', outBase: 'runtime' }),
],
})Every file under srcDir is emitted under outBase in the build's output directory, with its name intact apart from the extension. Scripts become .js (or .mjs), and compiled Sass becomes .css. Test and story files are excluded by default. Scripts are transpiled with oxc and keep their imports as written, apart from relative imports, which get the emitted extension. .vue files are transpiled with vue-sfc-transformer, stylesheets are processed as described in Dist files, and other files are copied. Declarations come from one TypeScript program that uses the nearest tsconfig.json.
The options are documented on the TranspileDirOptions type. The resolveExternal option controls what happens to relative imports that resolve outside srcDir. A build with nothing to bundle can pass emptyEntry, from the same export, as its entry.
- Clone repository
- Enable Corepack using
corepack enable - Install dependencies using
pnpm install - Try building example module using
pnpm example:build
MIT - Made with π