Nuxt Modules Crash Course
Tags: nuxt, vue, javascript, tutorial
Published: 2023-10-30 08:45:43

{% embed https://vue.school/fw-jakub %}

A lot of people have been asking me recently about recording a video crash course about building modules for Nuxt. As I have already created several nuxt modules, I thought that this is indeed a great idea! If you would like to check these modules, check out the bonus section at the end of this article.

So today, I come to you with my newest video tutorial as well as this written version of it so that you can follow easily.

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

In this crash course, I am showing how to build a simple Nuxt module that will allow to easily connect to [Medusa](https://medusajs.com/)

## Module

To create this module, the first thing we need to do is to generate a new module template:

```bash
npx nuxi init -t module my-module
```

Then, go to the directory of this newly created module and lets install the Medusa JS SDK:

```bash
yarn add @medusajs/medusa-js
```

Now, let's go to the `module.ts` file and add all necessary configuration to make the module work.

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

export type ModuleOptions = Config

export default defineNuxtModule<ModuleOptions>({
  meta: {
    name: 'nuxt-medusa',
    configKey: 'medusa'
  },
  // Default configuration options of the Nuxt module
  defaults: {
    maxRetries: 3,
    baseUrl: 'http://localhost:9000'
  },
  setup (options, nuxt) {
    const resolver = createResolver(import.meta.url)
    const runtimeDir = fileURLToPath(new URL('./runtime', import.meta.url))

    nuxt.options.runtimeConfig.public.medusa = defu(nuxt.options.runtimeConfig.public.medusa, {
      ...options
    })

    addPlugin(resolver.resolve('./runtime/plugin'))

    addImportsDir(resolver.resolve(runtimeDir, 'composables'))
  }
})
```

In the video, I am explaining each step here so make sure to check it out for detailed explanation about each line and its purpose.

We have the configuration ready so let's focus now on initializing an actual Medusa client in our `plugin.ts` file:

```ts
import { defineNuxtPlugin } from '#app'
import { useRuntimeConfig } from '#imports'
import Medusa from '@medusajs/medusa-js'

export default defineNuxtPlugin((nuxtApp) => {
  const { medusa: config } = useRuntimeConfig().public

  const medusaClient = new Medusa(config)

  nuxtApp.provide('medusa', medusaClient)
})
```

We are initialising a new Medusa client with the configuration that we will get from the runtime config (set in the module.ts file) and we will provide it to the Nuxt app under the name `$medusa`.

For the Vue way, let's create a new Vue composable that will make working with our module just a little bit more fun.

```ts
import Medusa from '@medusajs/medusa-js'
import { useNuxtApp } from '#imports';

export const useMedusaClient = (): Medusa => {
  const { $medusa } = useNuxtApp();

  return $medusa
}
```

And that's it from the module perspective. Now, let's go to the playground to see our module in action.

## Using in Nuxt app

In order to make our module work, we need to make some adjustements in our `nuxt.config.ts` file.

```ts
export default defineNuxtConfig({
  modules: ['../src/module'],
  medusa: {
    baseUrl: 'https://production-like-starter.herokuapp.com',
    maxRetries: 3
  },
  devServer: {
    port: 8000
  },
  devtools: { enabled: true }
})
```

We are setting the `medusa` configuration to baseUrl that points to the Medusa demo application and maxRetries. Setting the devServer port to 8000 is caused purely because Medusa demo has some CORS configuration set by default so the app expects connection from medusa demo app or localhost:8000. In case of your local medusa application, you have full control over it, so you most probably wont need it.

And now we are ready to use the `useMedusaClient` composable to initialize the client and then fetch the products.

```ts
<template>
  <div>Nuxt module playground!</div>
</template>

<script setup lang="ts">
const client = useMedusaClient();

const products = await client.products.list();

console.log(products);
</script>
```

It is so simple yet it delivers so much value. We now have access to Medusa client and we can use it to fetch not only products, but categories, users, carts and many more!

## Summary

You have now managed to build a custom Nuxt module that you can later publish on npm and help other users build more efficient Nuxt applications. Nice Work!

Take care and see you next time!

## Bonus

If you are interested in other modules that I have created, check out the following links:

* https://github.com/Baroshem/nuxt-security
* https://github.com/nuxt-modules/cloudinary
* https://github.com/nuxt-modules/algolia
* https://github.com/Baroshem/nuxt-medusa