Gatsby and the new era of site generators

Front-end, Software engineering

Gatsby and the new era of site generators

Maxime Fabre

Maxime Fabre

Why Gatsby?

One of the greatest aspects of modern web development is how modular and composable everything has become. Building an application these days has become a lot like tinkering with building blocks: piecing together packages, APIs, services and so on. Each doing what they do best. We’ve learned that reinventing the wheel is (often) not the solution and by embracing interoperability we’ve been able to make it easier than ever to bring an idea to life.

Of course, people still fight about what the best view layer is, or bundler or service for a given thing. But the fact is that these heated debates have become much more granular and much more focused on specific aspects of each app instead of just “What is the best framework?” period.

But as specific tasks became easier and easier to do, the workload gradually shifted from purely “implementing ideas” to “piecing existing ideas together”. This is one of the reasons why we’ve seen an incredible surge of “starter packs” repositories that show infinite variations of using this and that technology together. “Here is a starter pack about how to use Redux with React and GraphQL” per example; these individual technologies have become a lot more user-friendly (hopefully) but tying them together now becomes the challenge.

This is where Gatsby comes in: it is a tool specifically made to help you tie technologies together in one cohesive whole. There’s been a lot of misinformation about it, what it is, what it does, what you can do with it and so on. But at its core, that’s what Gatsby is: a giant blender, much like what Webpack aimed to do for compilation. So let’s dive into it and see what’s what.

What is Gatsby?

First, let’s peek at how Gatsby defines itself on its landing page. Here are the most important points you’ll see mentioned:

Gatsby is a framework based on React

For a lot of people this is a dealbreaker but fret not because there are alternatives for other view layers: if you’re a big Vue.js fan instead, then Gridsome has you covered for example. You can even keep reading this article because they have such a similar philosophy that most of what I’ll say will likely still apply.

Gatsby condenses data sources

This is the whole blender thing, and basically what it means is that it does not ultimately matter if the content you want to present is an image, a markdown file, comes from a third party API (GraphQL or REST), or a headless CMS. No matter the data type or source, everything gets thrown into the Gatsby blender and comes out of the other end as GraphQL data. This is the second deal-breaker for a lot of people: yes, if you hate GraphQL this is probably not the framework for you.

But you do need to keep in mind that the amount of knowledge required to make a Gatsby app is very, very minimal. Not only because all apps come with a GraphQL explorer which allows you to see your data and tinker with it without any knowledge of how to write queries, but also because this graph layer is purely there to ease your load. You won’t use crazy advanced GraphQL functionality here (even if you can), instead, most of your usage will boil down to going into the explorer, ticking checkboxes until you have the data you want, and copy/pasting the query in your page file. You don’t need to be an expert to start using Gatsby and you likely won’t need most of the more complex features of it.

Gatsby generates static files

We’ve gotten so used to SPAs being the norm that for some people this statement alone might be confusing: what even is a static website grandpa? A static website is a website whose pages are plain HTML (not generated by a dynamic back-end language like PHP), with fixed content, and which serves the same content to every user. This has a couple of pretty big upsides, but one of the absolute most visible of those is that a static website is incredibly fast, you click on a link and you already have the page in front of your eyes, like in the good old days of Web 1.0.

But when writing an application with Gatsby you won’t actually manually create HTML files and hardcode content in them, instead you will write your application like you would write any React application, and then Gatsby will “build” all possible permutations of all pages into a set of static files, bundle all the images, replace all the links, and so on, until Javascript is not needed. And the keyword here is needed because…

Gatsby is progressive enhancement done right

Once you have all those static files, this isn’t where the story ends. This is one of (if not the) biggest misconception about Gatsby: that because the end result is static files there are some things that you cannot do with it. That is absolutely not the case: if you visit one of the static pages that were built, it will still have a layer of Javascript on top of it with React, and Gatsby will then properly hydrate the state with the right information. But everything that can be made static, anything that isn’t dynamic to the end-user, was flattened. So what you get is a page that will work properly with Javascript turned off, that will display all the content it was meant to display, but then if you do want that extra layer of interactivity it’ll still be there.

Gatsby also uses the absolute best practices in terms of performance and optimization so you’ll be able to create modern, offline-first, progressive web apps that pass hands high tests like Lighthouse without having to even worry about it.

This doesn’t mean that Gatsby is suited for all applications: like all frameworks, there are situations it will handle more gracefully than others. But it does mean that there is no type of application that cannot be done with it.

How does Gatsby work?

Let’s imagine that I’m a photographer, and I want to build my portfolio with Gatsby. So far so good, you could probably write it entirely in plain HTML directly and it wouldn’t be that much of a challenge, but the catch is that all my photos are hosted on Flickr.

The first thing you would do is (of course) set up your application. Gatsby comes with a myriad of starter packs to help you develop specific types of applications (like blogging or e-commerce), but let’s imagine we want to do it vanilla. The framework has a dedicated CLI so we can do something like gatsby new and have a minimal setup ready to go.

As you can see, there isn’t much to it: in Gatsby, you create pages by simply creating files in the pages/ folder, so if you wanted to create an “About me” page you would pretty much create the following file:

import React from "react"
export default () => <div>About me</div>

And that’s it, you would now be able to go to /about-me and see your page. No complex routing layer or anything, WYSIWYG (sort of). You can of course also have dynamic routes with arguments by creating page templates but we’ll see that quickly later.

Collecting data

Now comes the interesting part: in order to add data to your application you will use plugins. The Gatsby ecosystem is incredibly furnished so there are plugins for everything and anything, but the ones that interest us most are source plugins. Plugins that get data from one place (local files, APIs, etc.), and pull it into your GraphQL API. Luckily for us, there already is a gatsby-source-flickr so we would install it and quickly configure it. To do this you would open the gatsby-config.js file you can see in the screenshot at the root, and add the plugin’s configuration there (again, in a way not dissimilar to Webpack loaders):

module.exports = {
  plugins: [
    {
      resolve: "gatsby-source-flickr",
      options: {
        api_key: "MY_FLICKR_API_KEY",
        user_id: "MY_FLICKR_USER_ID",
      },
    },
  ],
}

And… that’s it! If you now visit the /___graphql URL of your Gatsby website, you’ll be able to access the GraphQL explorer and without surprise, all our photos are there now. And not only can I freely explore all available fields, and their types or arguments, but I can start building the query I want from there without having to ever write anything.

I didn’t have to talk to Flickr, I didn’t have to learn how their API works, I didn’t have to learn how to use their SDK. I just said “I want some data from Flickr”, and now I have all the data from Flickr.

Once I have the query I want, all there is left to do is to copy/paste it into our index page as a query variable, and I’ll have access to the data as a simple prop:

import React from "react"
import { graphql } from "gatsby"

export default ({
  data: {
    allFlickrPhoto: { nodes: photos },
  },
}) => (
  <div>
    <h1>My Photos</h1>
    {photos.map(photo => (
      <figure key={photo.id}>
        <img src={photo.url_s} />
        <figcaption>{photo.title}</figcaption>
      </figure>
    ))}
  </div>
)

export const query = graphql`
  {
    allFlickrPhoto {
      nodes {
        id
        title
        url_s
      }
    }
  }
`

And boom we have our homepage:

Getting dynamic

This is a relatively simple example, but another great thing Gatsby is good at would be for example a personal blog. We can already yield something pretty powerful from a few simple steps:

1. Write some articles in Markdown

This is the easiest step, just create a folder named whatever in src and write some Markdown in it, you can even add some images if you want. Also add some front matter to it so we can use it as metadata later.

---
title: My Super Article
date: 2019-10-25
slug: my-super-article
---

# This is my super article

It is super because it has [links](http://google.com) and images

![](kitten.jpg)

and **bold text** and `inline code` and

```js
const blockCode = "And other cool stuff"
```

2. Install some plugins

Most of what you will do when working with a Gatsby application will be looking for (or writing) plugins, and those fall into two categories: sources and transformers. A source plugin will pull data into your GraphQL API, while a transformer will transform some of that data into a more usable/desirable format.

In our case, if we want the data from our Markdown files, we would need a source plugin that can read files (gatsby-source-filesystem), and a transformer plugin that transforms raw markdown into GraphQL data (gatsby-transformer-remark). The beauty is that transformers build on top of one another, so imagine you’re transforming a JSON file into data, if some of the JSON fields are relative paths to images, then the image plugin will kick in and also transform those, and so on.

The plugin that transforms images, in particular, is extremely powerful and will not only optimize your images but also create responsive variants of them, and allow you to manipulate them at the query level (serve a square fixed image in one place, a fluid responsive version in another). And because everything is centralized, it will work on any image, no matter if it’s on your disk, or comes from WordPress, or wherever.

Once everything is installed and configured, if we visit the GraphQL explorer we can see that we have all our blogposts as data, with very cool additional metadata like time to read or word count, and of course the final HTML. All we have to do is pick what we want and copy the query.

3. Create the pages

Now we’ll need to add pages dynamically to Gatsby, you do this in another special file called gatsby-node which provides hooks to manipulate and add data to your GraphQL API. In our case, we’ll use the createPages hook which provides some help to add pages to Gatsby. This is a very important file and will allow you to customize or expand on the data coming from plugins very easily through very simple functions provided by Gatsby.

exports.createPages = async ({ actions: { createPage }, graphql }) => {
  // Get data we need for the URLs from GraphQL
  const { data } = await graphql(`
    {
      allMarkdownRemark {
        nodes {
          frontmatter {
            slug
          }
        }
      }
    }
  `)

  data.allMarkdownRemark.nodes.forEach(({ frontmatter: { slug } }) => {
    // Call createPage for each page we want to add
    createPage({
      path: slug,
      component: require.resolve(`./src/templates/blogpost.js`),
      context: { slug },
    })
  })
}

We see I specify the component to use here, it can be located anywhere but I use templates by convention. The page is a very simple React component that will receive whats in context, so we can, for example, use it in our GraphQL query.

import React from "react";
import { graphql, Link } from "gatsby";

export default ({ data: { markdownRemark: blogpost } }) => (
  <div>
    <h1>{blogpost.frontmatter.title}</h1>
    <ul>
      <li>Published {blogpost.frontmatter.date}</li>
      <li>Time to read: {blogpost.timeToRead}mn</li>
      <li>{blogpost.wordCount.words} words</li>
    </ul>
    <h2>Table of Contents</h2>
    <div dangerouslySetInnerHTML={{ __html: blogpost.tableOfContents }} />
    <hr />
    <div dangerouslySetInnerHTML={{ __html: blogpost.html }} />
  </div>
);

export const query = graphql`
  query BlogpostQuery($slug: String) {
    markdownRemark(frontmatter: { slug: { eq: $slug } }) {
      frontmatter {
        title
        date(fromNow: true)
      }
      timeToRead
      tableOfContents
      wordCount {
        words
      }
      html
    }
  }
`;

Not only do the plugins pull data into Gatsby, but they also provide a lot of utilities to filter, group, format or sort the data so you receive only precisely the slice of information you want, however you want it. And sure enough, if we visit /my-super-article we now have our article.

The Future of Gatsby

This article is by no means meant to be a tutorial but I hope it demonstrates a bit Gatsby’s philosophy, and how it allows you to achieve incredibly powerful things with very little actual coding beyond React basics. And more importantly, how it allows you to unify data from many different sources into one cohesive result that ticks all the best practices boxes you could imagine. Think about how hard it is to make an offline-first, performant, progressive web app (PWA)… and now consider that you get all this by default in Gatsby out of the box without the need to really do anything.

And the best part is that because the output is just plain files, it is incredibly easy to deploy anywhere. And once it is it will never crash, it will never be offline because of a process error, you won’t have an uncaught undefined making the whole app unusable (unless you mess up your dynamic layer). It’s just HTML™, and it will work everywhere any time because you’re sifting your whole application to its most fundamental layers.

The official website has a nice Showcase section showing some of the most powerful things you can do with this framework: for example, there are some impressive fully-featured e-commerce websites that truly demonstrate how far you can take the notion of “static website” if you progressively enhance your pages with dynamic functionality.

So I hope I piqued your curiosity or at least got you interested in the idea. Not just of Gatsby but of this new wave of static website generators that go far beyond what the old guard like Jekyll used to offer. There is a very complete official tutorial on the website that demonstrates a lot of what it can do and I think it’s a great place to get started.

If you’re curious about the future of Gatsby and where it is headed, this article on their latest round of funding shows a bit what their vision of the product is, but I am personally very excited about it. Not just for the product itself, not just for Gatsby as a tool, but because it shows demand for a new way to make applications that radically rethinks what we learned during the SPA era. So even if this tool, in particular, seems too bloated or complex for you, I hope I at least made you interested in the ideas it propagates and maybe you will fall in love with the next step after Gatsby, whatever it ends up looking like.

Hire Maxime as a speaker?

Contact us
Maxime Fabre

Maxime Fabre

Maxime is madewithlove’s ‘French Connection’. He’s our (only) software engineer that speaks French fluently, thanks to being born and raised in the land of berets and baguettes. What else makes Maxime unique? His highly developed sense of how code should look and feel… which makes him a much appreciated colleague and ditto member of the Laravel/PHP community. As for his penchant for chocolate biscuits with soya sauce and mayonnaise, there’s no accounting for personal taste.