Powering up static sites with Gridsome taxonomies
Tags: vue, gridsome, graphql, jamstack
Published: 2019-09-10 08:15:15

---
title: Powering up static sites with Gridsome taxonomies
published: true
tags: vue, gridsome, graphql, jamstack
canonical_url: https://www.codegram.com/blog/powering-up-static-sites-with-gridsome-taxonomies
cover_image: https://thepracticaldev.s3.amazonaws.com/i/p9x7f21wxaga71co22wt.jpg
---


_Originally published at [Codegram's blog](https://www.codegram.com/blog/powering-up-static-sites-with-gridsome-taxonomies)_

At Codegram we are already pretty sold on [the JAMStack](https://www.codegram.com/blog/a-jamstack-journey-headless-content-management-with-vue-react), especially using Gridsome, a Vue.js framework (for React devs, it would equivalent to Gatsby). Despite being just version `v0.6.9` at the time I'm writing this, it's pretty much production-ready (unless you need [i18n](https://github.com/gridsome/gridsome/issues/23)), and offers a **great developer experience**. We've built a few sites with it, most notably [Full Stack Fest's](https://2019.fullstackfest.com) and the very own where you are reading this.

Where Gridsome shines the most versus, let's say, a simple statically generated Nuxt site, is the ability to add a **GraphQL data layer** with just a few lines of code and 0 experience creating APIs. The first and most obvious need our website had that could be solved with this was the blog. So let's see how to create a blog with Gridsome!

First, we will need to install a couple of plugins: [@gridsome/source-filesystem](https://gridsome.org/plugins/@gridsome/source-filesystem) and [@gridsome/transformer-remark](https://gridsome.org/plugins/@gridsome/transformer-remark). This will allow us to read markdown files and turn those into a GraphQL collection.

So, in `gridsome.config.js` file, we add the configuration for the plugin:

```js
module.exports = {
  plugins: [
    {
      use: '@gridsome/source-filesystem',
      options: {
        path: 'src/blog/*.md',
        typeName: 'BlogPost',
        route: '/blog/:slug'
      }
    }
  ],
  transformers: {
    remark: {
      // we can add options here
    }
  }
}
```

Then, we create a `blog.vue` file inside `src/pages`, and we can query our blogposts. It's that easy!

```html
<template>
  <Layout>
    <BlogPost
      v-for="post in $page.blogPosts.edges"
      :key="post.node.id"
      :post="post"
    />
  </Layout>
</template>

<static-query>
  query BlogPost {
    blogPosts: allBlogPost(sortBy: "published_at", order: DESC) {
      edges {
        node {
          title
          path
          image(width:640, quality: 75)
        }
      }
    }
  }
</static-query>
```

With the power of GraphQL, we only need to query the fields we need. Since it's the main blog page, we don't care about the content, so we only request `title`, `path`, and `image` (which we can even request in specific size and quality! 🤯).

What about each post page? With plain Vue or Nuxt we would need to create a route that with an `id` param, then get that param from the `$route` object, then query the post, set the data we get to the component state, probably adding a loading spinner while doing all that…

![](https://media.giphy.com/media/njAjh98E1PUha/source.gif)

With Gridsome is much easier! We only need to create a `BlogPost.vue` in the `templates` folder (remember that `BlogPost` is the `typeName` we used when configuring our app), and write the query:

```html
<template>
  <section>
    <h1>{{ $page.blogPost.title }}</h1>
    <!-- ... -->
  </section>
</template>

<page-query>
  query BlogPost ($path: String!) {
    blogPost: blogPost (path: $path) {
      title
      published_at
      author
      image(width:1024, quality: 75)
      content
    }
  }
</page-query>
```

As you see, the query gets a `$path` variable, that we pass along. But all that is done for you, no need to get the `$route.params.id` or anything!

That's only the beginning of what you can do with Gridsome, though. What good is a blog without tags, you might ask? Let's add them!

We need another GraphQL collection, but we don't want to have to create a file for each tag, right? Luckily there's an easy way! In `gridsome.config.js` we can add a reference to another `typeName`. The `create` option will create the collection without files:

```js
    {
      use: '@gridsome/source-filesystem',
      options: {
        path: 'src/blog/*.md',
        typeName: 'BlogPost',
        route: '/blog/:slug',
        refs: {
          typeName: 'Tag',
          route: '/blog/tag/:slug',
          create: true
        }
      }
    }
```

Now we can query the tags the same way to create our tag list:

```html
<page-query>
  query Tags {
    tags: allTag {
      edges {
        node {
          id
          path
        }
      }
    }
  }
</page-query>
```

But we will need to create a view for each tag, that lists the posts that have that tag, right? We create another template `Tag.vue`, and we can get the posts that the tag belongs to!

```html
<page-query>
  query Tag($id: String!) {
    tag(id: $id) {
      id
      belongsTo(sortBy: "published_at", order: DESC) {
        edges {
          node {
            ... on BlogPost {
              title
              path
              image(width:640, quality: 75)
            }
          }
        }
      }
    }
  }
</page-query>
```

_That `... on BlogPost` bit might look a bit weird if you are not familiar with GraphQL, it's called an [inline fragment](https://graphql.org/learn/queries/#inline-fragments)._

Isn't it great to be able to create relationships that easily? Without a backend! To access the posts easily, I like to create computed properties so the code is more readable:

```js
  computed: {
    posts() {
      return this.$page.tag.belongsTo.edges
    }
  }
```

This might not feel as much, but this truly brings a static site to the next level. We can create complex relationships between all the pieces that form our website. For example, we added related posts to some of our [services](https://www.codegram.com/services/). How? Adding tags as well!

```js
    // gridsome.config.js
    {
      use: '@gridsome/source-filesystem',
      options: {
        path: 'src/services/*.json',
        route: '/services/:id',
        typeName: 'Service',
        refs: {
          tags: {
            typeName: 'Tag',
            route: '/blog/tag/:slug'
          }
        }
      }
    },
```

Since we already created the tags for our blog posts, there is no need to add the `create: true` again, it will match against current existing tags.

On our services query, we add the tags and their posts:

```html
<page-query>
  query Service($path: String!) {
    service(path: $path) {
      title
      description
      tags {
        id
        belongsTo(
          sortBy: "published_at",
          order: DESC,
          limit: 3,
          filter: {
            typeName: { eq: BlogPost }
          }) {
          edges {
            node {
              ... on BlogPost {
                title
                path
                image(width: 640, quality: 75)
              }
            }
          }
        }
      }
    }
  }
</page-query>
```

_Note that since now tags have references to both BlogPosts and Services, we need to filter by `typeName` so we only get posts._

That easily, every time we add a post about Vue, it will show up on the Vue service page. And it works the other way around too! We can query related services from the post page, as you can see at the end of this post. And we did the same with case studies! If you read a post about [Decidim](https://www.codegram.com/blog/decidim-open-source-participatory-democracy-framework), you will see a link to the case study. Post tags enabled us to display relationships throughout the site.


![](https://media.giphy.com/media/XkDyB1jCZMxUs/source.gif)

<p class="text-centered text-italic">
  <small>Imagine the possibilities</small>
</p>


As we've seen, the JAMStack is not limited to simple sites with a few pages, or blogs at the most. We can create complex relationships and filters very easily, so we can sort our products in multiple ways (categories, families, tags, etc), add related products, link them to a different content type… you name it! In this post, we've been working with a file loader but Gridsome supports multiple sources: you can use popular headless CMS like [Contentful](https://gridsome.org/plugins/@gridsome/source-contentful) or [Netlify CMS](https://gridsome.org/plugins/gridsome-plugin-netlify-cms), [Wordpress](https://gridsome.org/plugins/@gridsome/source-wordpress), or even plugging it directly to a [MySQL database](https://gridsome.org/plugins/gridsome-source-mysql). So even if your site has _a lot_ of content, it's easily manageable with JAMStack too.

Apparently, you can even use the [Star Wars API](https://gridsome.org/plugins/gridsome-source-starwars) as a source. So try Gridsome today, _it **is** the framework you are looking for._

![](https://media.giphy.com/media/fZyssFynWmQSc/source.gif)