Dream Jamstack with Nuxt and Storyblok 🚀
Tags: jamstack, javascript, vue, webdev
Published: 2023-01-16 09:33:23

JAMstack is becoming more popular everyday, so I decided to give it a go and see if this really changes anything in terms of how modern websites are being built. I can't say that it was a game changer for me (but this is just my opinion) because I have seen several different approaches in modern development that I have found more useful like Headless, ZeroJS, Island Architecture, Server Components, and more. I might write about these concepts later if you think that they will be useful to share, let me know ;)

Let's go back to the initial topic which is finding what is in my opinion the dream stack for building Jamstack applications.

If you are interested in more visual explanation of this article, I gave a talk about this topic that you can check out below:

{% youtube u76n2JNvAfQ %}

## Jamstack

Jamstack is an architectural approach that decouples the web experience layer from data and business logic, improving flexibility, scalability, performance, and maintainability.

![Jamstack Architecture](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vwzl5gd53strvyq8nkjo.png)

You can check more about this concept here -> https://jamstack.org/

In our case, we will be using following technologies for JavaScript, API, and Markup

![Jamstack, Nuxt, Storyblok](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9lm1tkazy7rpzn6homv2.png)

## Our JAM

We will be using Nuxt 3 as our main framework, NuxtContent (to be able to write Markdown), a little bit of TailwindCSS styling, and Storyblok which will be our API. Finally, we will be deploying our app to Vercel.

You can check out all those tools and technologies below:

* https://nuxt.com/
* https://content.nuxtjs.org/
* https://tailwindcss.nuxtjs.org/
* https://www.storyblok.com
* https://vercel.com/home

## Code

Below, I have added some of the code snippets that I have found the most important for this tutorial. The full code can be seen here -> https://github.com/Baroshem/jamstack-storyblok-nuxt and also in the video linked at the top.

We will be using below Vue.js component to display an image of the cat. It will be used later for both static local data and dynamic data fetched from Storyblok:

```vue
// components/content/CatImage.vue

<template>
    <div class="flex flex-wrap w-1/3">
      <p>{{ title }}</p>
      <div class="w-full p-1 md:p-2 relative">
        <img
          class="block object-cover object-center w-full h-full rounded-lg"
          :alt="title"
          :src="src"
          >
      </div>
    </div>
  </template>
  
  <script setup lang="ts">
  const props = defineProps({
    src: {
      type: String,
      required: true,
    },
    title: {
      type: String,
      required: true,
    }
  })
  </script>
```

This component accepts two props (src and title) that are used for each individual image of the cat.
Apart from that, we have also created a gallery component that is used to display an array of cats fetched from Storyblok.

```vue
// components/content/CatImageGallery.vue

<template>
    <section class="overflow-hidden text-gray-700 ">
      <div class="container px-5 py-2 mx-auto lg:pt-12 lg:px-32">
        <div class="flex flex-wrap -m-1 md:-m-2">
          <cat-image
            v-for="image in story.content.body"
            :key="image.id"
            :title="image.title"
            :src="image.src.filename"
          />
        </div>
      </div>
    </section>
  </template>
  
  <script setup lang="ts">
const story = await useAsyncStoryblok("home", { version: "draft" });
  </script>
```

The most important file for us is the index.md file where we are creating our content that consists of normal .md content, vue.js components with local data, and an array of cat images built with the data fetched from Storyblok.

```md
// content/index.md

# Testing Nuxt Content

*Hello from Nuxt Content*

:cat-image{src=https://a.storyblok.com/f/126375/600x644/497572edee/cat-dog.jpeg title="My Favorite Cat from Markdown"}

:cat-image{src=https://a.storyblok.com/f/126375/600x644/497572edee/cat-dog.jpeg title="Second Favorite Cat"}

:cat-image-gallery
```

Thanks to this, we are now able to connect three JAM elements (JS, API, Markup) with usage of Vue.js components, .md content, and data from Storyblok.

In order to see the actual result, we need to add following component to our main app.vue page.

```vue
// app.vue
<template>
  <div>
    <ContentDoc path="/" class="prose text-left" />
  </div>
</template>
```

Also, also. Don't forget to add following configuration to nuxt.config.ts. Without it none of this will work ;)

```ts
// nuxt.config.ts

// https://v3.nuxtjs.org/api/configuration/nuxt.config
export default defineNuxtConfig({
    modules: [
        '@nuxt/content',
        '@nuxtjs/tailwindcss',
        ["@storyblok/nuxt", { accessToken: process.env.STORYBLOK_ACCESS_TOKEN }]
      ],
})
```

## Summary

Well done! By following this simple tutorial, you have managed to create a Cat Image Gallery application that is powered by static .md content, vue.js local data, and dynamic data fetched from Storyblok. Let me know if you would like me to dive deeper into JAMstack ecosystem and I will totally do it!