Learning Gatsbyjs by Building a Simple Blog: Part I

Posted by cmlugoce on January 24, 2019

Warning: it’s gonna be a looooong post!!

Last week I attended a meetup about Gatsbyjs! I found Gatsbyjs very interesting and decided to share a quick tutorial to get started on Gatsby!!

Gatsby.js is a static site generator for the react by using Gatsby we can build any type of modern web apps the sites built with Gatsby are high performant and blazing speed.It follows the “no build configurations” principle, This means that if you are a developer who wants to learn React.js or GraphQL you can go for it and do it without losing your time and motivation into learning build tools.

Gatsby.js does the code splitting so that user can only download the required number of files which needed to the particular page instead of over fetching the data.

Let’s get started

Note: Make you sure you have installed Node.js

Let’s start by installing the gatsby-cli:

npm install --global gatsby-cli

Once the installation is done, let’s create our project:

gatsby new 'your-project-name-here'

Awesome!! Let’s cd into our project folder and open the code editor to check the structure.

├── node_modules
├── src
├── .gitignore
├── .prettierrc
├── gatsby-browser.js
├── gatsby-config.js
├── gatsby-node.js
├── gatsby-ssr.js
├── LICENSE
├── package-lock.json
├── package.json
├── README.md

node_modules: The packages installed using npm will live in a node_modules folder.

src: The heart of the app lives on this folder! Inside this folder is where you are going to find the components, images and the pages to be render in the browser.

gatsby-browser.js: This file is related to the usage of any browser-related APIs provided by the gatsbyjs.

gatsby-node.js This file is related to the usage of any node related APIs provided by the gatsbyjs.

Now is time to open our browser!

gatsby develop (similar to npm start in React!) and visit localhost:8000

As you can see, Gatsbyjs provides you with a starter, so you can get creative pretty fast! To create new pages and components, we need to go back to the editor and open the src folder. There are three main folders in it: components, images and pages.

Components

This folder is where we can put other general components we create. Our starter code includes a header, and a layout component.

Pages

This is where your routing takes place!! Each file becomes one page and the name is based on the file name. So you might have an index page, which you will by convention name index.js.

Query the data

Gatsby uses the graphql for querying the data from the different data resources,

GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools.

We will learn some GraphQL as we go!. Also you can read this article

Now open your gatsby-config.js file and just change the title of the blog!

How cool is GraphQL! Gatsby also has included a tool to work test GraphQL queries: graphiQL. We can access this by navigating to localhost:8000/___graphql.

With graphiql we can test queries useful to ‘extract’ data from our site. Let’s try some queries:

We just got the same information from the gatsby-config.js file!

But, how our site is getting this data?🤔

If we go back to the editor and click on the /components folder we can see the layout.js . You will see that StaticQuery is querying for the site title data, which comes back from the query stored inside the data property.

//layout.js

import React from 'react'
import PropTypes from 'prop-types'
import { StaticQuery, graphql } from 'gatsby'

import Header from './header'
import './layout.css'

const Layout = ({ children }) => (
  <StaticQuery
    query={graphql`
      query SiteTitleQuery {
        site {
          siteMetadata {
            title
          }
        }
      }
    `}
    render={data => (
      <>
        <Header siteTitle={data.site.siteMetadata.title} />
        <div
          style=
        >
          {children}
          <footer>
            © {new Date().getFullYear()}, Built with
            {` `}
            <a href="https://www.gatsbyjs.org">Gatsby</a>
          </footer>
        </div>
      </>
    )}
  />
)

Layout.propTypes = {
  children: PropTypes.node.isRequired,
}

export default Layout



Create some content: Add some blog posts

We are going to create a few blog post in markdown format. In the /pages folder, create a folder for the first post. e.g. firstpost Inside it, create an index.md and put some content:


---
title: "My first Blog post 🐶"
description: Practicing Gatsbyjs
date: '2019-01-23'
image: ' '
author: The coding dog
---


Awesome Blog!

The next step will be to install 2 additional plugins. They will help in transforming the Markdown data into html format.

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

After installed, we need to add them in gatsby-config.js


module.exports = {
  siteMetadata: {
    title: 'Code and Dogs',
  },
  plugins: [
    'gatsby-plugin-react-helmet',
    {
      resolve: `gatsby-plugin-manifest`,
      options: {
        name: 'gatsby-starter-default',
        short_name: 'starter',
        start_url: '/',
        background_color: '#663399',
        theme_color: '#663399',
        display: 'minimal-ui',
        icon: 'src/images/gatsby-icon.png', // This path is relative to the root of the site.
      },
    },
    `gatsby-transformer-remark`,
    'gatsby-plugin-offline',
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        path: `${__dirname}/src/pages`,
        name: "pages",
      },
    },
  ],
}

Restart the server with gatsby develop and let’s make some queries on graphiql. You will see the same data from the first post!

{
  allMarkdownRemark {
    edges {
      node {
        frontmatter {
          title
          description
          date
        }
        html
      }
    }
  }
}

createPages API

Go back to the editor and open the gatsby-node.js file.

Gatsby exposes a powerful Node API, which allows for functionality such as creating dynamic pages, extending the babel or webpack configs, modifying the created nodes or pages, etc. This API is exposed in the gatsby-node.js file in the root directory of your project–e.g. at the same level as gatsby-config.js. Each export found in this file will be parsed by gatsby, as detailed in its Node API specification. However, we only care about one particular API in this instance, createPages.

First, we need to add a new field to our query : slug field. .onCreateNode API is used to create the new node fields. The slug will create a path to the blog post.

const path = require("path")
const { createFilePath, createFileNode } = require(`gatsby-source-filesystem`);
exports.onCreateNode = ({ node, getNode, actions }) => {
    const { createNodeField } = actions
    if (node.internal.type === `MarkdownRemark`) {
        const slug = createFilePath({ node, getNode, basePath: `pages` })
        createNodeField({
            node,
            name: `slug`,
            value: slug,
        })
    }
}

The next step is to create pages using the newly created API:

gatsby-node.js

const path = require("path")
const { createFilePath, createFileNode } = require(`gatsby-source-filesystem`)
exports.createPages = ({ actions, graphql }) => {
    const { createPage } = actions
    const blogPostTemplate = path.resolve(`src/templates/blog-post.js`)
    return new Promise((resolve, reject) => {
        resolve(graphql(`
    {
      allMarkdownRemark(
        sort: { order: DESC, fields: [frontmatter___date] }
        limit: 1000
      ) {
        edges {
          node {
              fields{
                  slug
              }
            frontmatter {
              title
            }
          }
        }
      }
    }
  `).then(result => {
                if (result.errors) {
                    console.log(result.errors)
                    return reject(result.errors)
                }
                const blogTemplate = path.resolve('./src/templates/blog-post.js');
                result.data.allMarkdownRemark.edges.forEach(({ node }) => {
                    createPage({
                        path: node.fields.slug,
                        component: blogTemplate,
                        context: {
                            slug: node.fields.slug,
                        }, // additional data can be passed via context
                    })
                })
                return
            })
        )
    })
}

exports.onCreateNode = ({ node, getNode, actions }) => {
    const { createNodeField } = actions
    if (node.internal.type === `MarkdownRemark`) {
        const slug = createFilePath({ node, getNode, basePath: `pages` })
        createNodeField({
            node,
            name: `slug`,
            value: slug,
        })
    }
}


We’re using GraphQL to get all Markdown nodes and making them available under the allMarkdownRemark GraphQL property. Each exposed property (on node) is made available for querying against. We’re effectively seeding a GraphQL “database” that we can then query against via page-level GraphQL queries. One note here is that the exports.createPages API expects a Promise to be returned, so it works seamlessly with the graphql function, which returns a Promise.

The createPage API accepts an object which requires path and component properties to be defined. Additionally, an optional property context can be used to inject data and make it available to the blog post template component via injected props. Each time we build with Gatsby, createPage will be called, and Gatsby will create a static HTML file of the path we specified in the post’s frontmatter–the result of which will be our stringified and parsed React template injected with the data from our GraphQL query.

Creating the Blog post template

A blog post template is needed to give shape to the posts. Create a template folder in the root of the project, and make a file, blog-post.js.

import React from 'react';
import Layout from '../components/layout';

const BlogPost= () => {
    return (
        <Layout>
            <div>
                My first post
        </div>
        </Layout>
    )
}
export default BlogPost

Now delete .cache folder and run the gatsby develop

If you navigate over to the localhost:8000/firstpost you will see the template rendered on the screen.

Time to write the blog-post query:

import React from 'react';
import Layout from '../components/layout';
import { graphql } from 'gatsby'
const BlogPost=()=> {
    return (
        <Layout>
            <div>
                My first post
        </div>
        </Layout>
    )
}
export default BlogPost
const query = graphql`
 query PostQuery($slug: String!) {
     markdownRemark(fields: { slug: { eq: $slug } }) {
       html
       frontmatter {
        title
        description
       }
   }
`

The underlying query name PostQuery (note: these query names need to be unique!) will be injected with the current path, e.g. the specific blog post we are viewing. This path will be available as $slug in our query. For instance, if we were viewing our previously created blog post, the path of the file that data will be pulled from will be /firstpost.

markdownRemark is the main data pull, and each item we pull from the underlying data store will be available to our component as data.markdownRemark.someValue, e.g. data.markdownRemark.html will be the injected HTML content transformed from the original Markdown source.

frontmatter, is our data structure we provided at the beginning of our Markdown file. Each key we define there will be available to be injected into the query. We can also access this data via props.data

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

const BlogPost=(props)=> {
    const post = props.data.markdownRemark;
    const { title } = post.frontmatter;
    return (
        <Layout>
            <div>
                <h1>{title}</h1>
                <div dangerouslySetInnerHTML= />
            </div>
        </Layout>
    )
}

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

Restart your server again and navigate to the post!

Getting the posts list

It’s time to render the posts list on the site!

index.js

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

const IndexPage = (props) => {
  const postList = props.data.allMarkdownRemark;
  return (
    <Layout>
      {postList.edges.map(({ node }, i) => (
        <Link to={node.fields.slug} className="link" >
          <div className="post-list">
            <h1>{node.frontmatter.title}</h1>
            <span>{node.frontmatter.date}</span>
            <p>{node.excerpt}</p>
          </div>
        </Link>
      ))}
    </Layout>
  )
}
export default IndexPage;
export const listQuery = graphql`
  query ListQuery {
    allMarkdownRemark(sort: { order: DESC, fields: [frontmatter___date] }) {
      edges {
        node {
          fields{
            slug
          }
          excerpt(pruneLength: 250)
          frontmatter {
            date(formatString: "MMMM Do YYYY")
            title
          }
        }
      }
    }
  }
`

Create a second post, restart the server and navigate to localhost:8000

Yay!! Now we can see our posts!!!

Awesome!! Now you have a simple blog app!! In the next post we will add images, the syntax highlighter, and some basic styling!