Going from Hugo to Nuxt

I have been using Hugo to generate my blog, but since I'm not so comfortable with Go, I wanted to try out something fresh and familiar. Between Gridsome and Nuxt, I chose Nuxt.

Hugo -> Gridsome || Nuxt

Hugo has been working well for me but I find the template language unintuitive and compared to using Vue single-file components, it's like pitch-dark night and blending sunny day. Gridsome was also on my radar but it fell short for me. Some of my reasons were:

Gridsome vs. Nuxt

  • Relative immature project: Aug. 2018 vs. Jan. 2017.
  • Low number of core contributors: 1 vs. 5. (over 100 commits total).
  • Pure popularity: 7.1k GitHub stars vs. 32.6k Github stars.
  • Opinionated GraphQL data layer. But this can be a positive for someone.

All in all, Gridsome is a young project so a lot can change in time. For now, I'm going for Nuxt.

Nuxt

Generating the Nuxt project filled my developer heart with bliss and thrill. I was intrigued by picking Programming language, Package manager, UI framework, Linting tools, Testing framework, Rendering mode, Deployment target, and Development tools. So far, so good. Try it yourself by running this yarn command yarn create nuxt-app nuxt-blog. If you want to generate a static website choose:

  • Nuxt.js modules: Content
  • Rendering mode: Universal (SSR / SSG)

When I opened the project in VSCode, it hit me, this was the right choice for my dev blog. I was sitting comfortably in front of a clean and developer-friendly directory structure. My markdown articles are stored in content/articles. The documentation of Nuxt and it's static module: Nuxt Content was easy to follow and lovely to read. They also have a nice guide for creating a blog using Nuxt content.

Listing out the articles is done in pages/index.vue and it roughly look like so:

<template>
  <div>
    <div class="posts__container">
      <div
        v-for="article of articles"
        :key="article.slug"
        class="post__container"
      >
        <NuxtLink
          class="post__link"
          :to="{ name: 'posts-slug', params: { slug: article.slug } }"
        >
          <img
            class="post__image"
            :src="article.featuredImage"
          >
          <div>
            <h3 class="post__title">
              {{ article.title }}
            </h3>
            <p>{{ article.description }}</p>
          </div>
          <span class="post__date">
            {{ article.date }}
          </span>

          <p>
            {{ article.body.children[0].children[0].value }}
          </p>
        </NuxtLink>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  async asyncData ({ $content, params }) {
    const articles = await $content('articles', params.slug)
      .only(['title', 'description', 'featuredImage', 'slug', 'author', 'date', 'body'])
      .sortBy('date', 'desc')
      .fetch()

    return {
      articles
    }
  }
}
</script>

Viewing a simple article is done in pages/posts/_slug.vue.

<template>
  <div>
    <article>
      <img
        class="image__featured"
        :src="article.featuredImage"
        :alt="article.alt"
      >
      <div class="article__container">
        <h1>{{ article.title }}</h1>
        <p class="article__date">
          {{ article.date }}
        </p>

        <nuxt-content :document="article" />
      </div>
    </article>
  </div>
</template>

<script>
export default {
  async asyncData ({ $content, params }) {
    const articles = await $content('articles').where({ slug: params.slug }).fetch()
    const article = articles[0]
    return { article }
  }
}
</script>

The road ahead

So far I have been delighted developing the blog in Nuxt. If you already have a love for Vue, there is no need to evaluate other options, Nuxt is for you. My plan is to extend the site using Vue components and write more articles. But life can be busy so we will see how it goes.

That was it so I wish you all a happy new year and don't forget to wear a mask 😷.