GatsbyJS as a blog

October 04, 2019

This post was originally writen for 'docsie.io' by me, with permision from the publisher I'm posting it to my own blog.

I used to have a Jekyll blog since 2016, but recently I felt like it was no longer enough. I needed something more, something that I can customize more, and plus, I don't know much ruby to fix problems on my own and I mostly relied on Google search to fix my problems. After a quick look around, I came across GatsbyJS which, like Jekyll, is a static site generate but unlike Jekyll, it uses React and JavaScript as well as GraphQL, things that I am much more comfortable with. So I decided I need to move my blog over, but how?

Blog posts and the magic of markdown

In Jekyll, we use markdown file formats to write the posts. Each file consists of a section called Frontmatter and then the rest is usual markdown. Frontmatter is like a dictionary, there are keys and values, a key for a date with a DateTime value, a key for the title with a string value plus whatever you decide to add. My Jekyll blog, like many others, consists of these two values with a category add on. The file names are special there as well, there is a date, an underscore and finally the path for this post.

Lucky for me this is similar to Gatsby, there are a few plugins to help with creating this blog, one being the gatsby-source-filesystem and the other gatsby-transformer-remark. I used these two to find my files and convert them to the blog post that I need.

Setting up GatsbyJS

First things first, create your GatsbyJS site. Install Gatsby and create your site (or use an existing one!)

npm i -g gatsby-cli
gatsby new blog https://github.com/gatsbyjs/gatsby-starter-hello-world
cd blog

This creates a bare gatsby site in blog directory. Next, we need to install the plugins I mentioned.

npm install --save  gatsby-transformer-remark gatsby-source-filesystem

Preparing the blog posts

The default gatsby setting requires a markdown file with a file name similar to hello_world.md and a content like this:

---
title: Hello World
date: 2019-09-10 9:15:12 -05:00
path: hello_world
---
Hello, world!

Note that the file name and the path values don't have to be similar, but I prefer them to be so that I can find them later easier.

As you can see, there is no path in my Jekyll posts, so I had to take care of that. If this is a new blog, just make a few posts ready, even the previous one works fine!

Place them in content/blog folder.

Finding the files

Okay now that the files are ready, we need to show Gatsby where they are. Gatsby has different kinds of plugins, one of them are the source plugins. They'll get your data from anywhere else (a web service? your file system? contentful? another GraphQL server?) and give them raw to the Gatsby system. Open (or create) gatsby-config.js in the root of your project, and fill it like this:

module.exports = {
  plugins: [
    {
      resolve: 'gatsby-source-filesystem',
      options: {
        name: 'blog',
        path: `${__dirname}/content/blog`
      },
    },
    'gatsby-transforer-remark',
  ],
};

Transforming the files

Now that gatsby has found our files, we need to tell it to convert them to blog posts.

Creating a template

First, we need to describe to it what a blog post looks like, open up src/templates/blog.js and fill it like the following:

import React from "react";
import { graphql } from "gatsby";

export default function Template({ data }) {
  const { markdownRemark } = data;
  const { frontmatter, html } = markdownRemark;
  return (
    <div>
      <h1>{frontmatter.title}</h1>
      <h2>{frontmatter.date}</h2>
      <div
        dangerouslySetInnerHTML={{ __html: html }}
      />
    </div>
  );
}

export const pageQuery = graphql`
  query($file: String!){
    markdownRemark(frontmatter: {path: {eq: $file}}){
      html
      frontmatter {
        date(formatString: "MMMM DD, YYYY")
        path
        title
      }
    }
  }
`;

A lot is going on here. Notice that there are two exports, a default export, and a pageQuery. In gatsby a pageQuery describes what GraphQL query to run in order to get the necessary information from Gatsby. We are making a query that has a mandatory file variable (we'll get to this later). Then we look at markdownRemark with a query that asks for the file whose frontmatter has a path equal to that file variable. So now that we have our file, we can ask for different information. We ask for the parsed HTML as well as the date, path, and title of the post. Notice that we ask the date to be in a format that we want.

Next, in the default export, we are exporting a react component. Notice how inside it is given a data as part of its attributes. This data is the result of the pageQuery we did earlier. The next is straight forward, we don't do much here, just a plain blog post. You can customize it further if you want.

Creating blog posts

Now that we have a template, and we have the source data in our system, all is left is to convert the source file to the template. Open up gatsby-node.js and fill it like this file:

const path = require('path');

exports.createPage = async ({actions, graphql})=>{
  const { createPage } = actions;

  let results = await graphql(`
    {
      allMarkdownRemark(filter: {fileAbsolutePath: {regex: "/blog/"}}){
        edges {
          node{
            frontmatter{
              path
            }
          }
        }
      }
    }
  `);
  if(result.errors){
    console.error(result.errors);
  }

  result.data.allMarkdownRemark.edges.forEach(({node})=>{
    createPage({
      path: "/blog/" + node.frontmatter.path,
      component: path.resolve(`src/templates/post.js`),
      context:{
        file: node.frontmatter.path,
      },
    });
  });
}

This file has special properties. Whatever is exported as createPage has the ability to create pages. So we first ask the markdown remark to query any file that has /blog/ in its path and then ask for their paths using GraphQL. Then we pass each of the files (or nodes) to the createPage function.

Create page function takes a path, a react component and a dictionary as context. Remember that file variable in our query earlier? Here we pass it under the context dictionary.

Now our posts are ready, start up gatsby gatsby develop and head over to http://localhost:8000/blog, you'll get a 404 error, but below there are every file registered in your system. In the next post, we can look at methods to list these blog posts and to style our site better.