Gatsby Blog + Netlify CMS Tutorial — Part 1

This will be a multipart series tutorial, to create a custom blog platform from scratch, with Gatsby and Netlify CMS without the headache I had to go through during the learning curve!

Application Features

This tutorial will not be a guide about React, nor an in-depth guide of Gatsby, though it will cover the essentials you need to know about Gatsby, to get you well on your way to Netlify your Gatsby app!

Gatslify!

Prerequisites — For this part of the Tutorial

What we will do

Tutorial Preparation

I will provide branches at each part of the tutorial with a start state, and an end state to help you follow along with the tutorial in case you ever get lost, while we

Though feel free to start completely from scratch if you prefer and just follow along if you prefer!

Right! Click HERE to get the first branch required for this tutorial.

This is just a standard default template provided from Gatsby, using the Gatsby-CLI, running the gatsby new CLI command, we won’t be using any of the premade blog templates.

Let's Get Started!

With the above project downloaded/cloned, navigate to the root of the project folder and do the following:

  • Run yarn to install all the dependencies
  • Run yarn develop to start up the project
  • Open http://localhost:8000 in the browser, and you should see the following.
The lovely default Gatsby Application — What is that image o.O

Creating A New Page

Gatsby handles page routing for us, based on the folder hierarchy in the pages folder lets set up a new page to get a feel for this.

Inside the pages folder do the following:

  • Create a new js file called blog-view.js
  • Paste the following code
import React from "react";
import Layout from "../components/layout";
import SEO from "../components/seo";
const BlogView = () => {
return (
<Layout>
< ="sample" />
This is a new page!
</Layout>
)
}
export default BlogView;
Our first page! Are you not proud ^_^

Note

As mentioned above Gatsby will base the application routes on the folder hierarchy within the pages folder nested routes are also supported

  • If we created a file in /src/pages/hello/world.js
  • The route to this page would be http://localhost:8000/hello/world

Let's Get Rid Of Those Nasty Import Paths

I hate relative imports, they can get messy when nested, and cause refactoring to be an issue. Luckily Gatsby does give us the ability to easily configure it’s webpack config, let's do this now!

  • Navigate to gatsby-node.js
  • This folder is currently empty, let add our first modification
  • Paste the following
.onCreateWebpackConfig = ({  }) => {
actions.setWebpackConfig({
resolve: {
modules: [path.resolve(__dirname, "src"), "node_modules"]
}
})
}

Restart the development server.
Now we can modify our imports instead of using this:

import Layout from "../components/layout";
import SEO from "../components/seo";

Imports will be resolved based on the src folder so we can now do

import Layout from "components/layout";
import SEO from "components/seo";

Dive into Gatsby GQL

With our development server running, navigate to http://localhost:8000/___graphql

This is where the real power of Gatsby lies, within its GQL Data Layer!

Oh…But we do!

Getting familiar with its capabilities and what it can do, will be essential for your quest and it shall aid us on our journey to create our blog platform.

Running our first GQL Query

  • Paste the following query below into the GraphiQL interface and run it
query MyQuery {
allFile {
edges {
node {
name
sourceInstanceName
}
}
}
}

Note
-
The side menu on the left has all the possible fields and nodes
- Based on the query we pasted above will check and collapse relevant fields
- We can use this to help explore and build our GQL queries.

Your GQL Query should produce the following result!

{
"data": {
"allFile": {
"edges": [
{
"node": {
"name": "gatsby-icon",
"sourceInstanceName": "images"
}
},
{
"node": {
"name": "gatsby-astronaut",
"sourceInstanceName": "images"
}
}
]
}
}
}

Query result breakdown

  • Return an array of all file assets that Gatsby is aware of
  • Returns the name of the file asset
  • sourceInstanceName will be something that we will explore in the next section of this tutorial.

Fetching Data From Filesystem Sources

Gatsby provides us with a large range of plugins to choose from that make our lives far easier, we shall now use the gatsby-source-filesystem, which allows us to source data from out filesystem, and into our application.

Let's try a little experiment

  • Navigate to gatsby-config.js
  • Comment out the following on lines 9–15
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: `${__dirname}/src/images`,
},
},

Restart the development server you will notice our GQL query now returns

{
"data": {
"allFile": {
"edges": []
}
}
}

This is because we removed the path to images from the gatsby-config.js.

Revert our change and uncomment the image source, let’s add a new one for our blog markdown files which we will add shortly.

  • Add the following object above the current images source.
{
resolve: `gatsby-source-filesystem`,
options: {
name: `blogs`,
path: `${__dirname}/content/blog-posts`,
},
},

Your file should now look like THIS

Creating Our Blog Markdown Files

Lets now manually create some markdown files which will be used by our application.

  • In the root of the project create these folders /src/content/blog-posts
  • Inside of the blog-posts folder create the following files
  • example-blog-1.md , example-blog-2.md , example-blog-3.md

Add the following content in the files

example-blog-1.md

---
title: Pikachu
description: Pikachu is an Electric-type Pokémon introduced in Generation I.
type: Electric
---

example-blog-2.md

---
title: Bulbasaur
description: Bulbasaur is a dual-type Grass/Poison Pokémon introduced in Generation I.
type: Grass / Poison
---

example-blog-3.md

---
title: Squirtle
description: Squirtle is a Water-type Pokémon introduced in Generation I.
type: Water
---

Your folder structure should be as follows

Using GQL Queries To Fetch Markdown Data

We will now start to explore fetching data of our markdown files through the GQL layer that Gatsby provides.

  • Restart your development server
  • Run the same query we ran above
  • The results below should be displayed
{
"data": {
"allFile": {
"edges": [
{
"node": {
"name": "example-blog-1",
"sourceInstanceName": "blogs"
}
},
{
"node": {
"name": "example-blog-2",
"sourceInstanceName": "blogs"
}
},
{
"node": {
"name": "example-blog-3",
"sourceInstanceName": "blogs"
}
},
{
"node": {
"name": "gatsby-icon",
"sourceInstanceName": "images"
}
},
{
"node": {
"name": "gatsby-astronaut",
"sourceInstanceName": "images"
}
}
]
}
}
}

Notice how the markdown files we just created are not fetched in this result. This is because we added an extra path in the gatsby-config.js file using the gatsby-source-filesystem plugin.

The sourceInstanceName is blogs because that is the name that we provided when setting up the paths to our blog posts.

Accessing Data Within Markdown Files

If you explore the current GQL fields, you will notice that while Gatsby is aware of the files, there is no way of currently accessing the data within them. Fortunately, Gatsby has a plugin that does the heavy lifting for us and gives access to the information within the markdown files.

Note now on the left-hand side we have 2 new fields allMarkdownRemark and markdownRemark, which will either get an array of all markdown files in the application or a single object returning data from one markdown file.

If we expand one of the these, we can see a field called frontmatter, this plugin will fetch information between the --- lines and create them into key-value pairs that we can access.

---
title: Squirtle
description: Squirtle is a Water-type Pokémon introduced in Generation I.
type: Water
---

This will give frontmatter access to the title, description and type properties, that can be accessed by the GQL Queries.

Running the following query

query MyQuery {
allMarkdownRemark {
edges {
node {
frontmatter {
description
title
type
}
}
}
}
}

Will give us the following result

{
"data": {
"allMarkdownRemark": {
"edges": [
{
"node": {
"frontmatter": {
"description": "Squirtle is a Water-type Pokémon introduced in Generation I.",
"title": "Squirtle",
"type": "Water"
}
}
},
{
"node": {
"frontmatter": {
"description": "Bulbasaur is a dual-type Grass/Poison Pokémon introduced in Generation I.",
"title": "Bulbasaur",
"type": "Grass / Poison"
}
}
},
{
"node": {
"frontmatter": {
"description": "Pikachu is an Electric-type Pokémon introduced in Generation I.",
"title": "Pikachu",
"type": "Electric"
}
}
}
]
}
}
}

Now we know how to query and access the data in our markdown files, let's start exploring how we can use various techniques to filter for specific posts!

Filtering Markdown Files With GQL Queries

There are various ways we can query and filter our results in Gatsby GQL layer. I will go over a few, which should give you enough information to explore and get creative with your own!

Simple Filtering Without Further Customization

Before we start modifying more code in our Gatsby config files, let see explore some simple regex filter queries we can do straight out of the box. Lets right some queries to get 1 result, so we use the markdownRemark field instead of the one we used above.

Query Based On File Path

We can query assets based on the file path, so we can use the file name in our regex to lookup certain markdown files.

Enter the following query below

query MyQuery {
markdownRemark(fileAbsolutePath: {regex: "/example-blog-1/"}) {
frontmatter {
description
title
type
}
}
}

Which successfully returns the data from the respective markdown file.

{
"data": {
"markdownRemark": {
"frontmatter": {
"description": "Pikachu is an Electric-type Pokémon introduced in Generation I.",
"title": "Pikachu",
"type": "Electric"
}
}
}
}

Try adding in the different file names to see the query filtering in action!

Query Based On Frontmatter Data

Along with the file path, we could run queries based on the content within the post, such as its title!

query MyQuery {
markdownRemark(frontmatter: {title: {eq: "Pikachu"}}) {
frontmatter {
description
title
type
}
}
}

Notice how we are not using regex for this filter, but eq Gatsby provides various built-in filter functions which we can utilize, you can explore which are available via the GraphiQL UI.

The query above would once again give us the result of the markdown file data of the previously queried item.

Filtering Based On Blog Slug

One of the most useful methods to query our posts will be based on a slug, this is a part of a URL which identifies a particular page on a website in an easy to read form. There is no built-in method of doing this, but we can easily create our own field node within the Gatsby configuration.

  • Navigate to gatsby-node.js
  • Paste the following code
const { createFilePath } = require("gatsby-source-filesystem");exports.onCreateNode = ({ node, getNode, actions }) => {
let parentNode = getNode(node.parent)
if (node.internal.type === "MarkdownRemark") {
if (parentNode.sourceInstanceName === "blogs") {
let slug = createFilePath({ node, getNode })
slug = slug.replace(/\//g, '');
actions.createNodeField({ node, name: "slug", value: slug })
}
}
}
  • We are using the sourceInstanceName which we created for our blog content source in gatsby-config.js
  • Based on the file path /example-blog-1/ we strip off all /
  • This will create a slug called example-blog-1

The onCreateNode function is called when a new node is created, we use this to extend current nodes in the GQL Schema, you can read more HERE.

Using the createNodeField we are able to add our own fields which will appear in the fields key in our GQL shape, you can read more HERE.

Restart the development server and go back to the GraphiQL interface.

You will notice that the slug field we just created is available under the fields key.

We can now write our queries in this manner to get the same results as above

query MyQuery {
markdownRemark(fields: {slug: {eq: "example-blog-1"}}) {
frontmatter {
description
title
type
}
}
}

You may be thinking why did we use this slug field when we could have used the other methods. This will become clearer in the next part of the tutorial when we start to dynamically create pages and pull data based on the URL.

You can explore more with the filtering if you like, add more markdown files, maybe we the same pokemon element type, and then use the allMarkdownRemark query, to fetch back more than one result!

The End

There we have it!
That will be all for Part 1 I hope the tutorial was easy to follow and gave a better insight into how we can use Gatsby GQL Data Layer to query files and retrieve data.

In part 2 of the tutorial, we will start to pull this data into our React components!

In case you got lost anywhere in the tutorial, HERE is the end state of how the project should look!

I hope you liked this introduction, don't forget to clap ;)