Chapter 1. Gatsby Fundamentals

Gatsby is an open source framework for building static sites, based on React. Commonly referred to as a static site generator (SSG), Gatsby is part of the Jamstack category of technologies, alongside other SSGs like Gridsome and JavaScript frameworks like Next.js, which also facilitates static site generation. Gatsby places particular emphasis on performance, scalability, and security, and it has a rich and growing ecosystem of plugins, themes, recipes, starters, and other contributed projects.

In this first chapter, we’ll get acquainted with Gatsby. Though Gatsby’s building blocks are pages and components, its internal data layer, made up of GraphQL and source plugins, acts as a bridge between data sources and the pages and components that are compiled at build time to produce a static site. Gatsby is built on React, so we’ll also take a look at some JavaScript and React concepts that are essential for Gatsby developers to understand. Finally, we’ll build our first Gatsby “Hello World” site, which will familiarize you with Gatsby’s developer tooling.

What Is Gatsby?

In short, Gatsby is a free and open source framework based on React for creating websites and web applications. But internally, its creator, Kyle Mathews, describes Gatsby as a complex and robust “web compiler”—a collection of building blocks that engage in data retrieval and rendering, page composition using components, linking across pages, and finally, compilation of components into a working static site.

In this section, we’ll take a bird’s-eye view of Gatsby’s overarching architecture to help us understand its major components. In addition, we’ll take a closer look at the three most important components of Gatsby: its basic building blocks (pages and components), the Gatsby data layer (GraphQL and source plugins), and the Gatsby ecosystem (plugins and themes that extend Gatsby’s functionality).

Gatsby Pages and Components

Gatsby leverages React components as its atomic unit for building websites. In other words, everything in Gatsby is built using components. To understand this more deeply, let’s take a look at the typical Gatsby project structure:

/
|-- /.cache
|-- /plugins
|-- /public
|-- /src
   |-- /pages
   |   |-- index.js
   |-- /templates
   |   |-- article.js
   |-- html.js
|-- /static
|-- gatsby-config.js
|-- gatsby-node.js
|-- gatsby-ssr.js
|-- gatsby-browser.js

For the purposes of illustrating Gatsby’s component-based architecture, let’s imagine that this Gatsby project consists of a home page (index.js) that links to individual pages that adhere to an article template (article.js). This article template renders the full text of each article into a consistent template for individual articles. To simplify this example even further, let’s assume that these articles are coming from an external database rather than from the local filesystem (something we’ll cover in Chapters 4 and 5).

Gatsby has four main types of components, the first three of which we can readily identify in this sample project structure:

Page components
Page components become full-fledged Gatsby pages. Any component that is placed under src/pages becomes a page automatically assigned the path suggested by its name. For instance, if you place a contact.js or contact.jsx file containing a React component in src/pages, it will eventually be available at <example.com>/contact/. In order for a file in src/pages to become a page, it must resolve to a string or React component.
Page template components
For relatively static pages, page components work well. But for pages that are templates, such as our article template, we need a reusable boilerplate according to which we’ll render each article. It would be prohibitive to write a page component for each individual article, so instead of doing that, we prefer to write a single page template component through which all article data will flow. Page templates are located under the src/templates directory.
The HTML component
There is only one HTML component: src/html.js. This file is responsible for everything outside the area of the page that Gatsby controls. For instance, you can modify metadata contained in the <head> element and add other markup. Customizing this file is optional, as Gatsby also has a default html.js that it uses as a fallback.
Non-page components
These are the typical in-page React components. They are sections of a page, such as a header, that are embedded in a larger page component, forming a hierarchy. As we’ll see later in the chapter, there are some non-page components that have greater importance, such as the layout component. I haven’t included the src/components directory in our sample Gatsby codebase, but this is where our non-page components would appear.

The three types of components that Gatsby developers will spend the most time on are page components, page template components, and non-page components. But how does Gatsby know what data to use to populate the properties, or props, in those components? That’s where GraphQL and Gatsby’s data layer, which we’ll explore in much more depth in Chapters 4 and 5, come in.

Gatsby’s Data Layer: GraphQL and Source Plugins

GraphQL is a query language that enables highly tailored queries. In the Representational State Transfer (REST) model, clients cannot define which data they receive from the server—that is a server-side responsibility. GraphQL takes a different approach, allowing clients to define their data requirements according to an arbitrary structure. The server then not only returns the needed data, but returns it according to the same structure the client sent in the request. This is the primary advantage of GraphQL.

Note

For a full overview of GraphQL and how it works in Gatsby, consult Chapter 4. For now, this conceptual understanding is sufficient to understand GraphQL’s role in Gatsby.

GraphQL is frequently used as a replacement or enhancement on top of APIs that use the REST paradigm, commonly known as RESTful APIs or REST APIs, which instead return data as defined by the server, not the client. In many content and commerce architectures, for example, GraphQL is used to retrieve data from third-party services and data providers such as databases and content management systems (CMSs) for use in an application. In these use cases, there is a GraphQL server that is constantly running, ready to respond to any incoming GraphQL query.

Gatsby, however, leverages GraphQL for an additional purpose: declarations of internal data requirements. Rather than consuming GraphQL from external sources as a client, Gatsby places GraphQL front-and-center to conduct data retrieval and handling at build time, not runtime. In other words, whereas many frameworks use GraphQL solely to consume data externally, Gatsby instead uses GraphQL internally so that many different data sources can be combined into a single GraphQL API.

A typical Gatsby site might pull from many different sources of data. The disparate data structures then need to be harmonized into a format that developers can easily consume in Gatsby. Gatsby might pull from an internal filesystem for data directly embedded in the Gatsby site, or it might perform API calls during the build process to a separate CMS or commerce platform. Gatsby could even pull from a GraphQL API to populate its own internal GraphQL API. And it can pull data from all of these sources at once into a single unified GraphQL API that makes the data easily accessible and straightforward to consume.

Each Gatsby component contains a GraphQL query that dictates the data that populates that component’s props. Though you can certainly declare data directly within the component, chances are you have data from other sources you want to pull into your Gatsby site. How does Gatsby achieve this?

In Gatsby, plugins are additional functionality that can be layered on top of an existing Gatsby site. Certain plugins might extend Gatsby’s core functionality, but there is one type of plugin that is particularly important due to its key role in the retrieval of data from external sources: source plugins.

In Gatsby, source plugins are Node.js packages that fetch data from its source, whatever that source may be. Gatsby offers many source plugins for a variety of systems that emit data, including APIs, databases, CMSs, commerce systems, and even local filesystems. For instance, gatsby-source-filesystem pulls data directly from the internal filesystem of Gatsby, whether it’s Markdown or something else. Meanwhile, gatsby-source-drupal and gatsby-source-contentful pull content from the Drupal and Contentful CMSs, respectively.

We’ll return to source plugins in short order, but first let’s take a look at the Gatsby ecosystem, which includes source plugins and a variety of other add-ons that improve the Gatsby developer experience.

The Gatsby Ecosystem

The Gatsby ecosystem encompasses all the community-contributed plugins and other modules that introduce new functionality to Gatsby. There are four types of projects in the Gatsby ecosystem:

Plugins
As we defined at a surface level in the previous section, plugins in Gatsby are Node.js packages that provide crucial functionality to Gatsby core. For instance, the gatsby-image plugin can be added to Gatsby sites by developers who need robust image handling. Gatsby plugins run the gamut from sitemap and RSS feed functionality to offline and search engine optimization (SEO) support.
Themes
A Gatsby theme is a kind of plugin that contains a gatsby-config.js file, just like a regular Gatsby site. This file provides arbitrarily defined configuration—prebuilt functionality, data sourcing in the form of source plugins, and interface code—to Gatsby sites. This means that a Gatsby site can become a Gatsby theme, which is installed as a package into another Gatsby site to extend it with reusable functionality.
Starters
In the Gatsby ecosystem, starters are boilerplate templates that developers can easily clone onto their own machines as a starting point for Gatsby development. Once modified by a developer, however, starters bear no ongoing relationship to their original state, unlike themes. Gatsby provides a long list of official starters for typical use cases, and it also has a rich process for building your own.
Recipes
New to Gatsby and still experimental, recipes are tools that are invoked in the Gatsby CLI to automate certain common responsibilities like creating pages, installing plugins, supporting TypeScript, and more. As of this writing, Gatsby has released roughly a dozen example recipes as well as information on how to write your own recipes.

We’ll explore each of these types of Gatsby ecosystem projects, but now that you’re equipped with a basic understanding of what Gatsby is, you may be wondering: Why should I use Gatsby? What’s in it for me?

Why Gatsby?

In this section, we’ll analyze some of the unique advantages and rationales that motivate developers to choose Gatsby for their next website projects. Gatsby has gained a reputation in the JavaScript and Jamstack communities for its focus on four key pillars: performance, accessibility, developer experience, and security.

Performance

Many websites today remain primarily server-driven, which means servers respond to each individual request issued by a browser. Gatsby, however, emphasizes performance enhancements at every level, including payload optimization (minimizing the size of the file sent down the wire to the browser) and delivery optimization (minimizing the time it takes to get there).

Here are the four primary means by which Gatsby enhances performance:

Static site delivery
When you perform a Gatsby build, the result is a collection of static assets that can be uploaded to any content delivery network (CDN), located in the public folder in the Gatsby project root. This means that Gatsby sites primarily consist of static HTML, which loads quickly in a browser. Only then is further client-side JavaScript, such as that provided by React, initialized.
Build-time compilation
Gatsby engages in build-time compilation to produce static files, rather than runtime compilation, which is much more granular and might render only a single page. Instead, build-time compilation renders a full set of static pages—this means requests to external data sources never introduce additional latency to the overall delivery time, because the result is a set of static files with data prepopulated, not a page that needs to retrieve and render data upon request. In this way, build-time compilation limits the amount of work servers usually need to perform for web applications that are chattier. Gatsby can leverage both build-time and runtime compilation, depending on which is more optimal for performance.
Payload optimization
Gatsby works hard to limit the size of the eventual payload delivered to users by reducing the sizes of images and JavaScript files, delaying the loading of any images below the fold (the unseen part of the browser viewport upon page load), and inlining CSS where necessary. Gatsby also includes automated route-based code splitting (so only code for a needed route is loaded), background prefetching (so assets can load in the background), and lazy loading of assets that aren’t immediately needed.
Delivery optimization
Gatsby sites are optimized to be served from a CDN, which lends itself to faster delivery of deployed code. Depending on your requirements, this model can be a substantial improvement over the historical paradigm, in which every incoming request from a browser would need to return to the origin server and database (though extensive caching can mitigate this on non-Gatsby sites).

Thanks to static site delivery and build-time compilation, Gatsby sites consist mostly of HTML rather than a slew of JavaScript files. And thanks to payload optimization and delivery optimization, Gatsby sites load quickly at the edge and stay small.

Accessibility

Once a fringe concern, accessibility is becoming an important consideration for businesses and organizations across the market. Single-page JavaScript applications have until recently been notorious for their poor support for assistive technologies and lack of consideration for different access needs. Gatsby treats accessibility as a first-class citizen by focusing on providing accessible markup and accessible routing, in addition to delivering static HTML rather than highly dynamic JavaScript:

Accessible markup
Gatsby provides by default the eslint-plugin-jsx-a11y package, which is an accessibility linting tool for code. This package looks for missing alternative text for images and correct usage of Accessible Rich Internet Applications (ARIA) properties, among other potential issues.
Accessible routing
Most JavaScript applications use dynamic page navigation to allow a user to click a link and see the page rerender immediately rather than incurring an additional page load by the browser. This dynamic routing, however, can be impossible for disabled users to use with the same convenience as normal hyperlinks. Gatsby ships with the @reach/router library, which supports scroll restoration and accessible dynamic navigation, and it also ensures that Gatsby links function accessibly.
Note

Web accessibility is becoming an increasingly pressing problem for many organizations. For more information about ARIA, consult the Web Accessibility Initiative’s website. Gatsby has consistently expressed a commitment to better accessibility in its own ecosystem, including the publication of an accessibility statement on its website.

Developer Experience

To make development as seamless as possible, and to enable developers to save time when building websites, Gatsby offers a range of developer experience features (especially for repetitive tasks), including:

Scaffolding with starters and minimal configuration
Gatsby starters allow for almost zero configuration and provide a fully scaffolded directory structure. All starters are fully functional Gatsby sites and can be immediately deployed. Though it’s possible to create a Gatsby site from scratch, it’s highly recommended to use one of the existing official starters, and that’s the approach we take in this book.
Local development environment with hot reloading
Gatsby provides a local development environment with hot reloading whenever code changes are saved. This facilitates a rapid feedback loop, where developers see their modifications immediately reflected in their working site. We’ll return to Gatsby’s local development environment in “Creating Your First Gatsby Site”.
GraphiQL and GraphQL Explorer
In addition to providing GraphQL, Gatsby also provides, out of the box, developer tools that aid those who need to consume data through GraphQL. GraphiQL, a GUI that provides debugging, and GraphQL Explorer, a schema explorer for GraphQL, are both packaged with Gatsby by default.
Built-in linting and testing
Gatsby also includes in its core package a variety of built-in tests and linting processes that allow you to check for concerns such as adherence to coding standards, loyalty to accessibility rules, and other issues of quality assurance that emerge during the development process.
Continuous integration and continuous deployment (CI/CD)
Finally, Gatsby integrates gracefully with a variety of infrastructure providers that offer rich capabilities for continuous integration (CI) and continuous deployment (CD). Some of the most common hosts for Gatsby include Netlify, Vercel, and Gatsby Cloud.

Security

These days, security is one of the most essential concerns plaguing traditional websites. Many websites still leverage monolithic architectures whose systems may be vulnerable to unmitigated access by attackers, especially when there is no protection between layers like databases and authentication providers. Others require actively running databases and servers, which can facilitate another vector for vulnerabilities if not architected carefully.

Because Gatsby delivers its sites as static HTML and not as dynamic code that includes information about the APIs or data sources it is consuming from, Gatsby automatically obfuscates external data sources, protecting them from unwanted eyes. For content and commerce system maintainers, this can be particularly useful, because those data sources can be shut down whenever they aren’t needed by an ongoing Gatsby build or an editor who wishes to update data. Security is a multifaceted topic that we will return to throughout this book, but Gatsby’s static site delivery ensures a rock-solid firewall between your markup and your data sources.

Now that you have a sense of some of the motivations behind why so many developers choose Gatsby, let’s contextualize it within the larger landscape of architectural paradigms and JavaScript development with React.

While Gatsby is a standalone framework for building highly performant websites and web applications, it is part of a larger trend toward web frameworks that prize build-time rather than runtime compilation, serverless over server-dependent architectures, and performance optimizations across the stack. In the next section, we’ll look at how Gatsby fits into the larger contexts of Jamstack architectures, JavaScript, and React.

Note

If you already understand the background behind Gatsby and the Jamstack and wish to get started immediately with code, you can skip to “Getting Going with Gatsby”.

Gatsby and the Jamstack

We’ve covered the architectural underpinnings of why organizations have migrated to architectures that are less monolithic and more decoupled than before. But to understand why developers and engineering teams have made similar moves, we need to explore the Jamstack (also written JAMstack), an architectural paradigm that juggles JavaScript, APIs, and static markup to facilitate high-performance websites.

In this section, we’ll first cover SSGs, which presaged the Jamstack by providing a build-time means of website deployment as opposed to runtime. Then, we’ll cover distributed content and commerce, a contemporaneous paradigm shift occurring in content and commerce architectures. Finally, we’ll combine SSGs and content and commerce architectures to define and outline what the Jamstack is and how Gatsby fits into the Jamstack landscape.

Static Site Generators

At its most basic level, Gatsby is an SSG. SSGs are tools that generate static HTML files based on a template and data furnished by an external database or other source (such as a spreadsheet). Given this data input, they then apply styles and templates, which can be written in templating languages like Markdown, Liquid, or others, to the data based on logic written by the developer.

Unlike typical dynamic web applications, which usually require an actively running server and execute at runtime, SSGs yield a series of static files and assets that don’t require anything more than a filesystem on a web server. Because they’re run manually, typically through a terminal command, they execute at build time, which means that they only run when the state of the static assets needs updating.

The first wave of SSGs were primarily rooted in server-side technologies to perform static site generation and processing of data into templates. For instance, though the still-popular Jekyll and Hugo are written in server-only languages like Ruby and Go, other older SSGs, like Metalsmith, are written in Node.js and JavaScript. Though the first generation of SSGs were optimal for small websites with limited content and dynamism, they lacked entirely the interactivity found in JavaScript applications.

In recent years, a second generation of SSGs has emerged, particularly in the JavaScript ecosystem. These differ considerably from older tools like Jekyll and Hugo in that they connect static files to dynamic client-side JavaScript that injects asynchronous rendering and other mainstays of interactive JavaScript into normally unchanging static sites. Because they rely on the client-side capabilities of JavaScript frameworks, rather than being associated with server-side languages, these SSGs link themselves with JavaScript frameworks. Gatsby and Next.js, for example, fall into the category of React-powered SSGs, whereas Gridsome and Nuxt.js are part of the Vue ecosystem.

This brings us to the first of several definitions of the framework we cover in this book: Gatsby is first and foremost an SSG based on React. But to examine precisely why Gatsby emerged in the first place and the reasons behind its success, we need to zoom out to a much wider perspective on how Gatsby resolves many persistent issues surrounding content and commerce website implementations: through distributed content and commerce and through the Jamstack.

Distributed Content and Commerce

In recent years, thanks to the emergence of frameworks like Gatsby, a new architectural paradigm has begun to emerge in the form of distributed content and commerce (the content variant of this is sometimes referred to as the “content mesh”).

One of the most important issues facing any content and commerce implementation is the availability of third-party integrations and plugins or extensions that make those third-party integrations available to a website implementation. Many of these plugins handle small concerns important to content and commerce, such as a search tool or a checkout system. During the era of monolithic content and commerce, most plugin ecosystems were tightly contained, as shown in Figure 1-1. WordPress plugins, for instance, were never interchangeable with Drupal modules.

Figure 1-1. Monolithic content and commerce systems have closed marketplaces for plugins that aren’t interchangeable with other systems

Another reason for the emergence of distributed content and commerce architectures was the increasing concern about the long-term maintenance of these plugins. If a checkout system maintainer decides to leave their open source project behind or to delist their plugin from a closed-source marketplace, the resulting disruption has an outsized impact on the ability of a user of that plugin to continue to make a checkout system available, especially if the plugin is proprietary. Often, the only solution is to rebuild the plugin from scratch or to architect a custom implementation.

In the last several years, as seen in Figure 1-2, interest has grown among developers in interchangeable in-page services that they can swap out as newer services emerge. A new class of startups offers in-page widgets and third-party services that are agnostic to content and commerce ecosystems, meaning that they can be used in any website implementation (though they still present long-term maintenance issues, in that they can also cease to exist). These companies include services like Algolia, which provides search features; Snipcart, which provides a shopping cart and checkout process; and Typeform, which offers easily managed webforms.

Figure 1-2. A typical distributed CMS architecture, showing Gatsby containing a variety of interchangeable in-page services from third-party providers, thus preventing ecosystem lock-in

Today, a content and commerce implementation might need to pull data from multiple sources in order to populate a website, with backend data providers being added and removed behind the scenes. Moreover, a content and commerce implementation might require a multifaceted combination of interchangeable in-page services that can be switched out as developers see fit. All this points to a more distributed future for content and commerce architectures that permits developers to leverage a diverse array of data sources, and just as diverse a range of third-party plugins and services.

The Jamstack

Let’s discuss the Jamstack in isolation before we turn to what makes Jamstack architectures so different from other (namely monolithic and decoupled) architectures.

Jamstack frameworks and methodologies introduce the notion of build-time rendering. In Jamstack architectures, an SSG is responsible for performing the rendering once a build begins. During a build, the SSG’s JavaScript is responsible for retrieving data from APIs (such as content and commerce providers) and rendering that data into static markup. The result of the build is a collection of static assets that can be uploaded to any filesystem, rather than a constantly running database, web server, or server-side application.

Thereafter, developers can choose to place those statically generated assets on a CDN to ensure rapid delivery at the edge (i.e., as close as possible geographically to the user’s location) and any required caching.

Differences between Jamstack and other architectures

On the other hand, traditional architectures—especially monolithic and many decoupled content and commerce implementations—perform runtime rendering, which occurs only when a user requests a website page. Rather than a build, an underlying database, constantly humming along, receives a request and provides the necessary data to another actively running server-side application, which is then deployed to a constantly running web server. This undesirable behavior is mitigated in most implementations through aggressive caching and a CDN.

Before the emergence of Jamstack architectures, all server-side JavaScript applications leveraged a constantly running Node.js web server. And all monolithic content and commerce architectures follow this pattern. As for decoupled content and commerce architectures, it depends on whether build-time or runtime rendering is occurring. Though distributed content and commerce architectures lend themselves most favorably to build-time rendering, it’s possible to implement runtime rendering as well.

The most important disadvantage of runtime rendering is that it produces only individual pages that are delivered on the wire. These pages can certainly be placed on a CDN and be aggressively cached, but each time a new page is requested that is unavailable in the CDN or in cached form, runtime rendering needs to occur all over again.

Serverless infrastructure

Today, there are a wide range of infrastructure providers that provide build-time rendering and CDN support for Jamstack implementations, especially those in Gatsby. Collectively, these infrastructure providers are known as serverless because they do not rely on constantly running server instances to power functionality like runtime rendering, which doesn’t occur in Jamstack implementations. Serverless hosts typically require three elements for a Jamstack deployment to succeed:

  • A static site codebase, typically a repository in a source control system such as GitHub

  • A build command, which triggers the build and rendering process conducted by the serverless host

  • A deployment target, representing the URL where the statically generated assets will be placed

One of the most commonly used serverless infrastructure providers is Netlify. Others include Vercel (formerly Zeit), the creator of the Next.js framework; Amazon’s AWS Amplify; and Gatsby Cloud, which specializes in Gatsby implementations.

Now that you have an understanding of some of the underpinnings of the Jamstack, let’s take a look at how Gatsby fits in the larger world of JavaScript and how it leverages JavaScript and React, a JavaScript library for building UIs.

JavaScript in Gatsby

A comprehensive overview of JavaScript’s core concepts and history is outside the scope of this book, but let’s highlight a few of the most salient concepts that are essential to working with Gatsby as a developer.

Warning

This section is not intended as an end-to-end guide to JavaScript. It is geared toward developers who already have some experience with the language, but before the emergence of server-side JavaScript. For a more holistic approach to learning JavaScript, consult David Flanagan’s JavaScript: The Definitive Guide, 7th edition (O’Reilly) or Kyle Simpson’s You Don’t Know JavaScript.

JavaScript is one of only two programming languages that can be executed in a web browser (the other, which as of this writing remains without widespread support, is WebAssembly). It’s characterized by its imperative orientation, weak typing, prototype-based inheritance (though class-based inheritance is possible in newer iterations of JavaScript), and functional nature.

In the earliest years of JavaScript’s history, it was used primarily to decorate static web pages with limited interactivity and asynchronous rendering. Today, however, JavaScript is among the most important languages in web development, and those who have worked with JavaScript in past decades, but not this one, will find that many aspects of the JavaScript developer experience have changed considerably—including CLIs and how modern JavaScript displays modularity.

Command-Line Interfaces

CLIs are text-based interfaces that developers use to interact with filesystems on their local machines and to provide tooling for application development, dependency handling, and deployment. Though the earliest CLIs were written in low-level languages such as Shell or Bash, today, many of these interfaces are written in JavaScript through Node.js (or still other languages like Rust and Go).

Node.js, the JavaScript runtime used for server-side rendering (SSR) and universal JavaScript approaches, isn’t just useful for JavaScript that needs to be executed outside the browser environment. It’s also useful for JavaScript that needs to be executed on computers to manipulate files and perform other actions that are important to application development. For instance, many JavaScript applications require the download of many dependencies, often third-party libraries that are maintained by other developers in the JavaScript space.

Today, JavaScript dependencies are downloaded and managed by package managers that facilitate the retrieval of dependency libraries and their interpolation into an application that needs them. The most popular package managers are Node Package Manager (NPM) and Yarn, which each provide a vast collection of packages. Though many of these packages can be dependencies that become small portions of application code, other packages contain CLIs that can be installed globally and whose commands can be invoked anywhere in the local filesystem.

The Gatsby CLI, which we cover in “Getting Going with Gatsby”, is an example of a JavaScript-driven CLI that is typically installed globally by invoking the command:

$ npm install -g gatsby-cli

NPM and Yarn are the most popular approaches to both dependency management and CLI installation in the JavaScript world.

Modular JavaScript

JavaScript today exhibits considerable modularity, which wasn’t the case when the language was first introduced in the 1990s. At the time, most JavaScript code was written either in a single embedded JavaScript file, which might have a colossal file size, or in multiple JavaScript files embedded in succession, indicating an order of execution. As JavaScript applications became more complex in the late 2000s and early 2010s, many developers recognized that a better approach to modularity was necessary.

ES6 (ECMAScript 2015) was the first version of JavaScript to introduce the concept of modules natively. In short, modules are isolated JavaScript files that have relationships to other JavaScript files in the application by means of exports and imports. Consider two JavaScript files, one providing a module and the other consuming that module (this example is adapted from Exploring ES6 by Axel Rauschmayer). Here’s the first one:

// lib.js
export const sqrt = Math.sqrt
export function sq(x) {
  return x * x
}
export function diag(x, y) {
  return sqrt(sq(x) + sq(y))
}

If this is a library that we want to import as a module into another application, we can either import only the exported functions that we need by referring to them by name:

// app.js
import { sq, diag } from 'lib'
console.log(sq(5))
// 25
console.log(diag(4, 3))
// 5

Or we can import the entire module and refer to it under the namespace we assign:

// app.js
import * as lib from 'lib'
console.log(lib.sq(5))
// 25
console.log(lib.diag(4, 3))
// 5

Many JavaScript frameworks and JavaScript applications use modules to pass values, functions, and classes between one another so they can be invoked and used in other areas of the application. Gatsby is no exception, and neither is React, a declarative library in JavaScript for writing component-driven UIs. In the next section, we’ll work through a rapid-fire introduction to the core React concepts you need to know to be successful with Gatsby and contextualize Gatsby within the larger React ecosystem.

Note

This was but a short introduction to ES6 modules and modular JavaScript in general; the full range of module syntax and approaches is outside the scope of this book. For a more comprehensive overview, I recommend Exploring ES6 by Axel Rauschmayer or the Mozilla Developer Network’s guide on modules.

React in Gatsby

React defines itself as a JavaScript library for building UIs, but it is perhaps better described as a declarative, component-based approach to writing interactive UIs. Originally created by Facebook, React is now one of the most popular libraries for building JavaScript applications in existence. Gatsby is built on top of React and inherits many of its concepts.

Providing a comprehensive overview of React would be impossible here, but throughout the book, we will deal with many React concepts. While there is much more to discover when it comes to React, the most important ideas to understand for now are declarative rendering, co-location of rendering and logic in React components, and passing values between React components by using React props.

Warning

This section is not intended as a full end-to-end guide to React. For a more holistic approach to learning React, consult Learning React, 2nd edition, by Alex Banks and Eve Porcello (O’Reilly).

Declarative Rendering with JSX

JSX is the name given to a syntax extension that most React developers use to perform rendering in React. Consider, for instance, this “Hello World” example:

const el = <h1>Hello, world!</h1>

Though JSX is similar in appearance to HTML or a templating language, it is actually interpreted as JavaScript syntax by React. When executed, this code will construct an HTML element and prepare it for insertion into the Document Object Model (DOM). The actual insertion looks like this:

const el = <h1>Hello, world!</h1>

ReactDOM.render(
  el,
  document.getElementById('root')
)
Note

Most React applications, before any rendering has taken place, consist solely of a <div id="root"></div> within the <body> element. React will render any elements declared in JSX within that HTML element.

JSX also allows for expressions within element declarations, unlike HTML:

const el = 
  <h1>Hello, world! The current time is {Date().toLocaleString()}.</h1>

ReactDOM.render(
  el,
  document.getElementById('root')
)

Note that certain HTML attributes need to be named differently in JSX due to conflicts with existing keywords in JavaScript, or due to React’s stylistic preference for camelCase:

const el = <div tabIndex="0"></div>
const el = <div className="hero-image"></div>

You can’t use double quotes in JSX (as they are interpreted differently by JavaScript), so all string interpolation into JSX attributes should occur within curly braces:

const el = <img src={article.heroImageUrl} />

JSX can also allow for nested elements within others. For multiline element declarations, it’s best to surround them in parentheses so JavaScript interprets them as expressions:

const el = (
  <div className="hero-image">
    <img src={article.heroImageUrl} />
  </div>
)

Let’s see an example of how Babel, a compiler for JavaScript that can compile JSX into raw JavaScript, compiles JSX into JavaScript. The following code is equivalent to the code in the previous example:

const el = React.createElement(
  "div",
  {
    className: "hero-image"
  },
  React.createElement(
    "img",
    {
      src: article.heroImageUrl
    }
  )
);

Now that you have an understanding of how React utilizes JSX to perform declarative rendering, we can turn our attention to React’s component-driven approach to UI development.

React Components

React displays a clear preference for co-location of two primary concerns that are important to application development: markup and logic. Unlike many historical approaches, which separate markup and logic arbitrarily into distinct files, React instead operates on components that contain both the rendering code and the data management logic in order to promote co-locating both responsibilities in a single file. For this reason, the declarative rendering we saw in the previous section is typically accompanied in each file by logic that governs the data to be rendered.

You can define a component either as a function or as a class:

// Function component
function HeroImage(props) {
  return (
    <div className="hero-image">
      <img src={props.heroImageUrl} />
    </div>
  )
}

// Class component
class HeroImage extends React.Component {
  render() {
    return (
      <div className="hero-image">
        <img src={this.props.heroImageUrl} />
      </div>
    )
  }
}

Up until now, we’ve only employed standard HTML elements to define the internal declarative rendering that occurs within a component. But React allows for components to be reused after they are defined as new JSX elements. When React comes across a JSX element that is equivalent to a component rather than an existing HTML element, it will pass the attributes and children contained inside that element declaration to the component as an object known in React parlance as props (short for “properties”).

React Props

Consider the following example, where we have replaced the URL for the article’s hero image with a new value contained within the props as we declare the element. Here, the resulting HTML is <img src="https://img.example.com/hero.jpg" />:

class HeroImage extends React.Component {
  render() {
    return <img src={this.props.src} />
  }
}

const el = <HeroImage src="https://img.example.com/hero.jpg" />

ReactDOM.render(
  el,
  document.getElementById('root')
)

Most new React applications contain a single root-level App component that represents the entire application as well as the components contained therein. In this example, we create a new overarching App component that contains the other component we’ve just created:

class HeroImage extends React.Component {
  render() {
    return <img src={this.props.src} />
  }
}

class App extends React.Component {
  render() {
    return <HeroImage src="https://img.example.com/hero.jpg" />
  }
)

ReactDOM.render(
  <App />,
  document.getElementById('root')
)

Note that in React, props are read-only within components, regardless of whether they are defined as a function or a class. React has a strict rule that applies to all props: “All React components must act like pure functions with respect to their props.” In other words, a component must not modify its own props; it must only use them to return a predictable result. Pure functions never modify their inputs.

Note

Some of the React syntax we’ve seen so far, including JSX and React’s component-driven approach, bears quite a bit of resemblance to Web Components and custom elements. However, JSX and Web Components should not be conflated with one another as they are fundamentally incompatible. Web Components is now available in all modern browsers, but React requires the full scope of the React library to function properly. As of this writing, React facilitates the use of React in Web Components and vice versa, but they cannot be merged.

As new React concepts surface during our deep examination of Gatsby concepts, we’ll explore them in the context of Gatsby rather than in isolation. Gatsby employs React extensively to power its underpinnings in terms of component and props handling. Now, let’s build our first Gatsby site!

Getting Going with Gatsby

Now that you have a full understanding of how Gatsby fits into the worlds of JavaScript and React, it’s time to get started with our first Gatsby site. In this section, we’ll focus solely on setting up a local development environment for Gatsby and creating a Gatsby site based on a starter, which as you saw earlier is Gatsby parlance for a boilerplate site template.

The Command Line

Like many other web development tools, Gatsby makes extensive use of the command line, the text-based interface that allows developers to manipulate files and folders within a computer rather than through graphical means. Also known as the terminal, the command line is the primary means of interacting with the local development environment that Gatsby provides as a foundation for implementation.

To find the command line on your local machine:

  • On macOS, open the Utilities folder in Applications. Open the Terminal application.

  • On Windows 10, click the Start button and type cmd. Then, select Command Prompt from the returned search results.

  • On Linux, open the application menu on the desktop, type “Terminal” to search for applications, and select Terminal.

Note

If you’re already familiar with the command line and have Node.js and Git installed, you can proceed to the next section.

On all three command lines, you can execute a command by typing the command (such as pwd, which prints the path to the current working directory into the terminal, or cd, which changes directories from where you executed the command to dive into a designated directory) and hitting the Enter key.

Installing the Gatsby CLI

The Gatsby CLI is the primary instrument developers can use to interact with Gatsby sites. It’s a tool that can scaffold and spin up Gatsby sites very quickly, and it contains various commands that are useful for developing Gatsby sites. It’s published as an NPM package, so the Gatsby CLI can be installed on any computer with Node.js installed.

To install the Gatsby CLI, execute the following NPM command. It is highly recommended to install Gatsby CLI globally using the -g flag so you can scaffold new Gatsby sites anywhere in your local machine’s filesystem:

$ npm install -g gatsby-cli
Tip

The first time you install the Gatsby CLI, a message will appear informing you about Gatsby telemetry, which collects anonymous usage data about Gatsby commands to guide future development of the framework. To avoid the gathering of telemetry data, opt out when the message appears using the following command:

$ gatsby telemetry --disable

To see all available executable commands represented in the Gatsby CLI, run the help command:

$ gatsby --help
Tip

Some computers, especially work computers, restrict the ability for users to install NPM packages globally using the -g flag and to impersonate a root user using the sudo command. The Gatsby documentation recommends consulting one of the following guides to resolve permission issues that may arise due to how computers are configured:

Now that you’ve successfully executed your first Gatsby command, you’re ready to create your first Gatsby site using the Gatsby CLI. Instead of building the site from scratch, which can be time-consuming, we’ll start with Gatsby’s “Hello World” starter.

Creating Your First Gatsby Site

Gatsby starters are boilerplate templates that contain partially implemented Gatsby sites with some initial configuration. Starters are designed to make it as painless and easy as possible to create a new site for a particular use case. The bare-bones “Hello World” starter contains the base-level requirements for a typical Gatsby site.

To create a new site based on the Gatsby “Hello World” starter, open your terminal and run the gatsby new command, which creates a new project in the directory you specify immediately afterward (if you execute the command without any arguments, the Gatsby CLI will open an interactive shell where you can supply certain parameters):

$ gatsby new hello-world \
  https://github.com/gatsbyjs/gatsby-starter-hello-world

You can supply an arbitrary directory name, since if it doesn’t exist, the Gatsby CLI will go ahead and create the directory for you—for example:

$ gatsby new my-new-gatsby-site \
  https://github.com/gatsbyjs/gatsby-starter-hello-world

The final portion of the command beginning with https:// is the URL at which the starter code is housed. Gatsby uses GitHub to manage its starter codebase repositories.

Now, you can change into the directory in which the “Hello World” starter was downloaded:

$ cd hello-world

If you gave the directory a different name, use that instead, as in:

$ cd my-new-gatsby-site

To see the files and directories encompassing the “Hello World” starter, you can issue the list command (ls). By executing the following command within the directory you’ve just changed into, you’ll be able to see what the root folder of a typical Gatsby site looks like. The -la flag instructs the terminal to show all files, including those whose names begin with a period (.), and certain details about them:

$ ls -la

The output of this command is a list of the files and directories in the project:

total 1032
drwxr-xr-x   14 prestonso    staff     448 May 16 12:37 .
drwxr-xr-x    6 prestonso    staff     192 May 16 12:37 ..
drwxr-xr-x   12 prestonso    staff     384 May 16 12:37 .git
-rw-r--r--    1 prestonso    staff     974 May 16 12:37 .gitignore
-rw-r--r--    1 prestonso    staff      45 May 16 12:37 .prettierignore
-rw-r--r--    1 prestonso    staff      46 May 16 12:37 .prettierrc
-rw-r--r--    1 prestonso    staff     675 May 16 12:37 LICENSE
-rw-r--r--    1 prestonso    staff    5866 May 16 12:37 README.md
-rw-r--r--    1 prestonso    staff     177 May 16 12:37 gatsby-config.js
drwxr-xr-x 1051 prestonso    staff   33632 May 16 12:37 node_modules
-rw-r--r--    1 prestonso    staff     822 May 16 12:37 package.json
drwxr-xr-x    3 prestonso    staff      96 May 16 12:37 src
drwxr-xr-x    3 prestonso    staff      96 May 16 12:37 static
-rw-r--r--    1 prestonso    staff  492120 May 16 12:37 yarn.lock

But we’re not done! Simply seeing a list of the files and directories of a Gatsby site isn’t enough—we want to see it in a browser. However, to view our Gatsby site in a browser environment when it’s still offline, we’ll need to spin up a local development server. We’ll do that next.

Starting a Development Server

To view a Gatsby site that isn’t yet online in a web browser, we need to find some way for the browser to be able to access that Gatsby site. This means that we need to set up a local development server that can mimic a website that’s online and can approximate as closely as possible the experience of visiting our Gatsby site in a browser.

The Gatsby CLI contains a development mode that starts up a new local development server on your behalf. To enter development mode and start the local development server, execute the following command in the root directory of your Gatsby site:

$ gatsby develop

As part of the messages the terminal will display from the Gatsby CLI, you will see a URL such as http://localhost:8000. Here, localhost means that we are accessing the Gatsby “Hello World” site we scaffolded on our local machine rather than fetching it from an external URL online somewhere. This means that we don’t need an internet connection to access localhost URLs.

Open the browser of your choice and navigate to http://localhost:8000 or the URL indicated in your terminal. There, you’ll see a message saying “Hello world!” Nice work—you’ve just built your first Gatsby site, as you can see in Figure 1-3!

Figure 1-3. Our first Gatsby site! Note the localhost URL and the “Hello world!” text.

Back in the terminal, notice that gatsby develop is still running; the command has not terminated, as shown in Figure 1-4. This is to enable you to continue using the local development server for as long as needed. The Gatsby CLI supports hot reloading, which is a feature that enables Gatsby sites to update immediately when you modify code. For as long as gatsby develop is running, the local development server will be available at the localhost URL, and the vast majority of changes you make to the code will be reflected immediately in the browser.

Figure 1-4. Our local development environment remains running until we decide to shut it down, so any code changes are reflected immediately in the browser

To see hot reloading in action, try opening src/pages/index.js and modifying the “Hello world!” text to something else. If you save your file while gatsby develop is still running, you’ll see the change take effect immediately without having to incur a browser reload!

To stop running the development server, in the terminal window, type Ctrl-C (hold down the Control key and press C). This will terminate the command, shut down the local development server, and make the site inaccessible through the browser. To restart the local development server, execute gatsby develop again.

Creating a Production Build

Though we’ve built our first Gatsby site, our work isn’t done yet. So far, we’ve managed to get a website running locally on a development server, but that doesn’t mean that our website is online. For that, we need to deploy our Gatsby site to a production environment, a publicly accessible web server where anyone can access the site. In addition, we need to perform a Gatsby build, which makes a Gatsby site production-ready and as small as possible so there aren’t any performance issues down the line.

Creating a production build means converting a development-ready Gatsby site into a production-ready static Gatsby site that consists of static HTML, CSS, JavaScript, and static assets such as images. To create a production Gatsby build, run the following command in the root of your Gatsby site directory:

$ gatsby build

This command will deposit the built and processed static files, ready for deployment to a production environment, into the public directory of your Gatsby codebase.

Serving the Production Build Locally

Now, we can either deploy this static site to an infrastructure provider of our choosing, or deploy the production Gatsby site locally so we can view it in a browser. To view your production site locally, run the following command, which spins up a local development server:

$ gatsby serve

The site will be viewable at https://localhost:9000 (note the difference from gatsby develop’s local development server), unless you’re already using that port for something else. There you have it—your first Gatsby site, ready for local development or for production deployment!

Conclusion

In this chapter, we’ve covered considerable ground. First, we linked the distinct trends of evolution in content and commerce architectures and evolution in developer experience and web architectures that coalesced in the form of the Jamstack and SSGs. This allows us to define Gatsby explicitly as an SSG and part of the Jamstack range of technologies, positioning it alongside similar serverless technologies.

Then we pivoted to the technical side of Gatsby, exploring core technologies essential to Gatsby development and how changes in both JavaScript and React have made Gatsby an even better choice for developers. Finally, we took a rapid-fire tour through installing Gatsby dependencies, working with the Gatsby CLI, and creating a new Gatsby “Hello World” site using a starter template, all of which has set us up nicely for a more comprehensive examination of Gatsby’s fundamentals.

In the next chapter, we’ll turn our attention to the core building blocks and elements of Gatsby, including starters, Gatsby pages and components, accessibility, CSS, and Gatsby’s plugin ecosystem.

Get Gatsby: The Definitive Guide now with the O’Reilly learning platform.

O’Reilly members experience live online training, plus books, videos, and digital content from nearly 200 publishers.