diff --git a/docs/2.guide/3.going-further/3.modules.md b/docs/2.guide/3.going-further/3.modules.md index 1588fa49af..83e1f80ddf 100644 --- a/docs/2.guide/3.going-further/3.modules.md +++ b/docs/2.guide/3.going-further/3.modules.md @@ -1,53 +1,123 @@ --- title: "Module Author Guide" -description: "Learn how to create a Nuxt module." +description: "Learn how to create a Nuxt Module to integrate, enhance or extend any Nuxt applications." +image: '/socials/module-author-guide.jpg' --- # Module Author Guide -A powerful configuration and hooks system makes it possible to customize almost every aspect of Nuxt Framework and add endless possible integrations when it comes to customization. +Learn how to create a Nuxt Module to integrate, enhance or extend any Nuxt applications. -Nuxt provides a zero-config experience with a preset of integrations and best practices to develop Web applications. -A powerful configuration and hooks system makes it possible to customize almost every aspect of Nuxt Framework and add endless possible integrations when it comes to customization. You can learn more about how Nuxt works in the [Nuxt internals](/docs/guide/going-further/internals) section. +Nuxt's [configuration](/docs/api/configuration/nuxt-config) and [hooks](/docs/guide/going-further/hooks) systems make it possible to customize every aspect of Nuxt and add any integration you might need (Vue plugins, CMS, server routes, components, logging, etc.). -Nuxt exposes a powerful API called **Nuxt Modules**. Nuxt modules are simple async functions that sequentially run when starting Nuxt in development mode using `nuxi dev` or building a project for production with `nuxi build`. -Using Nuxt Modules, we can encapsulate, properly test and share custom solutions as npm packages without adding unnecessary boilerplate to the Nuxt project itself. - -Nuxt Modules can hook into lifecycle events of Nuxt builder, provide runtime app templates, update the configuration or do any other custom action based on needs. +**Nuxt Modules** are functions that sequentially run when starting Nuxt in development mode using `nuxi dev` or building a project for production with `nuxi 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. ## Quick Start -For the impatient ones, You can quickly start with [module-builder](https://github.com/nuxt/module-builder) and [module starter template](https://github.com/nuxt/starter/tree/module): +We recommend you get started with Nuxt Modules using our [starter template](https://github.com/nuxt/starter/tree/module): ```bash npx nuxi init -t module my-module ``` -Starter template and module starter is a standard path of creating a Nuxt module. +This will create a `my-module` project with all the boilerplate necessary to develop and publish your module. **Next steps:** -1. Open `my-module` in the IDE of your choice (Visual Studio Code is recommended) -2. Install dependencies using the package manager of your choice (Yarn is recommended) -3. Ensure local files are generated using `npm run dev:prepare` -4. Start playground using `npm run dev` -5. Follow this document to learn more about Nuxt modules +1. Open `my-module` in your IDE of choice +2. Install dependencies using your favorite package manager +3. Prepare local files for development using `npm run dev:prepare` +4. Follow this document to learn more about Nuxt Modules -::alert{type=info icon=🚧} -This is an under-the-progress guide. Please regularly check for updates. +### Using the Starter + +Learn how to perform basic tasks with the module starter. + +#### How to Develop + +While your module source code lives inside the `src` directory, in most cases, to develop a module, you need a Nuxt application. That's what the `playground` directory is about. It's a Nuxt application you can tinker with that is already configured to run with your module. + +You can interact with the playground like with any Nuxt application. + +- Launch its development server with `npm run dev`, it should reload itself as you make changes to your module in the `src` directory +- Build it with `npm run dev:build` + +::alert{type=info} +All other `nuxi` commands can be used against the `playground` directory (e.g. `nuxi playground`). Feel free to declare additional `dev:*` scripts within your `package.json` referencing them for convenience. :: -## Module Anatomy +#### How to Test -A Nuxt module is a simple function accepting inline user options and `nuxt` arguments. +The module starter comes with a basic test suite: -It is totally up to you, as the module author, how to handle the rest of the logic. +- A linter powered by [ESLint](https://eslint.org), run it with `npm run lint` +- A test runner powered by [Vitest](https://vitest.dev), run it with `npm run test` or `npm run test:watch` -Starting with Nuxt 3, modules can benefit all [Nuxt Kit](/docs/api/advanced/kit) utilities. +::alert{type=info} +Feel free to augment this default test strategy to better suit your needs. +:: -```ts [modules/example.ts] -// modules/module.mjs -export default async (inlineOptions, nuxt) => { +#### How to Build + +Nuxt Modules come with their own builder provided by [`@nuxt/module-builder`](https://github.com/nuxt/module-builder#readme). This builder doesn't require any configuration on your end, supports TypeScript, and makes sure your assets are properly bundled to be distributed to other Nuxt applications. + +You can build your module by running `npm run prepack`. + +::alert{type=info} +While building your module can be useful in some cases, most of the time you won't need to build it on your own: the `playground` takes care of it while developing, and the release script also has you covered when publishing. +:: + +#### How to Publish + +::alert{type=warning} +Before publishing your module to npm, makes sure you have an [npmjs.com](https://www.npmjs.com) account and that you're authenticated to it locally with `npm login`. +:: + +While you can publish your module by bumping its version and using the `npm publish` command, the module starter comes with a release script that helps you make sure you publish a working version of your module to npm and more. + +To use the release script, first, commit all your changes (we recommend you follow [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0) to also take advantage of automatic version bump and changelog update), then run the release script with `npm run release`. + +When running the release script, the following will happen: + +- First, it will run your test suite by: + - Running the linter (`npm run lint`) + - Running unit, integration, and e2e tests (`npm run test`) + - Building the module (`npm run prepack`) +- Then, if your test suite went well, it will proceed to publish your module by: + - Bumping your module version and generating a changelog according to your Conventional Commits + - Publishing the module to npm (for that purpose, the module will be built again to ensure its updated version number is taken into account in the published artifact) + - Pushing a git tag representing the newly published version to your git remote origin + +::alert{type=info} +As with other scripts, feel free to fine-tune the default `release` script in your `package.json` to better suit your need. +:: + +## Developing Modules + +Nuxt Modules come with a variety of powerful APIs and patterns allowing them to alter a Nuxt application in pretty much any way possible. This section teaches you how to take advantage of those. + +### Module Anatomy + +We can consider two kinds of Nuxt Modules: + +- published modules are distributed on npm - you can see a list of some community modules on [the Nuxt website](/modules). +- "local" modules, they exist within a Nuxt project itself, either [inlined in Nuxt config](/docs/api/configuration/nuxt-config#modules) or as part of [the `modules` directory](/docs/guide/directory-structure/modules). + +In either case, their anatomy is similar. + +#### Module Definition + +::alert{type=info} +When using the starter, your module definition is available at `src/module.ts`. +:: + +The module definition is the entry point of your module. It's what gets loaded by Nuxt when your module is referenced within a Nuxt configuration. + +At a low level, a Nuxt Module definition is a simple, potentially asynchronous, function accepting inline user options and a `nuxt` object to interact with Nuxt. + +```js +export default function (inlineOptions, nuxt) { // You can do whatever you like here.. console.log(inlineOptions.token) // `123` console.log(nuxt.options.dev) // `true` or `false` @@ -57,34 +127,16 @@ export default async (inlineOptions, nuxt) => { } ``` -```ts [nuxt.config] -export default defineNuxtConfig({ - modules: [ - // Using package name (recommended usage) - '@nuxtjs/example', +Outside of short inline modules defined in `nuxt.config.ts`, **we do not recommend** using this low-level function definition. Instead, to define a module, **we recommend** using the higher-level `defineNuxtModule` helper provided by [Nuxt Kit](/docs/api/advanced/kit). - // Load a local module - './modules/example', - - // Add module with inline-options - ['./modules/example', { token: '123' }] - - // Inline module definition - async (inlineOptions, nuxt) => { } - ] -}) -``` - -## Defining Nuxt Modules - -Creating Nuxt modules involves tedious and common tasks. [Nuxt Kit](/docs/api/advanced/kit), provides a convenient and standard API to define Nuxt modules using `defineNuxtModule`: +This helper makes writing Nuxt Module more straightforward by implementing many common patterns seen in modules, guaranteeing future compatibility, and improving your module author developer experience and the one of your module users. ```js import { defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ meta: { - // Usually npm package name of your module + // Usually the npm package name of your module name: '@nuxtjs/example', // The key in `nuxt.config` that holds your module options configKey: 'sample', @@ -94,21 +146,20 @@ export default defineNuxtModule({ nuxt: '^3.0.0' } }, - // Default configuration options for your module + // Default configuration options for your module, can also be a function returning those defaults: {}, + // Shorthand sugar to register Nuxt hooks hooks: {}, - async setup(moduleOptions, nuxt) { - // -- Add your module logic here -- + // The function holding your module logic, it can be asynchronous + setup(moduleOptions, nuxt) { + // ... } }) ``` -The result of `defineNuxtModule` is a wrapper function with an `(inlineOptions, nuxt)` signature. It applies defaults and other necessary steps and calls the `setup` function when called. - -**`defineNuxtModule` features:** +Ultimately `defineNuxtModule` returns a wrapper function with the lower level `(inlineOptions, nuxt)` module signature. This wrapper function applies defaults and other necessary steps before calling your `setup` function: ::list - - Support `defaults` and `meta.configKey` for automatically merging module options - Type hints and automated type inference - Add shims for basic Nuxt 2 compatibility @@ -118,136 +169,127 @@ The result of `defineNuxtModule` is a wrapper function with an `(inlineOptions, - Expose `getOptions` and `getMeta` for internal usage of Nuxt - Ensuring backward and upward compatibility as long as the module is using `defineNuxtModule` from the latest version of `@nuxt/kit` - Integration with module builder tooling - :: -## Best Practices +#### Runtime Directory -### Async Modules - -Nuxt Modules can do asynchronous operations. For example, you may want to develop a module that needs fetching some API or calling an async function. - -::alert{type="warning"} -Be careful that `nuxi dev` waits for your module setup before going to the next module and starting the development server. Do time-consuming logic using deferred Nuxt hooks. +::alert{type=info} +When using the starter, the runtime directory is available at `src/runtime`. :: -### Always Prefix Exposed Interfaces +Modules, like everything in a Nuxt configuration, aren't included in your application runtime. However, you might want your module to provide, or inject runtime code to the application it's installed on. That's what the runtime directory enables you to do. -Nuxt Modules should provide an explicit prefix for any exposed configuration, plugin, API, composable, or component to avoid conflict with other modules and internals. +Inside the runtime directory, you can provide any kind of assets related to the Nuxt App: +- Vue components +- Composables +- [Nuxt plugins](/docs/guide/directory-structure/plugins) -Ideally, you should prefix them with your module's name (e.g. if your module is called `nuxt-foo`, expose `` and `useFooBar()` and **not** `