Barbarian Meets Coding
barbarianmeetscoding

WebDev, UX & a Pinch of Fantasy

13 minutes readgatsbyjsdraft

Gatsby.js

This blog in its current incarnation is built on Gatsby.js. I tinker on it now and then adding new features, upgrading it to latest versions, improving the user experience, making weird stuff, accomoddating it to the latest best practices but in between all this tinkering time goes by and I forget about how Gatsby.js which means that I’m re-learning how to Gatsby every 6 months or so.

So this article right here is going to be my refresher for the next time I decide to tinker with the blog and will focus first on fundamentals concepts and mental models about Gatsby and then about more specific details that’ll be useful for future Jaime. And as usual, you’re welcome to use it for your own learning, refreshment or problem-solving.

What is Gatsby?

When I started using Gatsby many years ago, Gatsby was a great framework for building static websites using modern front-end tooling based on React and GraphQL. Today, Gatsby is a complete web application platform with a great development experience which lets you build websites with great user experience and performance and which supports on-demand rendering and server-side rendering in addition to statically generated websites, and includes a hosting platform called Gatsby cloud.

At its core, Gatsby.js is a modern front-end framework that:

  • takes advantage of React to create a UI front-end based on components
  • can consume any type of data from markdown files in a filesystem to CMSes or databases
  • surfaces that data to your React front-end using the full power of GraphQL
  • has a large plugin ecosystem that lets you enrich your Gatsby.js with third-party services and useful features

Getting started

As it is common with most modern development tooling Gatsby.js has a cli tool that helps you crete and interact with Gatsby sites. The Gatsby CLI is powered by node.js and can be installed through npm:

npm install -g gatsby-cli

To get started creating a new Gatsby.js site use gatsby new:

$ gatsby new my-new-site

Follow the wizard to create your new site and select the options that make sense for you. Once you’re done use gatsby develop to start a development server so that you can see your new site. Now start changing things and see how they automatically appear in the browser.

Some useful CLI commands are:

# Get help. Shows all the commands available and what they do.
gatsby --help

# Create a new Gatsby website
#   - rootPath: where to create the website
#   - starter: which starter to use. A starter represents the skeleton
#              for a type of website e.g. a blog, a news site, an application, etc.
#              and it comes tailored to solve a specific use case.
gatsby new [rootPath] [starter]

# Start a development server locally
gatsby develop

# Build your site
gatsby build

# Serve a previously built site
gatsby serve

For a complete tutorial on how to setup everything you need to develop a Gatsby.js website take a look at the Gatsby docs.

Building a website in Gatsby.

Gatsby.js is a web framework designed to build highly performant web applications based on React and GraphQL. Using Gatsby.js you build a website as a collection of components that consume data from GraphQL that in turn obtains its data from a variety of data sources (oftentimes a collection of markdown pages from the filesystem but there is a large ecosystem of plugins that allow to use arbitrary data sources like CMS, databases or external API). At a high level one can think of Gatsby.js as a multilayered system where:

  1. We have a lowest layer of data or content (DATA LAYER)
  2. that is collected into a GraphQL schema for easy cosumption (API LAYER) normally during a build process
  3. which is then rendered in the browser using React (VIEW LAYER)

Although Gatsby.js lets you use React to create any component that you can imagine it also comes with a small number of components that ease the process of creating websites:

  • Page components: Any component that lives within src/pages in a Gatsby.js application becomes a page automatically with paths based on their filenames. For example:
    • src/pages/index.js becomes your-website.com (your main landing page)
    • src/pages/about.js becomes your-website.com/about
    • These components may or may not be bound to data.
  • Page Template components: Alternatively, you can create pages programmatically using “page template components”. These are react components that are wrappers around data obtained via GraphQL queries based on some data source (the filesystem or external APIs)
  • HTML components: src/html.js controls everything outside of the main page content. You can use this to change the overall structure of the site and add metadata to the head element. You normally don’t need this and can rely on the default src/html.js (that is automatically generated when not present). In my site I use layout components to control the structure of a site and React Helmet (via the gatsby-plugin-react-helmet plugin).
  • Non-page components: A non-page component is any smaller UI component that is embedded in a Gatsby.js website. Examples of these types of components could be a Header or Footer components shared among several pages, a Tag component, a BookReview component, etc. These component may be entirely controlled and provided with data by their parents, or they may be self-contained and declare exactly the data they need via GraphQL static queries or the useStaticQuery hook.
// These examples come from https://www.gatsbyjs.com/docs/conceptual/building-with-components/
// A page component
import React from "react"

function AboutPage(props) {
  return (
    <div className="about-container">
      <p>About me.</p>
    </div>
  )
}

export default AboutPage
// A page template component 
import React from "react"
import { graphql } from "gatsby"

// Here is the template component
function BlogPostTemplate(props) {
  const post = props.data.markdownRemark
  return (
    <div>
      <h1>{post.frontmatter.title}</h1>
      <div dangerouslySetInnerHTML={{ __html: post.html }} />
    </div>
  )
}

export default BlogPostTemplate

// And here is the query that retrieves the data necessary to 
// render the page template component
export const pageQuery = graphql`
  query($slug: String!) {
    markdownRemark(fields: { slug: { eq: $slug } }) {
      html
      frontmatter {
        title
      }
    }
  }
`

So in summary:

  • Page components live under src/pages and are automatically created and bound to a path matching their filename. A page component is a React component that represents a complete web page and may or may not be bound to some data.
  • Page template components …

TODO

Creating pages programmatically from Data

  1. File System Route API
  2. createPage API

Styling Gatsby websites

When you create a new website with Gastsby your project is automatically configured to style your website using CSS modules. CSS modules are CSS files where the styles and animations are scoped locally to that module by default. This is really useful when working with React because it embraces the self-contained nature of React componenets. That is, it helps you build components where the UI, the styles and the behavior are encapsulated in that component and don’t collide with that of other components.

Global styles

Global styles are normally applied through a Layout component. Within the layout component one can import the global styles like so:

import * as React from 'react'
// import global styles
import "styles.css"

const Layout = ({ children }) => {
  return (
    <section>{children}</section>
  )
}

export default Layout

There are also other alternatives detailed within the gatsby docs.

CSS Modules

Each CSS module is a regular CSS file that defines some styles using CSS classes:

/* colors.module.css */
.forest {
  color: green;
}

When writing a web application one consumes these CSS modules from your JavaScript components. This fits perfectly in React applications which are component-centric and naturally JS/JSX first:

import colors from "./colors.css";
// import { forest } from "./colors.css";

export theForest = () => {
  <p className={colors.forest}>
    In the forest
  </p>
}

A build step transforms the name of the class and ensures that it is unique across your web application. This happens whenever you run gatsby develop or gatsby build:

<p class="colors__forest__32fds12">
In the forest
</p>

As a result one can write CSS classes as if they are locally scoped and not care about the possibility of overwritting CSS styles or other unintended consequences.

Alternatives to CSS modules

Even tough Gatsby.js comes with built-in support for CSS modules it is really easy to use alternative styling approaches (normally by using a plugin). The Gatsby.js docs contain a lot of guides on how to setup different styling frameworks or whether to use vanilla CSS.

Using webfonts with Gatsby

Refer to this article in the Gatsby docs for more info: Using Web Fonts with Gatsby.

Querying data with GraphQL

Debugging GraphQL with GraphiQL

A really helpful way to debug your GraphQL queries is to experiment with the GraphQL UI (also known as GraphiQL or GraphQL integrated development environment) for your gatsby website that is hosted under localhost:8000/___graphql when running gatsby develop. GraphiQL allows you to explore your GraphQL instance by tinkering with its schema and writing arbitrary queries.

For more information about GraphiQL take a look at this GraphiQL guide on the Gatsby.js docs.

Images in Gatsby

Image resources

Gatsby design patterns

Layout components

In order to define the main structure and styles of a website in a reusable fashion Gatsby uses Layout components. These act as wrappers to the content of your website and are composed with other components using component composition in React.

You define a Layout component like any other react component:

import * as React from 'react'
import { Link } from 'gatsby'
import { NavBar } from '../navbar/navbar.js'
import { Footer } from '../footer/footer.js'
import { content } from './layout.module.css'

const Layout = ({ pageTitle, children }) => {
  return (
    <div>
      <title>{pageTitle}</title>
      <NavBar/>
      <main className={content}>
        <h1>{pageTitle}</h1>
        {children}
      </main>
      <Footer/>
    </div>
  )
}

export default Layout

And consume it from your page components or page template components:

import * as React from 'react'
import Layout from '../components/layout'

const HomePage = () => {
  return (
    <Layout pageTitle="Home Page">
      <p>This is my new site.</p>
    </Layout>
  )
}

export default IndexPage

Gatsby built-in components

Gatsby comes with a number of built-in React component that simplify building websites and provide advanced functionality:

  • The Link component
  • etc…

The Link component is a wrapper around the a HTML element that in addition to allow to link different parts of your site it enhances the UX of your Gatsby.js app by preloading the page corresponding to that link so when a user clicks on it the page can be rendered super fast. Learn more about Link in the Gatsby docs.

import * as React from 'react'
import { Link } from 'gatsby'

const HomePage = () => {
  return (
    <main>
      <h1>Hello World</h1>
      <p>This is my new website</p>
      <Link to="/about">About</Link>
    </main>
  )
}

export default IndexPage

Gatsby Versions

What’s new in Gatsby v4?

  • Performance improvements
  • In addition to static rendering Gatsby now supports SSR (Server-Side rendering) and DSG (Deferred Static Generation).

For more info take a look at Gatsby v4 release notes.

Errors and troubleshooting

Some useful error guides:

Fixing error “Error: Invalid Argument” when running gatsby build

UNHANDLED REJECTION Invalid argument

  Error: Invalid argument

  - read.js:19 LMDBStore.getString
    [barbarianmeetscoding]/[lmdb]/read.js:19:25

  - read.js:126 LMDBStore.get
    [barbarianmeetscoding]/[lmdb]/read.js:126:22

  - cache-lmdb.ts:69 GatsbyCacheLmdb.get
    [barbarianmeetscoding]/[gatsby]/src/utils/cache-lmdb.ts:69:25

  - index.js:382 cachifiedProcess
    [barbarianmeetscoding]/[gatsby-plugin-sharp]/index.js:382:30

  - index.js:396 base64
    [barbarianmeetscoding]/[gatsby-plugin-sharp]/index.js:396:18

  - index.js:573 fluid
    [barbarianmeetscoding]/[gatsby-plugin-sharp]/index.js:573:25


not finished createPages - 53.474s
not finished Running gatsby-plugin-sharp.IMAGE_PROCESSING jobs - 0.080s

I don’t know why this is happening. So far a possible workaround is to:

  1. gatsby clean
  2. gatsby develop
  3. gatsby build
  4. deploy built site

It looks as though gatsby build may use some assets been generated in gatsby develop that arent’ available if one just builds the site directly. It could be something with my ancient setup or maybe a bug. Should debug it and file an issues on the Githubs.

Resources


Jaime González García

Written by Jaime González García , dad, husband, software engineer, ux designer, amateur pixel artist, tinkerer and master of the arcane arts. You can also find him on Twitter jabbering about random stuff.Jaime González García