Setting up a personal blog with Gatsby and Contentful CMS
Tags: react, gatsby, webdev, netlify
Published: 2021-02-13 17:03:50

##Scope:
In this tutorial, we will learn how to set up Gatsby with Contentful CMS and then deploy the application on Netlify for free. 
##Background:
Prior to this, I had my blog site running on AWS([deployment post](https://dev.to/asim_ansari7/deploy-a-react-node-app-to-production-on-aws-2gdf)) that required extra effort to set up, and publishing content on it was a bit tedious. Moreover, I had a free tier plan that got expired, and the relevant services(**EC2 t2.micro** & **RDS db.t2.micro**) were being billed at around a dollar a day. 
I wanted to revamp my blog site and improve the content management flow in particular so started looking out for other options and got to know about  **Static Site Generators** and was amazed at how incredibly easy it was to work with them. I chose **Gatsby** to build the front-end layer of the blog and integrated it with **Contentful CMS** to fetch data from there.

##Setting up Gatsby:
Install Gatsby CLI globally on your machine by running the following command from the terminal.
```javascript
npm i -g gatsby-cli
```
To generate a new project run:
```javascript
gatsby new your-project-name
```
This will create a new project folder with all of the starter files. Switch to the project directory and run 
gatsby develop
This would start the gatsby server on the default port of 8000. 
![Gatsby-Default-Page](https://images.ctfassets.net/8pwqq37w808a/1nQcp2pXVP3L4Gz7dlsGMA/5e951ef7df4a96329c84c3e4b313ca54/Gatsby-default.png "Gatsby-Default-Page")

##Gatsby Starter
[Starters](https://www.gatsbyjs.com/starters/?) are basically boilerplate code that is maintained by the community to facilitate the development process. We can add another argument to our project setup command that is the URL of the starter that we want to use.

I initialized my project by using this [starter](https://www.gatsbyjs.org/starters/W3Layouts/gatsby-starter-delog/) and running the following command:
```javascript
gatsby new gatsby-blog https://github.com/W3Layouts/gatsby-starter-delog
```
I found the markup, styling, and dark mode feature super cool so went with it to speed things up. I did some customizations and changed the CMS to Contentful which was more powerful. The final site can be found [here](https://404found.tech/).

##Setting Contentful CMS
A CMS is pretty useful as it offers a nice interface for managing content and exposes APIs to pull data from it. 
1. Head over to [contentful.com](https://www.contentful.com/sign-up/)  and create a free account. 
2. Create a **space** for your project content from the sidebar menu.
3. Next head to the **Content model** tab, which could be thought of as schema for your actual content or blog posts. It will have fields like the blog title, description, publishing date, etc. 
4. Click on the **Content model** tab to add a content type and click on the **Create** button.
5. Add **relevant fields** in your model by clicking on the **Add Field** button. I had added the following fields:
![Content-Model](https://images.ctfassets.net/8pwqq37w808a/2mNEyQoteFrLzTQg1bIkkG/25ba561a4e1b5cf1ce46864a3315116e/Contenful-Model.png "Content-Model")
6. Save it and head to the **Content Tab** to create your first post by clicking on the **Add Blog Post** button.
![Content-Tab](https://images.ctfassets.net/8pwqq37w808a/1fBRUMEIwrkJcgx1Mt8hSH/16dd1da94cf802e0086c10d22bca0c51/Content-Tab.png "Content-Tab")
7. Hit the publish button once done and now we can start accessing this data from the Gatsby site.
8. Prior to it, go to the **Settings** dropdown menu and click on the **API Keys** and generate a new key by clicking on the Add API Key button. Copy the **Space ID** and **Access Token** that will be required later.

##Gatsby Project Setup:
Project Github link: [https://github.com/Asim1996/gastby-blog](https://github.com/Asim1996/gastby-blog)
In the installed starter project run the following command to install the Contentful plugin:
```javascript
npm install gatsby-source-contentful@2.3.12
```
The source plugin is required for pulling content types, entries, and assets into Gatsby from Contentful spaces. Add the plugin to **gatsby-config.js** file
```javascript
module.exports = {  
siteMetadata: { ... },
 plugins: [    
{      
resolve: 'gatsby-source-contentful',      
options: {        
spaceId: process.env.CONTENTFUL_SPACE_ID,        
accessToken: process.env.CONTENTFUL_ACCESS_TOKEN      
},      
forceFullSync: true    
},
...
]
}
```
Create **.env** file in your project root directory and paste the **Contentful Space ID** and **Access Token** in it.
Modify your development script in the **package.json** file to fetch data from the **.env** file.
```javascript
"develop": "env-cmd .env gatsby develop"
```
For fetching all blog posts data the **allContentfulBlogPost** node would be used in the GraphQL query.
![GraphQL-Query](https://images.ctfassets.net/8pwqq37w808a/6YN6vRyk0KIRd38L53h7hg/81723af829a5df681a8b05b6a80b6a3e/graphql_query.png "GraphQL-Query")
The above query returns the list of all posts available in Contentful which is then passed as props to the Card Component to generate a view for all posts.
Rather than fetching the post **body** too in the initial index page and passing it as props down the child component, we will be creating dynamic pages with the help of **slug** content-type defined in our blog schema and adding configurations in the **gatsby-node.js** file as defined below.
```javascript
const path = require("path")
// Create blog pages dynamically
exports.createPages = async ({ graphql, actions }) => {
  const { createPage } = actions
   const blogTemplate = path.resolve('./src/templates/blog.js')
  const res = await graphql(`
    query {
      allContentfulBlogPost {
        edges {
          node {
            slug
          }
        }
      }
    }
  `)
  res.data.allContentfulBlogPost.edges.forEach((edge) => {
    createPage({
      component: blogTemplate,
      path: `/blog/${edge.node.slug}`,
      context: {
        slug: edge.node.slug,
      },
    })
  })}
```
The above code dynamically generated blog pages basis the markup defined in the template file and the slug that is being fetched from Contentful in the building process of your Gatsby site.
In your project src directory create a new folder named **templates** and create a file named blog.js in it.
The following code is used to fetch the relevant blog post basis the **slug** that comes from the context object from the **gatsby-node.js** file.
```javascript
...
export const query = graphql`
  query($slug: String!) {
    contentfulBlogPost(slug: { eq: $slug }) {
      title
      publishedDate(formatString: "MMMM Do, YYYY")
      description
      backgroundImage{
      title
             fluid(maxWidth: 300, maxHeight:200) { 
             ...GatsbyContentfulFluid       
             }
             file{
        url
        fileName
        contentType
      }
     }
     body{
       json
     }
   }
}
`...
```
The JSX in the file can be modified or styled accordingly basis on the data we now have as props.
To render the **Rich Text** content(blog post body) install the following package:
```javascript
npm install @contentful/rich-text-react-renderer
```
and for syntax highlighting then use the following package:
```javascript
npm i react-syntax-highlighter
```
The template file can then be modified to use the above packages and render the content in a more appealing way. 

##Deploying to Netlify
Push your code on Github(or any other Git provider) and signup for a free account on [Netlify](https://www.netlify.com/). Then, click on the **New site from Git button** and choose your Git provider and the repository that needs to be deployed. Add your Environment Variables by clicking on the **Show advanced** button on the deploy settings page.
Click on the **Deploy site** button that will trigger the deployment process and once it is complete you'll see your site URL. And that's it, a few button clicks and your site is live on the internet.

##Optional Setups:
**Mapping a custom domain:** If you have an existing domain bought from any external Domain Name provider (GoDaddy, BigRock, etc). Head to your domain name provider and create an **A record** and link Netlify’s load balancer IP with your domain name to complete the entire setup.
Helpful links: [Custom Domains](https://docs.netlify.com/domains-https/custom-domains/), [Configure External DNS](https://docs.netlify.com/domains-https/custom-domains/configure-external-dns/)

**Netlify Forms:** In your contact form just add the following attributes
```javascript
<form class="form" name="contact"  method="post" data-netlify="true" data-netlify-honeypot="bot-field">
 <input type="hidden" name="bot-field" />               
<input type="hidden" name="form-name" value="contact" />
```
Netlify's bots will automatically detect the attribute **data-netlify="true"** when you deploy your site and process the form for you. 
Head to Settings > Forms > Form notifications and receive an email alert anytime a new submission comes through.
Helpful Link: [Netlify Forms](https://docs.netlify.com/forms/setup/)

**Configuring a Netlify build hook:**  If you make changes to your Contentful post data, you can either trigger a deploy manually from Netlify or generate a Netlify build hook (that you can add to Contentful CMS) to trigger an automatic redeploy of your site. 
From the Netlify dashboard, navigate to the "Settings" for your site, choose "Build & deploy", and scroll to "Build hooks". 
Click **Add build hook** that then generates an HTTPS URL that responds to requests by triggering a build and deployment of your site. Copy the URL and navigate back to the Contentful web app. From the Settings choose **Webhooks** and paste the URL that Netlify provided into the form.
Helpful link : [Netlify Build Hook](https://www.contentful.com/developers/docs/tutorials/general/automate-site-builds-with-webhooks/)

**Adding Disqus to Gatsby:** Having a comment section in your blog post can be pretty helpful and that could easily be set up signing up on [Disqus](https://disqus.com/profile/signup/?next=https%3A//disqus.com/). Post that, install the following package: 
```javascript
npm i disqus-react
```
Add the following config in your template file:
```javascript
... 
const disqusConfig = {    
url: `https://404found.tech/${props.data.contentfulBlogPost.slug}`,    identifier: `${props.data.contentfulBlogPost.slug}`,    
title: props.data.contentfulBlogPost.title,  
}
<Disqus.DiscussionEmbed shortname="404found-tech" config={disqusConfig} />
...
```

Thanks for reading.
Cheers!!