DEV Community

Cover image for Nuxt Modules Crash Course
Jakub Andrzejewski
Jakub Andrzejewski

Posted on • Updated on

Nuxt Modules Crash Course

Free Weekend - Get access to All 1000+ Vue School lessons

For 2 days, get free access to ANY course in the Vue School library. Choose from 54 courses and 1,000+ lessons. All you can watch in 48 hours!

favicon vueschool.io

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.

In this crash course, I am showing how to build a simple Nuxt module that will allow to easily connect to Medusa

Module

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

npx nuxi init -t module my-module
Enter fullscreen mode Exit fullscreen mode

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

yarn add @medusajs/medusa-js
Enter fullscreen mode Exit fullscreen mode

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

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'))
  }
})
Enter fullscreen mode Exit fullscreen mode

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:

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)
})
Enter fullscreen mode Exit fullscreen mode

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.

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

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

  return $medusa
}
Enter fullscreen mode Exit fullscreen mode

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.

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

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.

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

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

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

console.log(products);
</script>
Enter fullscreen mode Exit fullscreen mode

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:

Top comments (1)

Collapse
 
stefanobartoletti profile image
Stefano Bartoletti

Thanks for sharing, I'm in the process of building a Nuxt Module myself and I had a couple of nice insights here.