Building a Nuxt Modules clone with Nuxt 3, TailwindCSS, Storyblok, and Vercel
Tags: nuxt, tailwindcss, vue, javascript
Published: 2022-05-04 07:50:06

The Release Candidate version of Nuxt 3 dropped out of nowhere! The official release was rescheduled few times but we finally have it so it would be awesome to dive deeper into what it brings to the Nuxt ecosystem. And this is exactly what me and @alvarosabu did during our most recent video colaboration that I highly recommend you to check out with a link below:

{% youtube _GTWki_NoPI %}

In this article, I will summarize each step that we have taken in the video with a written examples and step by step guide. Enjoy!

If you get lost at some point, you can always check out the following github repository:

https://github.com/alvarosabu/nuxt-modules-clone

## Nuxt 3

The first step is to generate new project using:

```bash
npx nuxi init nuxt-modules-clone
```

This will generate a default Nuxt 3 project. Let's try to test the newest addition to the ecosystem which is the support for Static Site Generation. In `nuxt.config.ts` add following line:

```ts
export default defineNuxtConfig({
    ssr: false,  // <-
})
```

Now, let's build the project with the following command:

```bash
yarn generate
```

Finally, if we serve the generated static HTML files with the following command:

```bash
serve .output/public
```

*serve is an addition to VS Code that allows to serve static files with local server

We should now see the same result as with `yarn dev` in the broweser. Awesome!

## TailwindCSS

We now how to generate a static HTML page. Now, let's add a bit of styling into it to make it look a bit better. We will install TailwindCSS by using the official Nuxt module and style some parts of the application.

The installation of the module is relatively simple. Just use the following command:

```bash
yarn add --dev @nuxtjs/tailwindcss
```

And register the module in `nuxt.config.ts` in the modules array:

```ts
export default defineNuxtConfig({
    modules: ['@nuxtjs/tailwindcss'] // <-
})
```

From now on, you can use the TailwindCSS across your application. We will create a `TheHeader.vue` component by using the official Nuxt 3 CLI method:

```bash
npx nuxi add component TheHeader
```

And add a bit of styling into it:

```vue
<script lang="ts" setup></script>

<template>
  <header class="bg-white py-4 shadow-lg">
    <div class="container mx-auto">
      <a href="" class="flex items-center"> <img class="h-8 w-8 mr-4" src="/logo.svg" /> Nuxt Module</a>
    </div>
  </header>
</template>

<style scoped></style>
```

Inside `/public/logo.svg` add following svg code:

```html
<svg width="40" height="40" viewBox="0 0 70 70" fill="none" xmlns="http://www.w3.org/2000/svg" alt="Nuxt"><path d="M31.4918 17.1505C29.8172 14.2712 25.6308 14.2712 23.9562 17.1505L5.70589 48.5305C4.03131 51.4099 6.12453 55.009 9.4737 55.009H23.7209C22.2898 53.7583 21.7598 51.5946 22.8428 49.7382L36.6648 26.0451L31.4918 17.1505Z" fill="#80EEC0"></path><path d="M43.0556 24.0338C44.4415 21.678 47.9061 21.678 49.292 24.0338L64.3957 49.7083C65.7816 52.0641 64.0493 55.0089 61.2775 55.0089H31.0701C28.2984 55.0089 26.566 52.0641 27.9519 49.7083L43.0556 24.0338Z" fill="#00DC82"></path></svg>
```

Finally, we can use our new `TheHeader` component inside our `app.vue`

```vue
<template>
  <TheHeader />
</template>
```

## Storyblok

To add content into our page we will use Storyblok CMS. 

Let's install the required dependencies by typing following command:

```bash
yarn add @storyblok/vue
yarn add --dev axios
```

In order to make Storyblok work, we will use a Nuxt plugin. Create `/plugins/storyblok.ts` file and add following code into it:

```ts
import {
    StoryblokVue, apiPlugin
} from '@storyblok/vue';

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

    nuxtApp.vueApp.use(StoryblokVue, {
        accessToken: config.apiToken,
        use: [apiPlugin]
    });
})
```

*Remember to create a .env file with an access token grabbed from Storyblok.

Let's add storyblok token to runtimeConfig:

```ts
export default defineNuxtConfig({
    runtimeConfig: {
        public: {
            apiToken: process.env.STORYBLOK_TOKEN
        }
    },
})
```

Now, let's create a `ModuleCard` component that we will use to show each module:

```vue
<script lang="ts" setup>
const props = defineProps({
  name: {
    type: String,
    default: "Module Card"
  },
  description: {
    type: String,
    default: "Crazy description"
  },
  icon: {
    type: Object,
    default: () => ({})
  },
  url: {
    type: Object,
    default: () => ({})
  }
})
</script>

<template>
  <a class="flex justify-center" :href="url.url">
    <div class="flex items-center p-8 flex-col md:flex-row md:max-w-xl rounded-lg bg-white shadow-lg">
      <img class="w-10 h-10 object-fit" :src="icon.filename" :alt="icon.alt" />
      <div class="px-8 flex flex-col justify-start">
        <h5 class="text-gray-900 text-xl font-medium mb-2">{{name}}</h5>
        <p class="text-gray-700 text-base mb-4">
          {{description}}
        </p>
      </div>
    </div>
  </a>
</template>

<style scoped></style>
```
Finally, let's use all before created parts in our `app.vue` root page:

```vue
<script setup lang="ts">
 import { useStoryblokApi } from "@storyblok/vue";
  const storyblokApi = useStoryblokApi();
  const { data } = await storyblokApi.get("cdn/stories", { version: "draft", starts_with: 'modules' });
  const modules = computed(() => data.stories);
</script>

<template>
  <TheHeader />
  <div class="container mx-auto p-8 grid grid-cols-1 md:grid-cols-3 gap-4">
    <ModuleCard v-for="module in modules" v-bind="module.content" />
  </div>
</template>
```

## Vercel

The whole configuration of Vercel is well defined in the video so I will just summarize it.

Import github repository in Vercel

![Vercel Dashboard](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r0106w07jxgz548mncv4.png)

Define proper build command:

![Vercel settings](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/18k59s5f7kpsk8jes756.png)
 
Build command should be `yarn generate` and output folder `.output/public`

Finally, add Storyblok token as Environment Variable:

![Vercel Environment Variables](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xtxwyfy696kg02fepkht.png)

If all went well with the configuration, you should see similar result as our demo https://nuxt-modules-clone.vercel.app/

![Demo](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r6bllfbsa01jq55u1taz.png)
 

## Summary

Well done! You have just created a simple Nuxt Modules clone with Nuxt 3 SSG, TailwindCSS, Storyblok, and Vercel. We covered a lot in this article so take a little brake and then get back to the topic as there is much more to discover!

## Bonus

Below, I am posting some links that might be useful for you:

- https://github.com/nuxt-community/algolia-module
- https://github.com/storyblok/storyblok-nuxt-beta
- https://www.storyblok.com/tp/using-storyblok-algolia-in-nuxt-3