🥅 The Goal
I had three criteria's for my new blog :
I wanted to use DEV.to as a CMS for my blog.
I wanted my blog to be statically rendered for performance, SEO and to keep the cost of hosting free by hosting it on Netlify.
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>
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>
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 ✨
Top comments (7)
Nice post! I come to this post a few months after its publication directly from your website. I have a question about SEO and using Dev.to as CMS. Won't Google or other search engines penalize you because you are serving posts from other websites? Dev.to post are written earlier that in your website, and also I suppose Dev.to has a better SEO score (is more famous) than your website.
Hey thanks! My understanding is that because Dev.to is referencing the blog hosted on my own domain as the canonical URL it's not penalised.
Some links that might help"
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.
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! 🤯
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.
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.
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 :)
Yeah the dream would be to have Gridsome's GraphQL data layer within Nuxt!