Chapter 1. Gatsby Fundamentals

Gatsby is an open-source framework for building websites, based on React. Though commonly referred to as a static site generator, Gatsby is also referred to a “web compiler” due to its focus on more than just static sites. Part of the Jamstack category of technologies, alongside frameworks like Gridsome and Next.js, Gatsby confers special emphasis on performance, scalability, and security, with a rich and growing ecosystem of plugins, themes, recipes, starters, and other contributed projects.

In this first chapter, we get acquainted with Gatsby. Though Gatsby’s building blocks are pages and components, its internal data layer, made up of GraphQL and source plugins, bridges data from a variety of sources to a variety of settings. Because Gatsby’s pages and components are compiled at build time, Gatsby is part of the Jamstack category of technologies. Gatsby is built on React, so we’ll look at JavaScript and React concepts that are essential for Gatsby developers. Finally, we’ll build our first Gatsby “hello world” site, which will familiarize us with Gatsby’s developer tooling.

1.1 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 is 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 into a working static site.

In this section, we inspect Gatsby’s overarching architecture from a bird’s-eye view to help us understand its major components. In addition, we take a closer look at the three most important components of Gatsby: pages and components, the building blocks of Gatsby; GraphQL and source plugins, which make up the Gatsby data layer; and the Gatsby ecosystem, consisting of plugins that extend Gatsby functionality.

1.1.1 Gatsby pages and components

Gatsby leverages React components as its atomic unit for building websites, whether that means a Gatsby page or a Gatsby component within a page. 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 one-by-one, 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 file system.

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

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 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 repeatable 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, and it is src/html.js. The src/html.js file is responsible for all concerns that are 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 is 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. In our sample Gatsby codebase above, we don’t see a src/components directory, but this would be where our non-page components would appear.

The three types of components that most Gatsby developers will spend the most time in are page components, page template components, and non-page components. But how does Gatsby know what data to use to populate the props in those components? That’s where GraphQL and Gatsby’s data layer comes in.

1.1.2 Gatsby’s data layer: GraphQL and source plugins

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

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 used frequently as a replacement or enhancement on top of APIs that use the REST paradigm, commonly known as RESTful APIs or REST APIs. 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 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 instead places GraphQL front-and-center within Gatsby to conduct data retrieval and handling at build-time, not run-time. 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, all structured data that needs to be harmonized into a format that developers can easily consume in Gatsby. Gatsby might pull from an internal file system 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 Gatsby can also 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 that component, chances are you have data from other sources you want to pull into your Gatsby site. But how does Gatsby pull data from external sources? That’s where source plugins come in.

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 Gatsby plugin that is important due to its key role in the retrieval of data from external sources: source plugins.

In Gatsby, source plugins are JavaScript modules that fetch data from their source, depending on what that source is. Gatsby offers many source plugins for a variety of systems that emit data, including APIs, databases, CMSs, commerce systems, and even local file systems. gatsby-source-filesystem, for instance, pulls data directly from the internal file system of Gatsby, whether it is Markdown or something else. Meanwhile, gatsby-source-drupal and gatsby-source-wordpress pull content from the Drupal and WordPress content management systems, respectively.

We’ll return to source plugins in short order, but the last major swath of Gatsby we need to cover is the Gatsby ecosystem that encompasses source plugins and a variety of other add-ons that improve the Gatsby developer experience.

1.1.3 The Gatsby ecosystem

The Gatsby ecosystem is Gatsby’s contributed realm, consisting of all of 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

Gatsby themes are a category of plugin that contains a gatsby-config.js file, just like a regular Gatsby site. This gatsby-config.js 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.

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. 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 command-line interface (CLI) to automate certain common responsibilities like creating pages, installing plugins, supporting TypeScript, and others. As of this writing, Gatsby has released roughly a dozen example recipes as well as information on how to write Gatsby recipes.

We’ll turn to each of these Gatsby ecosystem projects later in this book, but now that we’re equipped with an understanding of what Gatsby is, you may be wondering: Why exactly should I use Gatsby, now that I know what it does?

1.2 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 project. Gatsby has gained a reputation in the JavaScript and Jamstack communities for its focus on four key pillars: performance, accessibility, developer experience, and security.

1.2.1 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 four the 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 at a 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 run-time compilation, which is much more granular and might only render a single page. Build-time compilation also means that 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 only upon request.

Payload optimization

Gatsby works hard to reduce the size of the eventual payload delivered to users by reducing the size of images and JavaScript files, delaying the loading of any images below the fold (the bottom 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 content delivery network (CDN), which lends itself to faster delivery of deployed code. Depending on your requirements, this model can be a substantial improvement over the foregoing 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.

1.2.2 Accessibility

Once a fringe concern, accessibility is becoming an important consideration for businesses and organizations across the market that need to serve disabled customers. 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 from 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 of 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, and Gatsby has consistently expressed a commitment to better accessibility in its own ecosystem, including the publication of an accessibility statement on its website (https://www.gatsbyjs.com/accessibility-statement/).

1.2.3 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 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 we take the same approach 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 for developers to see their modifications immediately reflected in their working site. We’ll return to Gatsby’s local development environment later in this chapter.

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 graphical user interface (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.

1.2.4 Security

These days, security is one of the most essential concerns plaguing traditional websites. Many websites still leverage monolithic architectures, whose systems are vulnerable to complete access by attackers without any protection between layers. Others require actively running databases and servers, which facilitate another vector for vulnerabilities.

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 we have a sense of some of the motivations behind why so many developers choose Gatsby, let’s contextualize Gatsby 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 run-time compilation, serverless over server-dependent architectures, and performance optimizations across the stack. Let’s now look at how Gatsby fits into the larger contexts of Jamstack architectures, JavaScript, and React.

Note

Note: If you already understand the background behind Gatsby and the Jamstack and wish to get started immediately with code, you can skip to the section of this chapter named “Getting going with Gatsby.”

1.3 Gatsby and the Jamstack

We’ve just 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 static site generators, which presaged the Jamstack by providing a build-time means of website deployment as opposed to run-time. Then, we’ll cover distributed content and commerce, a contemporaneous paradigm shift occurring in content and commerce architectures. Finally, we’ll combine static site generators and content and commerce architectures to define and outline what the Jamstack is and how Gatsby fits into the Jamstack landscape.

1.3.1 Static site generators

At its most basic level, Gatsby is a static site generator. Static site generators (commonly abbreviated SSG) 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, static site generators 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 run-time, static site generators yield a conjunct of static files and assets that don’t require anything more than a file system. Because static site generators need manual execution to run, typically through a terminal command, they execute at build-time, which means that they only run when a new state of the static assets is required. In this way, static site generators can help developers gain better efficiency by limiting the amount of work servers need to perform for chattier web applications.

The first wave of static site generators were primarily rooted in server-side technologies to perform static site generation and processing of data into templates. For instance, though still-popular Jekyll and Hugo are written in languages like Ruby and Go. others, like Metalsmith, are written in JavaScript. Though the first generation of static site generators was 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 static site generators has emerged, particularly in the JavaScript ecosystem. These static site generators 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 static site generators link themselves with JavaScript frameworks. Gatsby, the subject of this book, and Next.js fall into the category of React-powered static site generators, 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 a static site generator 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.

1.3.2 Distributed content and commerce

In recent years, thanks to the emergence of frameworks like Gatsby, a new architectural paradigm is emerging in the form of distributed content and commerce (the content variant of this is sometimes referred to as the “content mesh,” a coinage of Gatsby Inc. co-founder Sam Bhagwat).

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

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 handled 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. WordPress plugins, for instance, were never interchangeable with Drupal modules, as shown in Figure 1.1.

Another reason for the emergence of distributed content and commerce architectures is the increasing concern about the long-term maintenance of these plugins. If a checkout system maintainer decides to leave her open-source project behind or to delist her plugin from a closed-source marketplace, the resulting disruption has an outsized impact on the ability for a user of that plugin to continue to make a checkout system available. Often, the only solution is to rebuild a 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 on any website implementation. 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 content and commerce sources in order to populate a website, with such back-end 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.

1.3.3 The Jamstack

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

Jamstack frameworks and methodologies introduce the notion of build-time rendering rather than run-time rendering. In Jamstack architectures, a static site generator is responsible for performing the rendering once a build begins. During a build, the static site generator’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 file system, rather than a constantly running database, web server, or server-side application.

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

1.3.3.1 Differences between Jamstack and other architectures

On the other hand, traditional architectures, especially monolithic and many decoupled content and commerce implementations, perform run-time 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.

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 run-time rendering is occurring. Though distributed content and commerce architectures lend themselves most favorably to build-time rendering, it is possible to implement run-time rendering as well.

The most important disadvantage of run-time 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, run-time rendering needs to occur all over again.

1.3.3.2 Serverless infrastructure

Today, there is 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 run-time rendering, which doesn’t occur in Jamstack implementations. Serverless hosts typically require three steps for a Jamstack deployment to succeed:

  • A static site codebase, typically a repository in a source control provider 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

Some of the most common serverless infrastructure providers include Netlify, which is perhaps the most widely used. Others include Vercel, the creator of Next.js, another Jamstack framework; AWS Amplify, from Amazon Web Services; and Gatsby Cloud, which specializes in Gatsby implementations.

Now that we 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 Gatsby leverages JavaScript and React, a JavaScript library for building user interfaces.

1.4 JavaScript in Gatsby

A comprehensive overview of JavaScript’s core concepts and history is impossible in 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.

Caution: This upcoming section on JavaScript is not intended as a full end-to-end guide to JavaScript. It is geared toward developers who already have some experience with JavaScript in past decades or before the emergence of server-side JavaScript. For a more holistic approach to learning JavaScript, consult JavaScript: The Definitive Guide, 7th ed. (David Flanagan, O’Reilly) or You Don’t Know JavaScript (Kyle Simpson, GitHub, located at https://github.com/getify/You-Dont-Know-JS).

JavaScript is a programming language that is one of only two 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 now possible in newer iterations of JavaSCript), and functional and delegative nature.

In the earliest years of JavaScript’s history, it was used primarily to decorate static web pages with small-scale 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 but not limited to command-line interfaces (CLIs) and how modern JavaScript displays modularity.

1.4.1 Command-line interfaces

Command-line interfaces (CLIs) are text-based interfaces that developers use to interact with file systems on their local machines and to provide tooling for application development, dependency handling, and deployment. Though the earliest command-line interfaces were written in low-level languages such as Shell or Bash, today, many command-line interfaces are written in JavaScript through Node.js.

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 manager is Node Package Manager (NPM), which provides on its website (https://npmjs.org) a vast collection of JavaScript packages. Though these packages can be dependencies that become small portions of application code, other packages contain command-line interfaces that can be installed globally and whose commands can be invoked anywhere in the local file system.

The Gatsby command-line interface, which we cover later in this chapter, is an example of a JavaScript-driven CLI that is typically installed globally by invoking the command:

$ npm install -g gatsby-cli

Some developers have opted to shift to Yarn, another package manager, for a variety of reasons, though NPM remains the most popular approach to both dependency management and CLI installation in the JavaScript world.

1.4.2 Modular JavaScript

JavaScript today exhibits considerable modularity, which wasn’t the case when JavaScript was first promulgated in the 1990s. At the time, most JavaScript was written either in a single embedded JavaScript file, which might have a colossal file size, or in multiple JavaScript files embedded in succession, which indicates an order of execution. As JavaScript applications became more complex in the late 2000s and early 2010s, however, 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 Rauschmeyer.

// 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

Though this is 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 Rauschmeyer (located at https://exploringjs.com/es6/) or Mozilla Developer Network’s guide on modules (located at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules).

Many JavaScript frameworks and JavaScript applications use modules to pass values, functions, and classes between each other 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 user interfaces. 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.

1.5 React in Gatsby

React defines itself as a JavaScript library for building user interfaces, but it is perhaps better described as a declarative, component-based approach to interactive user interfaces. 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.

A comprehensive overview of React is 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.

Caution: The upcoming sections on React are not intended as a full end-to-end guide to React. For a more holistic approach to learning React, consult Learning React, 2nd ed. (Alex Banks and Eve Porcello, O’Reilly).

1.5.1 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 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')
)

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>

Due to the inability to use double quotes in JSX (as they are interpreted differently by JavaScript), 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 multi-line element declarations it’s best to surround them in parentheses so they are interpreted as expressions by JavaScript.

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

The following example demonstrates how Babel, a compiler for JavaScript that can compile JSX into raw JavaScript, compiles the above JSX into JavaScript. The following code is equivalent to the code in the previous example.

const el = {
  type: 'div',
  props: {
    className: 'hero-image',
    children: {
      type: 'img',
      props: {
        src: article.heroImageUrl,
      }
    }
  }
}

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

1.5.2 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 foregoing approaches, which separate markup and logic arbitrarily into distinct files, React instead operates in components that contain both the rendering code and the data management in one 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 this 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.

1.5.3 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="images/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

Note: Some of the syntax we’ve seen until now in React, including JSX and React’s component-driven approach, bear 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 prop handling. Now, let’s build our first Gatsby site!

1.6 Getting going with Gatsby

Now that we 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 is Gatsby parlance for a boilerplate site template.

1.6.1 The command line

If you’re already familiar with the command line, installing Node.js, and installing Git, you can proceed to the section entitled “Installing the Gatsby CLI.” Note that Node.js and Git installations can be found in Appendix A.

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 Mac OS X, 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 in the desktop, type “Terminal” to search for applications, and select Terminal.

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) and hitting the Enter key.

Note

Note: For installation instructions for Node.js and for Git on Mac, Windows, and Linux, Appendix A contains full installation guides corresponding to each operating system.

1.6.2 Installing the Gatsby CLI

The Gatsby command-line interface (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 also contains commands that are useful for developing Gatsby sites. As a published Node Package Manager (NPM) package, any Node.js-installed computer can install the Gatsby CLI.

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 file system.

$ npm install -g gatsby-cli

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

Note: 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 arise due to how computers are configured:

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

1.7 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 according to a particular use case. The bare-bones “Hello World” starter contains the base-level requirements for a typical Gatsby site.

To create a new “Hello World” 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 afterwards.

$ 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 one for you.

$ 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, we can change into the directory in which the “Hello World” starter was downloaded. The following command instructs the command line to change directories from where you executed the command to dive into the directory where the starter was downloaded.

$ cd hello-world

If you gave the directory your own name, use that name.

$ cd my-new-gatsby-site

To see the files and directories encompassing the “Hello World” starter, you can issue the list command to see files and their details. By executing the following command within the directory we have just changed into, you can see what the root folder of a typical Gatsby site looks like.

$ ls -la

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

1.7.1 Starting a development server

In order 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 for you on your behalf. To start the development mode and 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.

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

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-4. Our local development environment remains running until we decide to shut it down. This means that any code changes are reflected immediately in the browser.

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 any changes to code will be 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 by terminating the gatsby develop command, in the Terminal window, type Control+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.

1.7.2 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 in 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 live web server where anyone can access our 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. 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.

1.7.3 Serving the production build locally

Now, we can either deploy this static site to an infrastructure provider of our choosing, or we can 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!

1.8 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 static site generators. This is an important foundation on which we can define Gatsby explicitly as a static site generator and part of the Jamstack range of technologies, positioning it alongside similar serverless technologies.

Then, we pivoted into the technical side of Gatsby, exploring core technologies essential to Gatsby development and how changes in both JavaScript and React contribute to a more ironclad argument in favor of Gatsby for developers. This is important not only to justify the adoption of Gatsby but also to understand its underlying dependencies. Finally, we ended with 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 will 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 O’Reilly online learning.

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