COVID19 Lockdown Dev Log – Day 3

What I Worked On

Using the data layer in Gatsby and creating pages.

What I Learned

Scetching out data in GraphiQL and passing it to a React component. GraphiQL is GraphQL’s integrated IDE.

I learned what ‘transform’ plugins are in Gatsby and how they are used. Combined with ‘source’ plugins, they are typically used to transform data into what you need from almost any data source.
I tried transforming Markdown to HTML with the ‘gatsby-transformer-remark’ plugin. The transformer plugin and source plugin are imported in the ‘gatsby-config.js’ file like so:

//gatsby-config.js

module.exports = {
  plugins: [
    `gatsby-transformer-remark`,
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `src`,
        path: `${__dirname}/src/`
      }
    },
  ],
}

This is one of my Markdown files. They all have the same structure, which looks like this:

---
title: "Pirates A-hoy!"
date: "2019-09-12"
---

Here we see one of our time's greatest pirates doing what he does best: entertain!

<iframe width="713" height="401" src="https://www.youtube.com/embed/ehhs2T1AQVc" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

To list them on the front page, we write the following code in ‘index.js’ :

//index.js

import React from "react"
import { Link, graphql } from "gatsby";
import Layout from '../components/layout';

export default ({ data }) => {

  return(
    <Layout>
      <div>
        <h1> Amazing Stuff And Things </h1>
          <h4>{data.allMarkdownRemark.totalCount} Posts</h4>
          {data.allMarkdownRemark.edges.map(({ node }) => (
            <div key={node.id}>
              <Link
              to={node.fields.slug}
              >
              <h3>{node.frontmatter.title}{" "}
                <span>
                - {node.frontmatter.date}
                </span>
                </h3>
                <p>{node.excerpt}</p>
              </Link>
            </div>
          ))}
      </div>
    </Layout>
  );
}

The GraphQL query in ‘index.js’ to get the data:

//index.js

export const query = graphql`
  query {
    allMarkdownRemark(sort: { fields: [frontmatter___date], order: DESC }) {
      totalCount
      edges {
        node {
          id
          frontmatter {
            date(formatString: "DD MMMM, YYYY")
            title
          }
          fields {
            slug
          }
          excerpt
        }
      }
    }
  }
`

The above 2 codeblocks result in something that looks like this:

The result of ‘index.js’

Now, each post doesn’t link to it’s own individual page yet. To do that I utilized Gatsby’s ‘onCreateNode’ and ‘createPages’ API. In short, it will allow me to create pages dynamically for each post. This means that when you click on a blogpost you are taken to its own page with all the content.

Create and configure a ‘gatsby-node.js’. You need this file if want to use/implement APIs in Gatsby:

//gatsby-node.js

const path = require(`path`);
//Gatsby's own function for creating 'slugs' from filepaths
const { createFilePath } = require(`gatsby-source-filesystem`);

//create a node and slug
exports.onCreateNode = ({ node, getNode, actions }) => {
    const { createNodeField } = actions;

    if (node.internal.type === `MarkdownRemark`) {
        const fileNode = getNode(node.parent);
        const slug = createFilePath({ node, getNode, basePath: `pages`})

        createNodeField({
            node,
            name: `slug`,
            value: slug,
        })
    }
}

//create a page
exports.createPages = async ({ graphql, actions }) => {
    // **Note:** The graphql function call returns a Promise
    const { createPage } = actions;
    const result = await graphql(`
        query {
            allMarkdownRemark {
                edges {
                    node {
                        fields {
                            slug
                        }
                    }
                }
            }
        }
    `)

    result.data.allMarkdownRemark.edges.forEach(({ node }) => {
        createPage({
            path: node.fields.slug,
            component: path.resolve(`./src/templates/blog-post.js`),
            context: {
                // Data passed to context is available
                // in page queries as GraphQL variables.
                slug: node.fields.slug,
            }
        })
    });
}

This is one, big, codefile – sorry! In short, ‘onCreateNode’ creates a file node and a slug (path to the blogpost). The ‘createPages’ creates a page for each blogpost I have (Markdown files). It tells Gatsby to use ‘/templates/blog-post.js’ as the template for a blogpost page.

Finally, let’s setup the ‘blog-post.js’ file to display the data accordingly:

//blog-post.js

import React from "react";
import { graphql } from "gatsby";
import Layout from "../components/layout";

export default ({ data }) => {
    const post = data.markdownRemark;
    return (
        <Layout>
            <div>
                <h1>{post.frontmatter.title}</h1>
                <div dangerouslySetInnerHTML={{ __html: post.html}}></div>
            </div>
        </Layout>
    )
}

The GraphQL query for the data:

//blog-post.js

export const query = graphql`
    query($slug: String!) {
        markdownRemark(fields: { slug: { eq: $slug } }) {
            html
            frontmatter {
                title
            }
        }
    }
`

Voila! Our blogpost’s page will look like this, depending on which you click on (I’m displaying “Pirates A-hoy!”:

The template setup for ‘blog-post.js’

“But André, why is this smart?”. Glad you asked. As I might have mentioned in a previous post, this isn’t limited to local Markdown files only. This could just aswell have been data that came from another API. Using source and transformer plugins, you get the data and transforms it to the format you want to work with.

Man! This is one of those days filled with a lot of new information to process. I’m beginning to like working with Gatsby alot!

I know I wanted to keep my daily blogpost ultra short, but I feel this can’t be simplified much more without losing meaning and context. Going forward I still aim to keep the blogposts ultra short 😀

What Distracted Me During The Day

  • Friend asking for creative inputs on a book he is writing.
  • LinkedIn
  • Gf dancing around to 00’s popmusic (looked funny though) 😀
  • Instagram

Resources