DEV Community

Cover image for Introduction to Nuxt modules
Jakub Andrzejewski
Jakub Andrzejewski

Posted on

Introduction to Nuxt modules

Developing my first Nuxt module took much more time than I expected, probably because I had no experience in creating such modules whatsoever. I spent hours reading Nuxt.js documentation (which is very good btw), watching tutorials, inspecting code repositories of other modules, so I was finally able to create my first module -> Adyen payment module for Nuxt. But don't worry. To built a second module, it took only 3 hours (including reading platform docs ;))

One of the best sources of knowledge so far about creating Nuxt modules is an article by @debs_obrien -> https://nuxtjs.org/tutorials/creating-a-nuxt-module/. Definitely worth checking out alongside this article to build your next (Nuxt ;) ) module.

What is a Nuxt module?

Nuxt.js has a very good documentation on the purpose and anatomy of modules, so I will just copy/paste some short definitions here.

Nuxt provides a higher-order module system that makes it possible to extend the core. Modules are functions that are called sequentially when booting Nuxt.

export default {
 modules: [
   // Using package name
   '@nuxtjs/axios',

   // Relative to your project srcDir
   '~/modules/awesome.js',

   // Providing options
   ['@nuxtjs/google-analytics', { ua: 'X1234567' }],

   // Inline definition
   function () {}
 ]
}
Enter fullscreen mode Exit fullscreen mode

For more details, I highly encourage you to read the modules section in the Nuxt.js documentation.

Nuxt module directory structure

Woah! There are many files here. I suppose, you can feel quite lost right now but don't worry. Below I explained each folder and meaningful file that you need to create/modify in order to have your own module set up.

nuxt-module-directory

dist

The output of your source files written in TypeScript (if your module is built on top of that). If you are using plain JavaScript you will most probably export your package with direct src/lib.

docs

Nuxt.js based docs for modules. Nuxt.js team provides a very good documentation template that you can see across many Nuxt modules.

nuxt-i18n-docs

In here you can write instructions on how to use your module in a Nuxt application.

example

In this directory you will find a very basic Nuxt project where you can test how your module works. It's good to keep it as simple as possible so that it will be easy for the newcomers to try it out.

Inside example/nuxt.config.js you can import the module and its options.

export default {
 modules: ['../src/module.js'],

 'my-awesome-module': {
   option1: 'test',
   ...
 }
}
Enter fullscreen mode Exit fullscreen mode

src/lib

In this directory you will put your files related to the module itself. The most basic example contains a module.js and plugin.js files.

module.js

In simple words, this file will be used as a declaration inside the nuxt.config.js file in the modules section. It will allow for module registration and will also accept some module options that will be later used in your plugin.js file.

const path = require('path')

const nuxtModule = function (moduleOptions) {
 const options = {
   ...this.options['my-awesome-module'],
   ...moduleOptions
 }

 this.addPlugin({
   src: path.resolve(runtimeDir, 'plugin.js'),
   fileName: 'my-awesome-module.js',
   options
 })
}

export default nuxtModule
Enter fullscreen mode Exit fullscreen mode

Inside this file you can also add some error handling when a user forgets to add certain options, modify options and create separate plugins for client, server, or both.

If you need to access the underlying server of Nuxt application you can do so by calling this.addServerMiddleware() and passing your routes. You can see an example in Nuxt docs.

The easiest way to indicate that a plugin is server/client side only is to add a corresponding word to the plugin name, i.e.:

 this.addPlugin({
   src: path.resolve(runtimeDir, 'plugin.js'),
   fileName: 'my-awesome-module.server.js',  // add .server here to make it server only
   options
 })
Enter fullscreen mode Exit fullscreen mode

If you are using TypeScript you can also declare global typings here:

declare module '@nuxt/types' {
 interface NuxtConfig {
   ['my-awesome-module']: ModuleOptions
 } // Nuxt 2.14+
 interface Configuration {
   ['my-awesome-module']: ModuleOptions
 } // Nuxt 2.9 - 2.13
 interface Context {
   ['$my-awesome-module']: Api
 }
}
Enter fullscreen mode Exit fullscreen mode

plugin.js

In this file you will be injecting content into global Nuxt context.

const configuration = <%= JSON.stringify(options, null, 2) %>

export default function (context, inject) {
 inject('my-awesome-module', configuration)
 context.app['my-awesome-module'] = configuration
}
Enter fullscreen mode Exit fullscreen mode

In some cases you may want to register a component/function to be used by Vue. You can do that here:

<% if (options.registerComponent) { %>
 import Vue from 'vue'
 import SomeComponent from '~directory/SomeComponent.vue'

 Vue.component('SomeComponent', SomeComponent);
<% } %>
Enter fullscreen mode Exit fullscreen mode

test

In this directory you will write your unit tests using Jest. The simplest unit test case can look like this:

describe('module', () => {
 setupTest({
   testDir: __dirname,
   fixture: '../example',
   server: true,
   config: {
     dev: true,
     'my-awesome-module': {
       option1: 'test',
     }
   }
 })

 test('should have config with Adyen options', () => {
   const { option1 } = getNuxt().options['my-awesome-module']

   expect(option1).toBeDefined()
 })
})
Enter fullscreen mode Exit fullscreen mode

Summary

You just got knowledge that should allow you to create your own Nuxt module. Well done! I highly encourage you to dig into the Nuxt.js documentation about modules and plugins, as well as the source code of certain modules to get a better understanding of how it is all working together.

I have recently released two E-Commerce related packages that you may want to checkout:

Bonus links

Discussion (0)