Modules

Modules are Nuxt.js extensions which can extend its core functionality and add endless integrations.

Introduction

While developing production-grade applications with Nuxt, you'll soon discover that the framework's core functionality is not enough. Nuxt can be extended with configuration options and plugins, but maintaining these customizations across multiple projects is tedious, repetitive and time-consuming. On the other hand, supporting every project's needs out of the box would make Nuxt very complex and hard to use.

This is one of the reasons why Nuxt provides a higher-order module system that makes it easy to extend the core. Modules are simply functions that are called sequentially when booting Nuxt. The framework waits for each module to finish before continuing. In this way, modules can customize almost any aspect of Nuxt. Thanks to Nuxt's modular design (based on webpack's Tapable), modules can easily register hooks for certain entry points like the builder initialization. Modules can also override templates, configure webpack loaders, add CSS libraries, and perform many other useful tasks.

Best of all, Nuxt modules can be incorporated into npm packages. This makes them easy to reuse across projects and to share with the Nuxt community, helping create an ecosystem of high-quality Nuxt add-ons.

Modules are great if you:

  • Are a member of an agile team that needs to quickly bootstrap new projects.
  • Are tired of re-inventing the wheel for common tasks like integrating Google Analytics.
  • Are a lovely Open Source enthusiast who would like to easily share your work with the community.
  • Are a member of an enterprise company that values quality and reusability.
  • Are often up against short deadlines and don't have time to dig into the details of every new library or integration.
  • Are tired of dealing with breaking changes to low-level interfaces, and need things that just work™.

List of Nuxt.js modules

The Nuxt.js team offers official modules:

  • @nuxt/http: Light and universal way to make HTTP requests, based on ky-universal
  • @nuxt/content: Write in a content/ directory and fetch your Markdown, JSON, YAML and CSV files through a MongoDB like API
  • @nuxtjs/axios: Secure and Easy Axios integration with Nuxt.js to make HTTP requests
  • @nuxtjs/pwa: Supercharge Nuxt with a heavily tested, updated and stable PWA solution
  • @nuxtjs/auth: Authentication module for Nuxt.js, offering different schemes and strategies

A list of Nuxt.js modules made by the community is available on https://awesomejs.dev/for/nuxt/ and https://github.com/topics/nuxt-module

Write a basic Module

As already mentioned modules are just simple functions. They can be packaged as npm modules or directly included in project source code.

modules/simple.js

export default function SimpleModule (moduleOptions) {
  // Write your code here
}

// REQUIRED if publishing the module as npm package
// module.exports.meta = require('./package.json')

moduleOptions

This is the object passed using modules array by user we can use it to customize it's behavior.

this.options

You can directly access Nuxt options using this reference. This is the content of the user's nuxt.config.js with all default options assigned to. It can be used for shared options between modules.

this.nuxt

This is a reference to current Nuxt instance. Refer to Nuxt class docs for available methods.

this

Context of modules. Please look into the ModuleContainer class docs for available methods.

module.exports.meta

This line is required if you are publishing module as an npm package. Nuxt internally uses meta to work better with your package.

nuxt.config.js

export default {
  modules: [
    // Simple usage
    '~/modules/simple'

    // Passing options directly
      ['~/modules/simple', { token: '123' }]
  ]
}

We then tell Nuxt to load some specific modules for a project with optional parameters as options. Please refer to modules configuration docs for more info!

Async Modules

Not all modules will do everything synchronous. For example you may want to develop a module which needs fetching some API or doing async IO. For this, Nuxt supports async modules which can return a Promise or call a callback.

Build-only Modules

Usually, modules are only required during development and build time. Using buildModules helps to make production startup faster and also significantly decreasing node_modules size for production deployments. If you are a module author, It is highly recommended to suggest users installing your package as a devDependency and use buildModules instead of modules for nuxt.config.js.

Your module is a buildModule unless:

  • It is providing a serverMiddleware
  • It has to register a Node.js runtime hook (Like sentry)
  • It is affecting vue-renderer behavior or using a hook from server: or vue-renderer: namespace
  • Anything else that is outside of webpack scope (Hint: plugins and templates are compiled and are in webpack scope)

NOTE: If you are going to offer using buildModules please mention that this feature is only available since Nuxt v2.9. Older users should upgrade Nuxt or use the modules section.

Use async/await

import fse from 'fs-extra'

export default async function asyncModule () {
  // You can do async works here using `async`/`await`
  const pages = await fse.readJson('./pages.json')
}

Return a Promise

import axios from 'axios'

export default function asyncModule () {
  return axios.get('https://jsonplaceholder.typicode.com/users')
    .then(res => res.data.map(user => '/users/' + user.username))
    .then((routes) => {
      // Do something by extending Nuxt routes
    })
}

Common Snippets

Top level options

Sometimes it is more convenient if we can use top level options while registering modules in nuxt.config.js. This allows us to combine multiple option sources.

nuxt.config.js

export default {
  modules: [
    ['@nuxtjs/axios', { anotherOption: true }]
  ],

  // axios module is aware of this by using `this.options.axios`
  axios: {
    option1,
    option2
  }
}

module.js

export default function (moduleOptions) {
  // `options` will contain option1, option2 and anotherOption
  const options = Object.assign({}, this.options.axios, moduleOptions)

  // ...
}

Provide plugins

It is common that modules provide one or more plugins when added. For example bootstrap-vue module would require to register itself into Vue. In such situations we can use the this.addPlugin helper.

plugin.js

import Vue from 'vue'
import BootstrapVue from 'bootstrap-vue/dist/bootstrap-vue.esm'

Vue.use(BootstrapVue)

module.js

import path from 'path'

export default function nuxtBootstrapVue (moduleOptions) {
  // Register `plugin.js` template
  this.addPlugin(path.resolve(__dirname, 'plugin.js'))
}

Template plugins

Registered templates and plugins can leverage lodash templates to conditionally change registered plugins output.

plugin.js

// Set Google Analytics UA
ga('create', '<%= options.ua %>', 'auto')

<% if (options.debug) { %>
// Dev only code
<% } %>

module.js

import path from 'path'

export default function nuxtBootstrapVue (moduleOptions) {
  // Register `plugin.js` template
  this.addPlugin({
    src: path.resolve(__dirname, 'plugin.js'),
    options: {
      // Nuxt will replace `options.ua` with `123` when copying plugin to project
      ua: 123,

      // conditional parts with dev will be stripped from plugin code on production builds
      debug: this.options.dev
    }
  })
}

Add a CSS library

If your module will provide a CSS library, make sure to perform a check if the user already included the library to avoid duplicates, and add an option to disable the CSS library in the module.

module.js

export default function (moduleOptions) {
  if (moduleOptions.fontAwesome !== false) {
    // Add Font Awesome
    this.options.css.push('font-awesome/css/font-awesome.css')
  }
}

Emit assets

We can register webpack plugins to emit assets during build.

module.js

export default function (moduleOptions) {
  const info = 'Built by awesome module - 1.3 alpha on ' + Date.now()

  this.options.build.plugins.push({
    apply (compiler) {
      compiler.plugin('emit', (compilation, cb) => {
        // This will generate `.nuxt/dist/info.txt' with contents of info variable.
        // Source can be buffer too
        compilation.assets['info.txt'] = { source: () => info, size: () => info.length }

        cb()
      })
    }
  })
}

Register custom webpack loaders

We can do the same as build.extend in nuxt.config.js using this.extendBuild.

module.js

export default function (moduleOptions) {
    this.extendBuild((config, { isClient, isServer }) => {
      // `.foo` Loader
      config.module.rules.push({
        test: /\.foo$/,
        use: [...]
      })

      // Customize existing loaders
      // Refer to source code for Nuxt internals:
      // https://github.com/nuxt/nuxt.js/tree/dev/packages/builder/src/webpack/base.js
      const barLoader = config.module.rules.find(rule => rule.loader === 'bar-loader')
  })
}

Run Tasks on Specific hooks

Your module may need to do things only on specific conditions and not just during Nuxt initialization. We can use the powerful hooks Nuxt.js system to do tasks on specific events (based on Hable). Nuxt will wait for your function if it return a Promise or is defined as async.

Here are some basic examples:

export default function myModule () {
  this.nuxt.hook('modules:done', (moduleContainer) => {
    // This will be called when all modules finished loading
  })

  this.nuxt.hook('render:before', (renderer) => {
    // Called after the renderer was created
  })

  this.nuxt.hook('build:compile', async ({ name, compiler }) => {
    // Called before the compiler (default: webpack) starts
  })

  this.nuxt.hook('generate:before', async (generator) => {
    // This will be called before Nuxt generates your pages
  })
}

Module package commands

Experimental

Starting in v2.4.0, you can add custom nuxt commands through a Nuxt module's package. To do so, you must follow the NuxtCommand API when defining your command. A simple example hypothetically placed in my-module/bin/command.js looks like this:

#!/usr/bin/env node

const consola = require('consola')
const { NuxtCommand } = require('@nuxt/cli')

NuxtCommand.run({
  name: 'command',
  description: 'My Module Command',
  usage: 'command <foobar>',
  options: {
    foobar: {
      alias: 'fb',
      type: 'string',
      description: 'Simple test string'
    }
  },
  run (cmd) {
    consola.info(cmd.argv)
  }
})

A few things of note here. First, notice the call to /usr/bin/env to retrieve the Node executable. Also notice that ES module syntax can't be used for commands unless you manually incorporate esm into your code.

Next, you'll notice how NuxtCommand.run() is used to specify the settings and behavior of the command. Options are defined in options, which get parsed via minimist. Once arguments are parsed, run() is automatically called with the NuxtCommand instance as first parameter.

In the example above, cmd.argv is used to retrieve parsed command-line arguments. There are more methods and properties in NuxtCommand -- documentation on them will be provided as this feature is further tested and improved.

To make your command recognizable by the Nuxt CLI, list it under the bin section of your package.json, using the nuxt-module convention, where module relates to your package's name. With this central binary, you can use argv to further parse more subcommands for your command if you desire.

{
  "bin": {
    "nuxt-foobar": "./bin/command.js"
  }
}

Once your package is installed (via NPM or Yarn), you'll be able to execute nuxt foobar ... on the command-line.

There are way more hooks and possibilities for modules. Please read the Nuxt Internals to find out more about the nuxt-internal API.

Platinum Sponsors

Storyblok Support Us