DEV Community

loading...
Cover image for Building My New Blog | Nuxt Vs Gridsome

Building My New Blog | Nuxt Vs Gridsome

chiubaca profile image Alex Chiu Originally published at chiubaca.com ・5 min read

🥅 The Goal

I had three criteria's for my new blog :

  1. I wanted to use DEV.to as a CMS for my blog.

  2. I wanted my blog to be statically rendered for performance, SEO and to keep the cost of hosting free by hosting it on Netlify.

  3. I had legacy blogs in markdown files which I wanted to host along with the rest of the blog.

To achieve this, I experimented with both Nuxt and Gridsome. This is my experience with both frameworks.

🎬 Take 1 - Nuxt

First, addressing my old markdown blogs. Nuxt recently released the content module which was perfect for rendering my old markdown files into individual pages.

To build the rest of the blog, Nuxt has a new Full Static mode which was released in version 2.14.0.

This mode used in conjunction with Nuxt's asyncData hook means it is possible to fetch all DEV.to blogs post via the DEV.to API at build time. When we run npm run generate to build the blog, Nuxt auto-magically pre-renders each page of your Nuxt site into static HTML pages.

How this works at high level. In my .src/pages/index.vue file, the home page of the blog, I fetch a list of all published posts from the DEV.to API using the /articles/me endpoint. This data fetching is done within the asyncData hook and this endpoint returns an array of your published posts. With the data retrieved, I list each of the posts, and link to a new page by making use of the <nuxt-link> router component. I re-use the DEV.to post slug for the sub-paths of each of the blogs, like so:

<div v-for="(post, index) in posts" :key="index">
    <nuxt-link :to="`/${post.slug}`">{{ post.title}}</nuxt-link>
</div>
Enter fullscreen mode Exit fullscreen mode

Nuxt handles routing based on the file structure of your pages directory, so by creating a _slug.vue file relative to where the index.vue file is. Nuxt knows that this will be the template for any sub paths off that page.

Within _slug.vue, we make use of asyncData lifecycle hook again to make another call to the DEV.to API, which will retrieve the specific blog based on the slug using the /articles/{username}/{slug} endpoint. This returns an object of the specific post and one of the properties is body_markdown. This is the raw markdown of your Dev.to post. Converting this to HTML and making it look nice is another challenge within itself, but once done you can render this directly in the Vue template using Vue's v-html directive. You can see how I did it here (warning very messy code!!).

What's key here is that when building this application in static mode, Nuxt will perform all the actions in the asyncData hook at build time!

Although I was happy with the end result. I realised there is a lot of logic in the asyncData lifecycle hook. Data fetching, markdown parsing and potentially extra data cleaning logic which I would need to implement later. I also had plans to extend the data fetching to alternative sources such as other Forem sites, Medium and GitHub. I felt like this could get pretty unwieldy if I didn't adopt a nice pattern. This is what lead me to Gridsome.

🎬 Take 2 - Gridsome

The main selling point of Gridsome is the GraphQL data layer. Gridsome provides a simple API to import data from any external source into a data layer. This normalises all your content into a user-friendly GraphQL API.

Also, Gridsome has a growing number of source plug-ins which are helpers to pull data from an external source and import it into the GraphQL data layer.

To read in my old markdown blogs I was able to make use of the filesystem source plug-in. This allows me to create pages for each of my old markdown blog with minimal effort.

Next was to connect Gridsome to DEV.to. There were already plug-ins for this but I decided to hand roll my own as a learning exercise 🤓.

I was able to copy most of my data fetching logic from the Nuxt version of my blog, but I had to write some additional code to import the DEV.to posts into GraphQL using Gridsome's Data Store API. You can see how I did this here.

Once all my DEV.to blogs are loaded in the data layer we can work with this data in any .vue file in the Gridsome project via the <page-query> or <static-query> blocks. Within this block, you can write a GraphQL query and the result is exposed in your <template> via the $page object. The Gridsome docs explain this a lot better!

Similar to Nuxt, Gridsome also has a ./src/pages/ directory and also it's own router component, g-link. This is how you list the titles of all your DEV.to posts and link to them:

<template>
    <div v-for="blog in $page.articles.edges":key="blog.node.id">
     <g-link :to="blog.node.slug">{{ blog.node.title }}</g-link>
    </div>
</template>

<page-query>
  query {
    articles: allDevToArticles{
      edges {
        node{
          title
          slug
        }
      }
    }
  }
</page-query>
Enter fullscreen mode Exit fullscreen mode

Whereas Nuxt crawls your entire application to figure which pages it needs to generate. Gridsome is smart enough to generate a page for each node in for all your GraphQL collections*.

*The aggregation of all Dev.to blogs in the Gridsome data layer, is referred to as a "collection" each blog is referred to as a "node".

To work with these pages we create a .vue file in the ./templates directory in the Gridsome project. This is the equivalent of the _slug.vue file in the Nuxt version of the blog.

The name of this template file should be the same as the collection name. Though this can be configured to your liking in gridsome.config.js.

With that setup, I now had parity between both Nuxt and Gridsome implementations of my blog.


Closing Thoughts

Why I Chose Gridsome Over Nuxt

Overall I felt like the architecture for Gridsome was much better suited for my blog. I liked that there is a separation of concerns with data fetching. All of this logic was contained in my Dev.to source plug-in. This meant I only needed to focus on the organisation of pages and design in the Gridsome codebase.

Nuxt Is Still Great

  • I think Nuxt is perfect for more complex Vue applications.
  • There was nothing wrong with having too much logic in the asyncData hook. This was just a personal opinion.
  • If you are only working with markdown files for your blog, the content module is perfect!

Cons of Gridsome

  • It's still not at a 1.0 release.
  • Development doesn't seem to be as active as Nuxt.
  • Developer experience improvements on the <page-query> and <static-query> blocks. Is it possible to have GraphQL autocompletion somehow?
  • More documentation for plug-ins. Creating a source plug-in was a good experience, but I had difficulty understanding how to use transformer plug-ins

This was a quick comparison between two great Vue.js meta frameworks. Are you planning to work with Nuxt or Gridsome any time soon? Let me know.

If you're reading this on DEV.to, you check out my new blog site here 👇

chiubaca.com

Discussion (5)

pic
Editor guide
Collapse
brpaz profile image
Bruno Paz

I did the opposite with my personal website, from Gridsome to Nuxt. ;)
I think where Gridsome really shines is when you need to fetch data from multiple data sources and have an uniform layer over that data.

For my site, I only needed Markdown and some static YAML files and the release of Nuxt Content Module made me switch. I found the data layer of Gridsome a bit overkill for my use case. and like you said, I feel that Gridsome development has slowed down and I am bit unsure about it´s future. Nuxt is a lot more mature and with a bigger community.

I hope it can regain some traction as I think it´s a cool project and there is space for both.

Just an observation about your example of fetching posts from dev.to API in async data. I am still a novice with Nuxt, but since you were rendering a static site, I guess it would be possible to, fetch the posts at build time in a module/plugin and then transforming the results into a format supported by Nuxt Content, for example. Of course if you plan to have other sources in the future, like you said, then yes I think it fits perfectly with Gridsome.

Collapse
chiubaca profile image
Alex Chiu Author

I guess it would be possible to, fetch the posts at build time in a module/plugin and then transforming the results into a format supported by Nuxt Content

I... didn't know this was possible! Will need to research into this a bit more.

A small part of me wants the two projects to be merged together. Imagine having a GraphQL data layer in Nuxt! 🤯

Collapse
brpaz profile image
Bruno Paz • Edited

I... didn't know this was possible! Will need to research into this a bit more.

Never tried anything similar myself, but Nuxt has Hooks that allows to run code at specific points of Nuxt Lifecycle including build. This is how for example nuxt sitemap plugin works to generate a sitemap at build time. So in theory, it should be possible.

A small part of me wants the two projects to be merged together. Imagine having a GraphQL data layer in Nuxt

Yes. I think it would be a cool add-on on top of Next. It could work similarly to Nuxt Content but with a GraphQL API.

Collapse
lansolo99 profile image
Stéphane CHANGARNIER

Interesting point of view. I used both a lot for small projects. I finally decided to stick to Nuxt, because of a bigger community, and an extensive set of official modules. It’s also more versatile as it support SSR.

The @Nuxt/Content module fill the void that existed before, regarding managing local data. Nevertheless, I still think Gridsome is a very good solution for static sites, and it’s true the built-in graphQL layer is a thing.

Apart from this, I think Gridsome outperform Nuxt regarding the build time, and also the component : the perfect solution to manage responsive + progressive images. Nuxt team is developing a similar feature with the @nuxt/image module, but still not production-ready.

Maybe both teams should merge to union their efforts :)

Collapse
chiubaca profile image
Alex Chiu Author

Yeah the dream would be to have Gridsome's GraphQL data layer within Nuxt!