Introduction to Nuxt Modules - Revisited
Tags: nuxt, vue, javascript, typescript
Published: 2023-07-24 07:58:27

Almost two years ago, I have released my article about the same topic as this one -> `Introduction to Nuxt Modules` 🚀
You can check it out [here](https://dev.to/jacobandrewsky/introduction-to-nuxt-modules-21a1) if you like but it is probably a bit out of date and that is why I decided to create a more modern version today.

I really love the idea of modules as a way for individual contributors to be able to add their `brick` to the framework ecosystem. Why? Purely because it is an isolated environment that you can create in your private repository and work on it without worrying about breaking something in the main framework repository.

And when you will get more proficient with patterns you can always jump in the main repo and contribute there (believe me, there is a lot of issues that you can grab and help framework grow)

In this article, I will focus on the modules that I have created for the Nuxt ecosystem, how they work, and how you become a module author even today!

Let's jump in!

## What are modules?

I won't be explaining that much how the modules work because I did it already in my previous article and there was not that much changes since then. Interestingly, when I released this article back in 2021, there was no actual official guide from Nuxt about this topic. So, my article was used as an official documentation about creating Nuxt modules.

But today, there is a Muxt Module author guide that you can check out [here](https://nuxt.com/docs/guide/going-further/modules)

![Nuxt Module Author](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0xhglx168d9ayg5d8ltz.png)

For those of you who are coming from Nuxt 2 there is a really good information bout compatibility

Nuxt 3 has a basic backward compatibility layer for Nuxt 2 modules using @nuxt/kit auto wrappers. But there are usually steps to follow to make modules compatible with Nuxt 3 and sometimes, using Nuxt Bridge is required for cross-version compatibility.

Regarding the modules themselves, there is actually a lot of them!

![Nuxt Modules](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mic3svzablvtke87m5h2.png)

Check out the official page [here](https://nuxt.com/modules)


## Content about creating a Nuxt module

Regarding the content about building and maintaining Nuxt modules, there is actually a lot of videos and tutorials that you can check out. But two of them are basically go to as they show it from scratch.

First of them is the recording of my talk at Vue.js Global Summit about Building Modules for Nuxt 3 that you can check out below:

{% embed https://www.youtube.com/watch?v=6jJ6Gssf0bI %}

It basically guides you through the process of building a Nuxt module for ngrok (a tool that allows you to access your localhost application from web). Very simple one but back then there was no content about it so such step by step tutorial was really useful.

And next, I have a recording of the talk made by @lihbr at most recent Vue.js Live conference that we attended together. You can check the video [here](https://portal.gitnation.org/contents/nuxt-3-modules-and-open-source)

In it, Lucie will guide you through the similar process of building modules and show how you can become a great maintainer!

## Deeper look into the structure of a Nuxt Module

For this deeper look, I will be using my Medusa module for Nuxt as it is relatively easy to explain and it covers several concepts that can be useful for you when building your module. Below, you can see the folder and files structure of the module:

![Nuxt Module File Structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2rz6yl64myrrsrfvdk92.png)

Let's talk about each meaningful folder / file in this repo.

### `.github`

This folder contains issue and PR templates as well as the whole CI process including testing, linting, building the project. It is more for the maintainer part of the work on the modules.

### `.stackblitz`

This is my recent idea to keep the Stackblitz template in the repository of the module so that it is easier to keep it up to date with the changes to the module. It basically contains the simple Nuxt application with the module implemented. In the README.md there is a link to the Stackblitz that will clone the repo and start the project for fast discovery.

### `docs`

This folder contains all the files that are necessary to generate a documentation page built with [docus](https://docus.dev/) that you can check out [here](https://nuxt-medusa.vercel.app/). It is not mandatory for the module repository but I like to keep everything in one place for easy maintenance.

### `playground`

This folder contains the local Nuxt application with the direct link to the module file. It is great for local testing and development. I sometimes get questions what is the difference between `playground` and `.stackblitz`. I explain it that playground is a local testing project while .stackblitz is a remote testing project (purely because playground has a link to the local project while .stackblitz downloads the module from npm)

### `src`

Contains all the source code for your module. It must have a `module.ts` file with structure more or less like following:


```ts
import { defineNuxtModule, addPlugin, createResolver, addImportsDir, extendViteConfig, addTemplate } from '@nuxt/kit'
import { fileURLToPath } from 'url'
import { defu } from 'defu'
import { Config } from '@medusajs/medusa-js'

export type ModuleOptions = Config & { global?: boolean, server: boolean }

export default defineNuxtModule<ModuleOptions>({
  meta: {
    name: 'nuxt-medusa',
    configKey: 'medusa'
  },
  defaults: {
    baseUrl: 'http://localhost:9000',
    maxRetries: 3,
    global: true,
    server: false,
  },
  setup (options, nuxt) {
    const resolver = createResolver(import.meta.url)

    if (options.global) addPlugin(resolver.resolve('./runtime/plugin'))

    const runtimeDir = fileURLToPath(new URL('./runtime', import.meta.url))
    nuxt.options.build.transpile.push(runtimeDir)
    nuxt.options.build.transpile.push("@medusajs/medusa-js");
})
```

This `module.ts` file is also a wrapper for everything else that your module can include to the basic Nuxt application like:

* Auto-imported components
* Auto-imported composables
* Server utilities
* Plugins
* CSS
* Many more!

There is actually many things that you can do in the module so threat it like a useful wrapper for the functionality that someone could reuse in many cases.

### `test`

This folder includes all files related to automatic testing of your module by using tools like Vitest and Playwright. Here you can write test cases and run them from CI after each pull request / merge.

### other files

And there are also many other files here that are used for configuring the linters/pretiers/npm/git/etc. I usually just copy/paste them from one module to another and just adjust them to a new project.

## Bonus - The modules that I have created

Because of my positive experience of using the modules, I wanted to build and maintain one by myself. And I liked it so much that today, I am a maintainer of four Nuxt modules:

* [Security](https://github.com/Baroshem/nuxt-security) - A Security module for Nuxt based on OWASP Top 10 and Helmet. With no configuration it allows you to have more secure web application, but it also comes with customisability options so that you can adjust it to match your needs.
* [Algolia](https://github.com/nuxt-modules/algolia) - Use Algolia related functionalities like Algoliasearch, InstantSearch, Docsearch, and Recommend by using a single package.
* [Cloudinary](https://github.com/nuxt-modules/cloudinary) - Deliver optimized and performant images for the modern web by using simple components and composables to fetch images directly from Cloudinary
* [Medusa](https://github.com/Baroshem/nuxt-medusa) - Easily connect to your Medusa Headless Commerce platform from your Nuxt application.

So, as you can see, I have created few of them already. If you like any of them, do not hesitate to add a GitHub start to make the module grow!