The Gatsby Struggles

Published on 11 Jun 2020 by Dave Regg

Gatsbyjs is incredible to use! If you have some basic knowledge of React, Gatsby is very easy to pick up on. It comes with an entire library of useful plugins, templates, and support. Overall, I have enjoyed the few projects that I have built in Gatsby. That isn't to say that there were some struggles along the way.

gatsby-node.js

A standard file in a Gatsby app is the gatsby-node.js file. From how I have used it, the file is essentially an "in-between" for a graphql query and a gatsby template page. Within this article, I will be talking about the Gatsby Node createPages API.

The createPages method is used to source data from markdown or a CMS from graphql, create a page based on a pre-defined template, and create a page combining the two. createPages is a method that is exported from gatsby-node.js. It takes in parameters ({ graphql, actions }), used to query graphql and define Gatsby Node API actions. A Promise will be used later in the method, so this will be an async / await function. The method will look like this:

module.exports.createPages = async ({ graphql, actions }) => { ... }

To begin creating a page, create a variable to hold the path to your template in.

const postTemplate = path.resolve(`./src/templates/post.js`);

The graphql method provided in the API will then be used to query the graphql database. The graphql method returns a Promise, so this is where await comes into play.

const posts = await graphql(` ...insert query here `)

The query will most likely involve searching for all nodes within the edges of the graphql database, whether it be allMarkdownRemarks or allContentfulBlogPost. The retrieved data can then be manipulated to createPages with. I learned that the easiest way is to loop through each edge with a forEach loop

posts.data.allContentfulBlogPost.edges.forEach(({node}) => { ... }

Each node represents page data. That means there will be a new page for each node. Within the forEach block is where actions.createPage is called, which will take in an object of options.

createPage.({ component: postTemplate, path: `/blog/${node.slug}`, context: { slug: node.slug } })

Where context is any information that needs to be sent down to the template via props. In the case for this blog, I send down the slug. The slug is then used to query graphql in the template page in order to get the relevant data for the template!

gatsby-node.js was intimidating for me in my first Gatsby project. I am now at least a bit more comfortable with createPages, and I understand the flow of data in order from Gatsby to graphql to template. The more you build, the easier it is to grasp.

SEOh-no!

One thing that I never really cared for was SEO- Search Engine Optimization! I have always related it to how easy it is for my website to be found by Google. In my case, I don't have a preference whether my sites are on Google or not- they're all just pet projects to me.

However, Gatsby makes SEO so simple that I decided to give it a go. Between using React-Helmet and the Gatsby SEO docs, I learned how to implement an SEO Component in my layout. Along the way, I learned that SEO is more than just for search engines. I used the SEO prompts in order to make a Twitter card for my articles. And golly, it worked!

React-helmet is a package that creates a <head> element for you, complete with <title>, <link>, and <meta> tags that you can populate with data that you query with graphql or implement with contentful data.

Starting off simple, within another special Gatsby file, gastby-config.js, export some siteMetadata as an object.

siteMetadata = { title: 'Dave Regg\'s Blog', author: 'Dave Regg' }

This data can be retrieved with a graphql query in the SEO Component and implemented with <Helmet title={siteMetadata.title} meta={[{ name: `author`, content: siteMetadata.author }]} />

In order to make a Twitter card out of this, it can get a bit more complex. A lot of the docs and tutorials I saw about the Twitter cards had essentially the same code, so unfortunately, it was a copy/paste kind of procedure. You can find the code that I used to implement it on my Github page.

Assuming you're reading the code, Twitter has its own meta tags, twitter:creator, twitter:title, twitter:description. Then <Helmet> needs to .concat images in a separate array. An image needs a source, width, and height, while Twitter needs a twitter:card to define the type of card to use in your personal Tweet- in this case, the content is set to `summary_large_image`.

SEO from Where?

In order to get the data, the SEO Component needs to brought into each Page or Template Component. The data is passed down through props. For example, in order to get my Blog title, I pass down the title of the Post from the Post Template, and combine it with the Title of my site from siteMetadata.

In such a way, post description and post images will also be passed down after each Post Template is populated with the post data from the graphql query! It's complex, but it's easy to see how it all intertwines and works together in order for the data to get from one place to another, and eventually, on to Twitter!

To check if the card is valid, use Twitter's own validation tool! I personally struggled with getting the source image from each post because the link isn't in the same format as the Gatsby docs page (pro hint: Gatsby uses Markdown. It's actually easier to use Contentful). Things I learned about Twitter- usernames are case sensitive, and the source image needs to be in http:// format, no security!

It took me a couple of hours to truely understand how the SEO Component worked, but now that I know, using the default starter template for Gatsby has its own SEO Component out of the box, and I can use it with ease!