Guide to setting up a markdown blog with Gridsome

Table of contents

This website (webdevetc.com) is currently running on Gridsome.

Gridsome is a vue based static site generator. I quite like it, but it is a pain to get set up I think.

Here are the step by step instructions to configuring your Gridsome app to add a blog which uses markdown files.

Installing Gridsome

Installing Gridsome is easy:

yarn global add @gridsome/cli;
gridsome create your-blog-name;
cd your-blog-name;
gridsome develop;

Then you should be able to visit http://localhost:8080

Install some gridsome packages to support markdown

yarn add @gridsome/source-filesystem;
yarn add @gridsome/transformer-remark;

Adding blog markdown content for Gridsome

First lets add some blog content. Create a file called blog/2020-10-24-hello-world.md and paste in the following content:

note: this should be in ./blog, not in ./src/blog

---
title: "A hello world example in Gridsome"
path: /gridsome-markdown-blog
date: 2020-10-24
summary: "Read my guide to setting up Gridsome"
tags: [ 'Blog' ]
---

## Hello world!

This is where your content goes

You can add **markdown** here

Now set up the gridsome configuration

You will need to edit gridsome.config.js to tell Gridsome about the blog directory

module.exports = {
  siteName: 'Your site name',
  siteDescription: 'Write a description here',
  siteUrl: 'https://webdevetc.com',
  plugins: [
    {
      use: '@gridsome/source-filesystem',
      options: {
        path: 'blog/**/*.md',
        typeName: 'Post',
        refs: {
          tags: {
            typeName: 'Tag',
            create: true
          },
        }
      }
    },
  ],
  templates: {
    Tag: '/tag/:id',
    Post: '/blog/:path',
  },
  transformers: {
    remark: {
      autolinkClassName: 'icon icon-link heading-anchor',
      externalLinksTarget: '_blank',
      externalLinksRel: ['noopener', ],
      anchorClassName: 'icon icon-link',
    }
  },
}

Add the Vue component files for the blog section

There are a couple of Vue files we must add now - one for the index page (to show all posts) and one for viewing a single post.

We also want to support tags, so they need their own index page and page to view their own tag.

The blog post index page

In src/pages/Blog.vue add the following:

<template>
  <div>
    <article v-for="post in $page.posts.edges" :key="post.id" >
      <h2><g-link :to="post.node.path" rel="bookmark">{{ post.node.title }}</g-link></h2>
      <p>Posted on <time :datetime="post.node.date">{{ post.node.date }}</time></p>

      <p>{{ post.node.summary }}</p>
    </article>

    <h2>Pagination</h2>
    <Pager :info="$page.posts.pageInfo"/>
  </div>
</template>

<page-query>
query Posts ($page: Int) {
  posts: allPost (sortBy: "date", order: DESC, perPage: 10, page: $page) @paginate {
    totalCount
    pageInfo {
      totalPages
      currentPage
    }
    edges {
      node {
        id
        title
        date (format: "MMMM D, Y")
        summary
        path
      }
    }
  }
}
</page-query>

<script>
import { Pager } from 'gridsome'

export default {
  components: {
    Pager
  },
  metaInfo: {
    title: 'View my blog posts'
  },
}
</script>

Blog single post page

In src/templates/Post.vue add the following content:

<template>
    <article>
      <h1>{{ $page.post.title }} </h1>

      <div>
        Tags:
        <g-link
            v-for="tag in $page.post.tags"
            :to="tag.path"
            :key="tag.id">
          #{{ tag.title }}
        </g-link>
      </div>

      <p>Posted on {{ $page.post.date }}</p>

      <div class="markdown-body mb-8" id="article-area" v-html="$page.post.content" />
    </article>
</template>

<page-query>
query Post ($path: String!) {
  post: post (path: $path) {
    title
    date (format: "MMMM D, Y")
    content
    tags {
      title
      path
    }
  }
}
</page-query>

<script>
  export default {
  metaInfo() {
    return {
      title: this.$page.post.title
    }
  }
}
</script>

Setting up a Gridsome Tag/category page

In src/templates/Tag.vue add the following:

<template>
    <article>
      <h1>Posts tagged {{ $page.tag.title }}</h1>

      <ul>
        <li v-for="post in $page.tag.belongsTo.edges" :key="post.node.id" >
          <h3><g-link :to="post.node.path">{{ post.node.title }}</g-link></h3>
          {{ post.node.date }}
        </li>
      </ul>
    </article>
</template>

<page-query>
query Tag ($id: ID!, $page: Int) {
  tag: tag (id: $id) {
    title
    belongsTo (page: $page, perPage: 30) @paginate {
      totalCount
      pageInfo {
        totalPages
        currentPage
      }
      edges {
        node {
          ...on Post {
            title
            path
            summary
            tags {
              title
            }
          }
        }
      }
    }
  }
}
</page-query>

<script>
export default {
  metaInfo() {
    return {
      title: `Tag: ${this.$page.tag.title}`
    }
  },
}
</script>

Restart Gridsome and you are ready to go!

Restart Gridsome (or just run gridsome develop), let it rebuild from the blog files and if you visit localhost:8080/blog you should see your post!

View repo with working example of a blog in Gridsome

See my Github repo with an example Gridsome installation using markdown files as blog content

You will need to add styling and play with things a bit, but this tutorial on setting up a blog in Gridsome with markdown (with tag support) should help out.

Comments Guide to setting up a markdown blog with Gridsome