Gridsome: Let’s Build Something!

06-10-20 Paul Butler III

Gridsome is a powerful Vue.js framework. Follow along with Paul as he teaches you how to build a blog in Gridsome, showing you the framework’s benefits along the way.

Gridsome is a Vue.js framework built for JAMstack apps. Whether it’s Serverless, markdown, or a headless CMS, Gridsome has you covered! And as Gridsome says it, “Gridsome makes it easy for developers to build modern websites, apps & PWAs that are fast by default.”

It should also be said that Gridsome is “highly inspired by Gatsby.js (React based) but built on top of Vue.js.”

With that out of the way, let’s jump in and build! For this article, we will set up a Gridsome blog utilizing Markdown as our source of data.

Setup (Installing Gridsome)

You can skip installing the Gridsome CLI if you are using npx.

Install the Gridsome CLI tool

  • Using YARN: yarn global add @gridsome/cli
  • Using NPM: npm install --global @gridsome/cli

Creating our Blog!

With the CLI installed, let’s open a terminal and run the following commands.

  • gridsome create my-blog to create a new project
  • cd my-blog to open folder
  • gridsome develop to start local dev server at http://localhost:8080

Gridsome Default Page

Setting up Gridsome to Look for Our Markdown

In gridsome.config.js, we will utilize the Gridsome plugins @gridsome/source-filesystem and @gridsome/transformer-remark to let Gridsome understand our content that in turn can be pulled in with GraphQL. Restart your server after making changes to your config.

Install:

  • npm install @gridsome/source-filesystem
  • npm install @gridsome/transformer-remark
module.exports = {
  siteName: 'Gridsome Blog!',
  siteDescription: 'Whoaaa what a blog you\'ve got here',
  templates: {
    Resource: '/blog/:slug',
  },
  plugins: [
    {
      use: '@gridsome/source-filesystem',
      options: {
        path: 'content/articles/**/*.md',
        typeName: 'Resource',
      }
    }
  ],
}

Next we’ll update the layouts/Default.vue

This is a generated, base layout, created by Gridsome and used as a wrapper for pages and templates to be inserted. In this file, we will replace the default contents with the template below. For more information, check out the Layout Docs.

<template>
  <div class="layout">
    <slot/> <!-- this slot is where pages && templates end up -->
    <div class="footer"></div>
  </div>
</template>

Moving on to Pages/index.vue (Homepage)

Here we will set up the homepage for our blog. We will display a list of our articles by utilizing a <page-query> to query all of our content (articles) from our allResource schema. For now, we will demonstrate that our page context is working properly by outputting the siteName and siteDescription onto our page. Further examination can be done by utilizing the Vue.js devtools to inspect different components of our blog.

Notes:

  • When utilizing GraphQL queries, <page-query>is for pages/templates and <static-query>is for components.
  • To set the title for a page, you can utilize the metaInfo.title property shown below. It is also possible to set these globally from your gridsome-config.js.
<template>
  <Layout>
    <header class="header">
      <h1 v-html="$page.metadata.siteName" />
      <h2 v-html="$page.metadata.siteDescription" />
    </header>
  </Layout>
</template>

<page-query>
query {
  metadata {
    siteName
    siteDescription
  }
  allResource {
    edges {
      node {
        id
        title
        description
        date (format: "D MMMM YYYY")
        path
      }
    }
  }
}
</page-query>

<script>
export default {
  metaInfo: {
    title: "The Most Awesome Blog You Have Never Heard Of!"
  }
};
</script>

<style>
body {
  font-family:-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
}

a {
  color: purple;
}

.header {
  background-color: black;
  color: white;
  font-size: 2rem;
  text-align: center;
  line-height: 1.5rem;
  padding: 1rem;
}

.header h2 {
  font-family: inherit;
  font-size: 1.5rem;
  font-weight: normal;
}
</style>

New homepage for our blog

Creating our ResourceList Component (Styles Optional)

Like most blogs, we’re gonna show a list of our articles on the homepage. For this we will create a ResourceList component at components/ResourceList.vue. This component is quite simple in that we are simply receiving the resources props as defined in the parent (index.vue) and displaying them on the screen.

<template>
  <div class="resource-list">
    <h3 v-html="resource.title" />
    <ul class="resource-list__details">
      <li v-html="resource.date" />
    </ul>
    <p class="resource-list__description" v-html="resource.description" />
    <g-link :to="resource.path" class="resource-list__full-article">Full Article &rarr;</g-link>
  </div>
</template>

<script>
export default {
  name: 'ResourceList',
  props: ["resource"],
};
</script>

<style scoped>
.resource-list {
  padding: 1rem;
}

.resource-list__description {
  padding: 1rem 0;
}

.resource-list__full-article {
  background-color: black;
  color: white;
  padding: 1rem;
  text-decoration: none;
}

ul {
  display: flex;
  list-style: none;
  padding: 0;
}

li:first-of-type {
  padding-right: 1rem;
}
</style>

Adding the ResourceList Component to Our Page

With our new component completed, we can go ahead and plug it into the index.vue by updating our template markup and then our script section. These updates will not create any visual changes for us quite yet as we have one more step we must complete in order for this to happen.

<template>
  <Layout>
    <header class="header">
      <h1 v-html="$page.metadata.siteName" />
      <h2 v-html="$page.metadata.siteDescription" />
    </header>
    <section class="resources">
      <ResourceList 
        v-for="edge in $page.allResource.edges"
        :resource="edge.node" 
        :key="edge.node.id"
      />
    </section>
  </Layout>
</template>
<script>
import ResourceList from "@/components/ResourceList";
export default {
  components: {
    ResourceList
  },
  metaInfo: {
    title: "The Most Awesome Blog You Have Never Heard Of!"
  },
};
</script>

Lest We Forget our New Template

The last piece we are going to add is our template. As stated above, we need to create a template with the same name as we define in our config. Go ahead and create templates/Resource.vue. This will enable us to render full articles at our specified path, mine being /blog/:slug. Notice here that unlike our index.vue query, we are simply calling out an individual resource based on its id.

<template>
  <div class="resource-template">
    <router-link to="/">Home</router-link>
    <h1 v-html="$page.resource.title" />
    <p v-html="$page.resource.date" />
    <div v-html="$page.resource.content" />
  </div>
</template>

<page-query>
query ($id: ID!) {
  resource(id: $id) {
    title
    content
    date (format: "D MMMM YYYY")
  }
}
</page-query>

<style>
.resource-template {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
}
</style>

Finally We Can Write and Display Articles!

Let’s create a sample article to prove that this thing actually works. At the root of your project, create a directory structure for your articles. Mine is content/articles. Note that by “root” I mean outside of the src directory. Here we will create our first article. We’ll call it article_1.md. If you are familiar with other static site generators, like Jekyll, you may be thinking that the name of the article should be formatted differently, possibly postfixed with a date. But for us, we told the @gridsome/source-filesystem plugin to look for any markdown files in content/articles/, and our urls are created with/blog/:slug.

In our document, we will set the yaml properties for querying in our pages/templates/components. It is possible for us to define any number of properties here and query them later on. If you add or remove properties, be sure to restart your server after and make sure any existing queries you may have are either looking for the new properties or no longer looking for old properties.

---
title: "Our First Article"
description: "Odio ut sem nulla pharetra. Ornare aenean euismod elementum nisi quis eleifend quam adipiscing."
date: 2019-05-23
slug: our-first-article
---

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Justo eget magna fermentum iaculis eu non diam phasellus. Odio ut sem nulla pharetra. Ornare aenean euismod elementum nisi quis eleifend quam adipiscing. Felis eget velit aliquet sagittis. Est velit egestas dui id ornare arcu odio ut sem. Lectus proin nibh nisl condimentum. Sagittis nisl rhoncus mattis rhoncus urna neque. Tincidunt tortor aliquam nulla facilisi. Sed nisi lacus sed viverra. Sed augue lacus viverra vitae congue eu. In nibh mauris cursus mattis molestie a iaculis. Feugiat vivamus at augue eget.

Blog home page with resourceList

Clicking on the Full Article link will take you to the article page!

Blog article page

If you have made it this far, congratulations! You should now be able to display your blog’s content, create new content, and see the power of Gridsome.

Gridsome is still young, with its initial commit coming on July 31, 2018. As a Vue lover, I see a lot of benefits in the project and hope it grows similarly to the way Gatsby has grown. With its growing plugin system, flexibility, and easy deployment options like Netlify, you are able to implement the power of the JAMstack, a headless CMS, or a SPA in such a short period of time that you’ll be wondering why everyone else isn’t already doing it.