Simple Blog Site with Gatsby
Tags: gatsby, react, npm, node
Published: 2020-03-17 21:58:52

Hello everyone,

***Quick note: I use terminal and cmd prompt or command line interchangeably throughout this post. Also in case you are not as familiar with using the terminal in the command throughout this post please do not type the $ in with the commands. The $ is just meant to show you that it is a terminal prompt. Any similarities to courses or posts is coincidence. This post has been my own experience with Gatsby and what I went through building the blog site.***

I know in my last post I promised I would write a series of posts on the JAMStack for how to create an eCommerce site. But with this post I just want to start small. A lot of people might not be familiar with Gatsby or static site generators so what I want to do is get you going with your own blog site. One where you can post thoughts and tutorials of your own and then also provide the link here on sites like https://dev.to/ so that you can make sure the posts get read.

# The Great Gatsby
Gatsby is a free and open source framework based on React that helps developers build blazing fast websites and apps. This is directly from Gatsby's home page at https://www.gatsbyjs.org/. What does Gatsby allow us to do? And why is it so fast? 
## The Workings of Gatsby
Gatsby allows us, as developers, to use several different ways to get data to our application/website. We can use CMSs, Markdown, or data in the form of JSON or an API even. We can pull data in from anywhere. Write some code and Gatsby will take the code generate a website using **HTML**, **React**, and some **CSS** and allow you to deploy to sites such as **GitHub Pages**, **Netlify**, **AWS Amplify** and **Zeit Now** to name a few.

## Examples:
With Gatsby developers and even non developers that want their own site can finally enjoy the power of the latest web technologies like **React**. You can even use **Webpack** and modern **JavaScript** to build your site. You are able to bring your own data. Gatsby uses a rich data plugin ecosystem that lets you build sites with the data you want. You can pull from one or many different sources such as: from a headless CMS or SaaS, multiple APIs, databases your own file system and more using the power of GraphQL.

## Speed of light
Gatsby builds the fastest possible website. Instead of waiting to generate pages when you request them, Gatsby has already pre-built the pages and just lifts them so to speak into a global cloud of servers where they are ready to be delivered instantly to your users wherever they are.

Now that you have a brief introduction to what Gatsby can do let's get started with actually setting up the project.

# Where to Start
The first thing that you will want to do in order to work with Gatsby is actually make sure you have nodejs installed. Head over to nodejs.org and click the download button. I usually recommend the lts version. I have circled which one to use in the screen shot below
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/ji8vhy36or37b6s6nnpg.png)

After you have Nodejs installed you can verify that its been installed by opening up your terminal and typing:
```bash
$node -v
```
Also make sure you have an up-to-date version of npm as well with this command:
```bash
$npm -v
```
At the time of writing this post the versions I have installed are:
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/tr8o0wy5bywzb889erf9.png)
If you have YARN installed and would rather use it over npm feel free to replace the commands with the YARN equivalent.

# Getting Gatsby
Now that we have the necessary tools available we are going to install Gatsby. To install Gatsby you will run these commands in your terminal.
```bash
$npm install -g gatsby gatsby-cli
```
The commands above will make sure that we are installing the latest versions of both Gatsby and the Gatsby CLI.

# Brief pause in the Action
I want to take a second and say that here: https://www.gatsbyjs.org/starters/?v=2 you are able to go and look at a starter template to use for your site. I know we are creating a blog but that doesn't mean that you can't make the site look good by choosing a neat starting template. Be sure to replace the one I chose in the command used in the next section with one you chose. If you didn't find one that you liked feel free to just use the same command I did. 

# Creating your project
Next we will run the command to bootstrap a new Gatsby project. In your terminal type the following command, remember to replace the url with the starting template of your choice if it's different from mine.
```bash
$gatsby new awesome-blog https://github.com/gatsbyjs/gatsby-starter-blog
$cd awesome-blog
$npm i
```
This will start to generate all the files and folders necessary for the project. As well as install all of the dependencies the project needs. After this finishes run:
```bash
gatsby develop
```
Once the application has started you should be able to view the project on localhost:8000. 

# Gatsby config file
We are going to create a config file. So here I will open the project in VS Code, you can of course use whichever IDE or text editor you are comfortable with. From within your terminal if you are using VS Code input this command to open the project:
```bash
$code .
```
This command will open the project directly in VS Code at the current directory you are in. If you are using Atom then the command is similar:
```bash
$atom .
```
Next we will create a new file called **gatsby.config**. Inside the file we will write this:
```js
module.exports = {
  siteMetaData: {
    title: 'My Super Awesome Blog',
    description: 'This blog is my personal blog, I think it's awesome'
  },
  plugins: [
    `gatsby-transformer-remark`,
      {
        resolve: `gatsby-source-filesystem`,
        options: {
          name: `pages`,
          path: `${__dirname}/src/pages`
      }
    }
  ]
} 
```
*Quick note with the plugins section above those are backticks not quotes. Also I wanted to let you know that if you decided to use a different starter kit then you will most likely already have a gatsby.config file. You can modify this if you feel comfortable with doing that. If not just leave it the way that it is or you could just use the simple blog starter kit.*

With the config file created we are ready to start adding posts. We can do this by right clicking on the pages directory from within VS Code and typing out the date then the name of the blog post like this 2020-03-16-my-first-blog-post. Make sure this is folder and not a file. This is a directory for your posts. Next we will create an **index.md** file in this directory. The **index.md** file will be our actual blog post.Inside of the index.md file we can type:
```md
---
path: "/my-first-blog"
date: "2020-03-16"
title: "My First Blog Post"
tags: ['gatsby', 'blog']
excerpt: "My very first Gatsby Blog Post"
---

Here is the content of my first Gatsby blog. This is really awesome.
```

# Using React
Inside of our pages directory we will need an index.js file. Let's create it now if it doesn't already exist. Inside of the index.js file we will add these lines of code:
```react
import React from 'react';
import { StaticQuery, graphql } from 'gatsby';

const TitleAndDescription = ({data}) => {
  const title = data.site.siteMetadata.title;
  const description = data.site.siteMetadata.description;

  return (
    <div style={{
       display: 'flex',
       flexDirection: 'column',
       alignItems: 'center'
    }}>
      <h2 style={{marginBottom: 0}}>{title}</h2>
      <p style={{
        marginTop: 0,
        opacity: 0.5
      }}>
       {description}
     </p>
    </div>
  )
}

const Header = () => {
  return (
    <StaticQuery
      query={graphql`
        query {
         site {
          siteMetadata {
            title
            description
           }
          }
         }
       `}
        render={data => <TitleAndDescription data={data} />}
    />
  )
}

const Layout = () => {
  return (
    <div>
      <Header />
    </div>
  )
}

export default Layout;
```
Let's actually refactor this a little bit. Create a new fold in your *src* directory called *components*. Then create a new files one called `Header.js` and we will take all of this:
```react
import React from 'react';
import { StaticQuery, graphql } from 'gatsby';

const TitleAndDescription = ({data}) => {
  const title = data.site.siteMetadata.title;
  const description = data.site.siteMetadata.description;

  return (
    <div style={{
       display: 'flex',
       flexDirection: 'column',
       alignItems: 'center'
    }}>
      <h2 style={{marginBottom: 0}}>{title}</h2>
      <p style={{
        marginTop: 0,
        opacity: 0.5
      }}>
       {description}
     </p>
    </div>
  )
}

export default Header;
```
and copy it over to the `Header.js` file. Then remove the two components from our `index.js` file. Make sure you leave the imports and then after you have removed the components, import the header file:
```react
import Header from '../components/Header';
```

# List of our Posts
We are now going to try to render our list of posts to the page. To do that we need to add some more code to our `index.js` file. Place this code above our default export statement at the bottom of the page.
```react
export const query = graphql`
  query listOfBlogs {
     allMarkdownRemark(
      sort: {order: ASC, fields: [frontmatter___date]}
    ) {
       edges {
        node {
         frontmatter {
           title
           path
           date
         }
      }
   }
}
`
```
Next what we want to do is modify our Layout component to accept the data. Let's add that code now.
```react
const Layout = ({data}) => {
  const { edges } = data.allMarkdownRemark
  return (
    <div>
     <Header />
      {edges.map(edge => {
        const {frontmatter} = edge.node;
        return (
         <div key={frontmatter.path}>
          {frontmatter.title}
         </div>
        )
      })}
    </div>
  )
}
```
In the above code snippets I added `ASC` for the order parameter on allMarkdownRemark. You can add DESC if you want to show your latest posts first. I chose ASC because I wanted the order to start with my very first post. This is your site and your blog so you should make it how you want it.

# It's All About the Link
So as you've probably noticed you have the title of the post or posts you've made at this point but you can't go into the post to actually read anything. That is because they are not a link. Let's do that now.
```react
// modify the import statement from Gatsby
import { graphql, Link } from 'gatsby';

// next we will wrap our title with the Link tag
<Link to={frontmatter.path}
  {frontmatter.title}
</Link>
```
Now the titles are links and we can... not go to them. What gives? Why do we get a 404 error? Well we haven't created the routes to those pages yet.

# Follow the Route of the 40 Thieves...
So in order to create the route we need to create a file in the root directory. So outside of the src directory where your `node_modules` folder is create a new file and call it `gatsby-node.js`. Then inside your `src` folder let's add a templates folder. Inside the templates folder we will create a file called blogPost.js.
```react
//blogPost.js
import React from 'react';
import { graphql } from 'gatsby';

const Template = (props) => {
  return (
    <div>
     Blog Post! Blog Post! Read All About It!
    </div>
  )
}
```

```js
// gatsby-node.js
const path = require(path);

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

  return new Promise((resolve, reject) => {
    const blogPostTemplate = path.resolve('src/templates/blogPost.js');
    resolve(
     graphql(
       `
       query {
        allMarkdownRemark {
          edges {
           node {
            fronmatter {
              path
            }
           }
          }
        }
      }
     `
   ).then(result => {
     result.data.allMarkdownRemark.edges.forEach(({node}) => {
        const path = node.frontmatter.path
        createPage({
          path, 
          component: blogPostTemplate,
          context: {
            pathSlug: path
          }
         })

         resolve()
        })
      })
 )

})
```
We will need to rerun `gatsby develop` command so that the changes we made take effect. Now we are able to click on our title and it will take us to the blog post. 

# Building the Blog Post Template
We are going to update our template file to actually get our HTML for the blog post. Above our export for Template place this code:
```js
import React from 'react';
import { graphql } from 'gatsby';

const Template = ({data}) => {
  const {markdownRemark} = data;
  const title = markdwonRemark.frontmatter.title;
  const html = markdownRemark.html;
  return (
    <div>
      <div className="blogPost" dangerouslySetInnerHTML={{__html: html}} />
    </div>
  )
}

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

# Moving Forward and Backward
We are now going to add the next and previous links to our blogs so that we can either go to the next one directly from the current post or the previous one as well. We will be updating our `gatsby-node.js` file. 
```js
// in the .then()
const posts = result.data.allMarkdownRemark.edges;
posts.forEach(({node}, index) => {
  const path = node.frontmatter.path;
  createPage({
    path,
    component: blogPostTemplate,
    context: {
      pathSlug: path,
      prev: index === 0 ? null : posts[index - 1].node,
      next: index === (posts.length - 1) ? null : posts[index + 1].node
    }
  })
```
Make sure the `.then()` method looks like the above snippet. Now we are going to update our query for allMarkdownRemark to make sure that the order is correct for our previous and next posts.
```js
allMarkdownRemark (
  sort: {order: ASC, fields: [frontmatter___date] }
 ) }
```
We are now ready to add the links. Let's update the template component
```js
import { graphql, Link } from 'gatsby';

const Template = ({ data, pageContext }) => {
  const {next, prev} = pageContext;
  // under the return add this
 <div style={{marginBottom: '1rem'}}>
  {next && 
    <Link to={next.frontmatter.path>
     Next
    </Link
  }
  {prev &&
    <Link to={prev.frontmatter.path}>
     Previous
    </Link>
  }
 </div>
</div>
```
# Tag You're It
We will now add browsing posts by tag. We will start by adding some templates. In our templates directory lets add `tagsIndex.js` and `tagindex.js`.
```js
// tagsIndex.js
import React from 'react';
import { graphql, Link } from 'gatsby';

const TagsTemplate = ({ data }) => {
  return(
    <div>
      <div>
        tags here
      </div>
    </div>
  )
}

export default TagsTemplate;
```

```js
// tagIndex.js
import React from 'react';
import { graphql, Link } from 'gatsby';

const TagTemplate = ({data}) => {
  return (
    <div>
      <div>
        tags here
      </div>
    </div>
  )
}

export default TagTemplate;
```
Now we need to update our gatsby-node.js file. 
```js
const createTagPages = (createPage, posts) => {
  const tagsIndexTemplate = path.resolve('src/templates/tagsIndex.js);
  const tagIndexTemplate = path.resolve('src/templates/tagIndex.js);

  const postsByTag = {}

  posts.forEach(({node}) => {
    if (node.frontmatter.tags) {
      node.frontmatter.tags) {
        if(!postsByTag[tag]) {
          postsByTag[tag];
        }

        postsByTags[tag].push(node);
      })
    }
  })

  const tags = Object.keys(postsByTag)

  createPage({
    path: '/tags',
    component: tagsIndexTemplate ,
    cointext: {
      tags: tags.sort()
    }
  })


}
```
Next we will update our `.then()` method to actually create the pages.
```js
// underneath the posts variable
createTagPages(createPage, posts)

// make sure to add this line in our query
      title
      tags
```
Restart our `gatsby develop` and we should now be able to see our tags page at localhost:8000/tags. Next we will update our gatsby-node.js file to iterate over the tags.
```js
// under createPage add this line
tags.forEach(tagName => {
  const posts = postsByTag[tagName];
  
  createPage({
    path: `/tags/$tagName}`,
    component: tagIndexTemplate,
    context: {
      posts,
      tagName
    }
  })
})
```
Now lets update our tagTemplate.
```js
const tagTemplate = ({data, pageContext}) => {
  const { posts, tagName } = pageContext;
  return (
    <div>
      <div>
        Posts about {`$[tagName}`}
      </div>
    <div>
      <ul>
        {posts.map((post, index) => {
          return (
           <li key={index}>
             <Link to={post.frontmatter.path}>
               {post.frontmatter.title}
             </Link>
           </li>
          )
        })}
      </ul>
    </div>
  </div>
 )
}
```
We will now open up the `tagsIndex.js`file and give it a similar treatment. 
```js
// tagsIndex.js
const TagsTemplate = ({data, pageContext}) => {
  const { tags } = pageContext;
  return (
    <div>
      <div>
        <ul>
          {tags.map((tagName, index) => {
            return (
              <li key={index}>
                <Link to={`/tags/${tagName}`}>
                  {tagName}
                </Link>
              </li>
            )
          })}
        </ul>
      </div>
    </div>
  )
}
```
The final thing we are going to do in this section is create a link on the home page to view all posts.
```js
//index.js
//Under our edges mapping put this code
<div>
  <Link to='/tags'>Browse by Tag</Link>
</div>
```
# Pu Pu Pu Push It Real Good
We are finally finished with our blog site. It is now time to push the website to production. We will be using Netlify. We will need to run one command that will bundle all of this code up and make production ready. 
```bash
gatsby build
```
Then we can head over to GitHub, if you don't have a GitHub account don't worry it's free. I believe you could also use BitBucket if you are more comfortable doing that. I believe the steps are similar but I'm not 100% on that. From GitHub you can make a new repository name it whatever you want. I will be using my-awesome-blog. Here are the basic steps for pushing to GitHub:
- visit https://github.com
- sign up or login
- create a new repository by clicking the + next to your profile image
- name your repository 
- follow the below steps to push your code
```bash
cd <root of project>
dir //if you are on mac use ls
// make sure you see the src folder in the list
git init
git add .
git commit -m "initial commit"
git remote add origin git@github.com:<YOUR GITHUB USERNAME HERE>/<NAME OF YOUR REPO HERE>.git
git push -u origin master
```
Now go to netlify.com. Sign up or sign in if you already have an account. If you sign up I would definitely use your GitHub, BitBucket, GitLab etc account to sign up. It will make publishing easier. Then follow these steps
1. Click on the Git provider button you pushed your code to, if you followed this tutorial it should be GitHub.
2. Authorize your account.
3. Select the repo in my case it would be my-awesome-blog.
4. Select the master branch, should be the only branch you have
* We don't need to specify any build commands or the publish directory since we did that already with the `gatsby build` command*
5. Click the Deploy site button
6. After the build has finished you will have a link you can go to that will end with netlify.com. You can share that link with friends and family as the site is now live. 

# The End
Thanks for reading this tutorial. I hope that it helped you in seeing the power of Gatsby and that it demonstrated its ease of use. Now that you have your own blog site you can blog about anything and everything. Those of you that are proficient with React can modify this site to be more than just a blog. If you wanted to convert this to a portfolio site with your blog attached you definitely could. Please feel free to leave your comments and let me know if you liked this. I am totally up for doing more.