written by Andre Liem
07/18/2017

An introduction to Nuxt Modules

When you start deep diving into Nuxt, one feature that you should look at sooner than later are modules. Otherwise you'll find yourself re-inventing the wheel on functionality that has already been built. Because Nuxt is so new, there is very little documentation on it, but you can check out the github community page.

As of this post, there is already a good sizeable list of modules available to use. Here is an example of a few posted on the community page which I am using or looking to use in the near future.

  • axios
  • font-awesome
  • bootstrap
  • google-analytics
  • markdownit

What about Plugins?

Modules may seem similar to plugins, after all you configure them in nuxt.config.js in a similar fashion.

  plugins: [...],
  modules: [...]

Aside from this, Nuxt Plugins are really best used as wrappers around existing VueJS plugins or external code. For example, this is how you would integrate a notification library for Vue.

Create wrapper file plugins/vue-notification.js

import Vue from 'vue'
import VueNotifications from 'vue-notifications'

Vue.use(VueNotifications)

Then add it to your config file nuxt.config.js

module.exports = {
  plugins: ['~plugins/vue-notifications']
}

This configuration system provides a clean way of seperating external plugins which have little configuration overhead. It's important to note you can pass in more parameters into Plugins, such as whether it's SSR or not. Go check out the offical docs for more info.

Is it a Module or Plugin?

The lines are a bit blurry as to when to use or build functionality as a module or plugin. I'm sure this will be clearer when the official documentation comes out on Modules. For now, my own interpretation of Modules is that a module is a more complex Plugin, it can encapsulate a lot more functionality and not simply act as a wrapper around an existing Vue Component library. If you for example, want to do a lot of setup work around a Plugin, you'll probably be better off creating a module and passing in several options.

For example, lets take a look at the Google Analytics module.

A key requirement of using Google Analytics is supplying the UA code. In this code snippet below you can pass this as an option parameter.

modules: [
  ['@nuxtjs/google-analytics', { ua: 'UA-XXXXXXXX-X' }],
]

Then, here's a snippet of how it works.

index.js packages the code into a module and passes in some options.

<script type="text/javascript">
const path = require('path')

module.exports = function nuxtAnalytics(options) {
  // Don't include on dev mode
  if (this.options.dev && process.env.NODE_ENV !== 'production') {
    return
  }

  // Add google analytics script to head
  this.options.head.script.push({
    src: options.analyticsURL || 'https://www.google-analytics.com/analytics.js',
    async: true
  })

  // Register plugin
  this.addPlugin({src: path.resolve(__dirname, 'plugin.js'), ssr: false, options})
}

module.exports.meta = require('./package.json')
</script>

Notice how this code handles high level configuration details, such as not loading in dev mode, and pulling in the analytics library. It's also responsible for registering the plugin.js file (code snippet below) which does the actual work. So this module is in fact a wrapper around a plugin.

<script type="text/javascript">
export default ({ app: { router, store } }) => {
  if (!window['ga']) {
    console.warn('google analytics is not available')
    return
  }

  // Set the current page
  ga('create', '<%= options.ua %>', 'auto')

  // Every time the route changes (fired on initialization too)
  router.afterEach((to, from) => {
    // Set page settings
    const settings = Object.assign({}, routeOption('analytics', from, to, store), to.meta && to.meta.analytics)
    Object.keys(settings).forEach(key => {
      ga('set', key, settings[key])
    })

    // We tell Google Analytics to add a page view
    ga('set', 'page', to.fullPath)
    ga('send', 'pageview')
  })
}
</script>

This file is responsible for sending the pageview to Google Analytics by hooking into the router. Notice how in this file we have access to the router and store.

Modules in use here

On the VueJSRadar, I am using a few modules already. Thanks to the tips from the community I found these early and saved a lot of time. Although I'll have to admit I did spend many hours hooking in different markdown plugins before I found there was an official markdownit module

Here's a snippet of the configuration I have to load bootstrap, font awesome, google analytics, and markdown with syntax highlighting.

modules: [
  '@nuxtjs/bootstrap-vue',
  '@nuxtjs/font-awesome',
  ['@nuxtjs/google-analytics', { ua: '...' }],
  ['@nuxtjs/markdownit', { html: true, linkify: true, breaks: true, highlight: (code, lang) => {
    const Prism = require('prismjs')
    return Prism.highlight(code, Prism.languages[lang] || Prism.languages.markup)
  } } ]
]

A module I would like to see in the near future is one which can generate a sitemap for Google Webmaster tools. Perhaps it will be something I attempt to create in the near future.

Wrapping up

That's it for this post. I'm excited to see what the Nuxt guys have in store for us when version 1.0 comes out. In the meantime, I would encourage developers to check out the modules and look at contributing to the ecosystem!