Chapter 2. Core Elements of Gatsby

In Chapter 1, we covered some of the most important foundations you’ll need to be familiar with as you begin working with Gatsby, and walked through creating a rudimentary “Hello World” site in Gatsby in your local development environment. In this chapter, we’ll dive into what we covered at the end of Chapter 1 in more detail. I’ll provide more information about the Gatsby command-line interface, working with starters, how Gatsby pages and components work, the layout component, CSS in Gatsby, and how to add plugins to your site.

We explored the Gatsby CLI at some length at the end of Chapter 1, because it is the primary conduit by which you, as a Gatsby developer, will interact with your Gatsby sites. Many common tasks for Gatsby development can be performed with the Gatsby CLI, and we’ll return frequently to Gatsby CLI commands throughout this book. For this reason, it’s only logical that we start with a closer look at CLI and what it can do to accelerate your Gatsby development workflows.

The Gatsby CLI

As you saw in Chapter 1, the Gatsby CLI is the primary means by which developers interact with Gatsby sites during development. It’s the main way to set up a new Gatsby application through scaffolding (generation of files and directories adhering to a boilerplate template) and to run a development server for debugging. In this overview of the Gatsby CLI, we’ll take another look and discuss some of the most important commands.

Installing and Configuring the Gatsby CLI

The Gatsby CLI is an executable JavaScript package named gatsby-cli that you can leverage from anywhere in your filesystem if you install it globally, though some commands will only work in directories where there is a Gatsby codebase present. As we covered briefly in the previous chapter, the Gatsby CLI is available in the NPM registry, and it’s recommended that all users install (i is shorthand for install) it globally by running:

$ npm i -g gatsby-cli

To see a list of commands and a help mode to help you navigate the internals of the Gatsby CLI, you can run the following help command, which begins with the word gatsby, as all Gatsby CLI commands do:

$ gatsby --help

Some starters wrap their Gatsby CLI commands in NPM scripts, which are executable commands that can be defined within a package.json file. In NPM projects, the package.json file contains information about the project in question and all of its dependencies, along with other important information such as commands specific to the project.

Now that we’ve covered the Gatsby CLI installation process and help mode, we’ll turn to some of the most frequently invoked commands in the Gatsby CLI and why they are relevant to your own work.

Note

In certain scenarios, you may wish to use NPM scripts to execute Gatsby CLI commands. To allow for developers to create aliases to use NPM scripts to execute Gatsby CLI commands on your behalf, add the following to your package.json file. Check to make sure that another NPM script isn’t already present; if one is, add this alongside the existing script:

{
  "scripts": {
    "develop": "gatsby develop"
  }
}

Now, instead of running gatsby develop to access the gatsby develop command, you can also run the following command according to the defined NPM script:

$ npm run develop

gatsby new

The gatsby new command is responsible for the creation of new Gatsby sites based on specific parameters. It takes the following format:

$ gatsby new [site-name [starter-url]]

The gatsby new command accepts two arguments:

site-name
Your Gatsby site name. This is also used as the name for your new project directory.
starter-url
A URL pointing to a Gatsby starter or to a local file path. If you don’t supply a starter-url argument, the Gatsby CLI will supply gatsby-starter-default by default.
Note

The site-name argument must only contain letters and numbers, and the gatsby new command will throw an error if you specify ., ./, or a space in your site name argument.

To create a new Gatsby site named my-great-gatsby-site with the default starter, you can execute the gatsby new command without providing a starter-url argument:

$ gatsby new my-great-gatsby-site

To create a new Gatsby site with a specific starter, you can supply the URL or local file path to the starter as the starter-url argument. In this example, we’re using gatsby-starter-blog as the starter of choice:

$ gatsby new my-great-gatsby-site 
  https://github.com/gatsbyjs/gatsby-starter-blog

You can also refer to a starter by using just a GitHub username and repository. Here is an example of the same command using this approach:

$ gatsby new my-great-gatsby-site gatsbyjs/gatsby-starter-blog

To supply your own local custom starter located on your machine’s filesystem, use:

$ gatsby new my-great-gatsby-site ~/path/to/my/custom/starter

If you decide not to supply either of the two arguments, the Gatsby CLI will prompt you to supply them through an interactive shell interface that looks like the following:

$ gatsby new
create-gatsby version 1.3.0

                                Welcome to Gatsby!

This command will generate a new Gatsby site for you in
/Users/prestonso/projects with the setup you select. Let's answer some
questions:

What would you like to call your site?
? > My Gatsby Site

The gatsby new command is the quickest entry point to start developing a Gatsby site out of the box with minimal overhead. Though you can certainly write your own Gatsby site from scratch, you will find it much easier to use one of the existing default starters and adapt it to your needs rather than kicking off a new codebase from scratch.

Now that we’ve covered how the Gatsby CLI supports site creation, we’ll turn to more details about gatsby develop, the command you executed to see your site in a browser at the end of Chapter 1.

gatsby develop

The gatsby develop command can be executed within the root directory of any Gatsby project:

$ gatsby develop

Once you’ve created your new Gatsby site, you can change directories (cd) into the root of the project and execute gatsby develop immediately:

$ gatsby new my-great-gatsby-site
$ cd my-great-gatsby-site
$ gatsby develop

The gatsby develop command initializes a local development server that includes hot reloading (automatic browser refreshing) when your code is updated. This means you can keep gatsby develop running indefinitely while you modify your code and preview the changes in your browser. To exit and shut down the local development server, simply press Ctrl-C.

The gatsby develop command accepts several options:

--host or -H
This sets the host for your gatsby develop command and defaults to localhost for local development.
--port or -p
This sets the port for your local development server and defaults to env.PORT (if you have environment variables defined) or 8000 (if none is set).
--open or -o
This opens the site in your default browser on your behalf without any manual action on your part.
--https or -S
This instructs the server to use HTTPS to set up an HTTPS development server.

The gatsby develop command can also be used with the host option (--host or -H) to access your development environment from other devices that are on the same network. To do this, execute the following command:

$ gatsby develop -H 0.0.0.0

The terminal output will then log information as normal, and it will also provide you with a URL that you can share with those using other devices:

You can now view gatsbyjs.com in the browser.
 ⠀
 Local:            http://0.0.0.0:8000/
 On Your Network:  http://192.168.0.212:8000/

Navigate to that URL within a device on the same network to see how the site renders outside your local machine.

Tip

When previewing code changes on your local machine instead of for other devices, with this host set, you have the option to use http://localhost:8000 or the URL listed alongside “On Your Network” to see your Gatsby site in action.

gatsby build

The gatsby build command is used to compile a complete Gatsby site and ready it for deployment to production (such as to a content delivery network, or CDN). Generally speaking, it’s the last step you’ll take before making your site available for access on the web:

$ gatsby build

The gatsby build command must be executed in the root directory of your project and accepts several options. Note here that one of the options, --prefix-paths, relies on information from gatsby-config.js, which we’ll discuss after this exploration of the Gatsby CLI:

--prefix-paths
Build the site with all links prefixed (by setting pathPrefix in your Gatsby configuration).
--no-uglify
Build the site without uglifying JavaScript bundles (this makes it much easier to debug generated bundles).
–profile
Build the site with React’s profiling API enabled to examine site performance.
--open-tracing-config-file
Build the site and open a tracer configuration file that is OpenTracing-compatible. This is for performance tracing, a topic we’ll return to in Chapter 14.
--graphql-tracing
Build the site and open a trace for every GraphQL resolver. This option can be detrimental to site performance.
--no-color or --no-colors
Build the site but disable color-coded terminal output.
Note

In addition to these options to cater your Gatsby build process to your needs, there are optional build environment variables that allow you to influence the outcome of your command. If you’re familiar with environment variables (if not, we’ll cover them in Chapter 12), you can set CI=true as an environment variable to cater to dumb terminals that aren’t as robust as modern terminals. You can also set NO_COLOR as an environment variable to disable color-coded terminal output.

gatsby serve

The gatsby serve command is used to serve the production build of your site from a local development server so you can see the production version of your site in a browser:

$ gatsby serve

The gatsby serve command must be executed in the root directory of your project and accepts several options:

--host or -H
This sets the host to the host of your choosing. It defaults to localhost.
--port or -p
This sets the port to the port of your choosing. It defaults to 9000.
--open or -o
This will open the site in your default browser on your behalf without any manual action on your part.
--prefix-paths
This serves the Gatsby site with link paths prefixed according to the pathPrefix you configure in your Gatsby configuration.

These are the major commands you will use on a regular basis when interacting with your Gatsby site.

Other Useful Gatsby CLI Commands

There are several other Gatsby commands that are useful for Gatsby development but might not be used as frequently as the others. These commands often are responsible for displaying information about a site, clearing the cache folder (.cache) for a site, and directing you to documentation about plugins.

gatsby info

The gatsby info command is used to deliver helpful information about the environment in which a Gatsby site is displayed so that when a bug is reported, Gatsby’s maintainers can reproduce the situation that led to the issue:

$ gatsby info

The gatsby info command must be executed in the root directory of your project and accepts one option: --clipboard or -C, which automatically copies the environment information displayed in terminal output to your clipboard so you can send it to others.

gatsby clean

The gatsby clean command is used to wipe out any items in Gatsby’s .cache folder, its internal cache, and public directories where compiled files are delivered:

$ gatsby clean

The gatsby clean command must be executed in the root directory of your project and is most useful as a last resort when your codebase seems to be having issues like the following:

Stale data
Sometimes Gatsby’s internal cache can get out of sync with certain files or resources used to populate your site’s data. If a particular file or resource isn’t appearing, or if you aren’t seeing data that should be loaded in, clearing the internal Gatsby cache may resolve the issue.
GraphQL errors
If you have included a GraphQL resource but it is not appearing, executing gatsby clean can ensure that GraphQL accounts for all new resources.
Dependency problems
If you are seeing a dependency with a different version from what was intended or incomprehensible errors in the terminal that have to do with a dependency that doesn’t exist, your cache may need to be cleaned.
Plugin problems
If you are developing a local plugin (see Chapter 9) and your changes and feature additions are not taking effect, clean the cache.

The gatsby clean command can be useful in a variety of situations that may surface during Gatsby development, and we’ll return to examine some of these in later chapters.

gatsby plugin

The gatsby plugin command is used to execute commands that are relevant to Gatsby plugins, add-ons from the Gatsby ecosystem. Executing gatsby plugin docs will transport you to documentation about how to use, install, and write plugins:

$ gatsby plugin docs

gatsby repl

The gatsby repl command is used to open a Node.js read–eval–print loop (REPL) within the context of your Gatsby environment:

$ gatsby repl

As you interact with gatsby repl, Gatsby will prompt you to type in certain commands and explore by displaying:

$ gatsby >

You can then type in a REPL command to understand more about how your site data is used within Gatsby.

Starters

As we saw briefly in Chapter 1, starters are boilerplate Gatsby site templates managed by the Gatsby community that are intended to get you started quickly with Gatsby development. When you execute a gatsby new command with a starter URL, it clones that boilerplate starter’s repository, installs any required dependencies, and clears its Git commit history so you can start with a clean slate.

Official and Community Starters

The Gatsby ecosystem offers a range of official starters, which are maintained by the Gatsby project team. Many new Gatsby developers begin with the gatsby-starter-hello-world starter, as we did in Chapter 1, before moving on to the gatsby-starter-default starter.

Table 2-1 lists the official starters and their most salient features. We’ll cover the starters for Gatsby themes in later chapters.

Table 2-1. The list of official starters maintained by the Gatsby project team
Starter GitHub URL Use case Features
gatsby-starter-default https://github.com/gatsbyjs/gatsby-starter-default Adequate for most use cases Baseline Gatsby site
gatsby-starter-blog https://github.com/gatsbyjs/gatsby-starter-blog Create a rudimentary blog Blog post pages and blog post listings
gatsby-starter-hello-world https://github.com/gatsbyjs/gatsby-starter-hello-world Get started with Gatsby Bare essentials of a Gatsby site
gatsby-starter-blog-theme https://github.com/gatsbyjs/gatsby-starter-blog-theme Create a blog with blog posts and pages Gatsby themes
gatsby-starter-theme-workspace https://github.com/gatsbyjs/gatsby-starter-theme-workspace Get started with Gatsby themes Gatsby themes

The gatsby-starter-default starter is the most common starting point for Gatsby developers beginning a site implementation from scratch. During our upcoming inspection of Gatsby’s page strategy, I’ll talk more about key concepts such as pages, templates, and components.

Gatsby also allows for community contributors to submit starters for inclusion in the community starter library, a compendium of starters built by members of the Gatsby community. We’ll return later in this book to the topic of how to create your own custom starter for yourself or for the community.

Modifying Starters

All Gatsby starters are fully functional websites off the shelf, but the vast majority of Gatsby developers will wish to modify a starter and customize it according to their needs. For this reason, it’s important to select a starter that satisfies your requirements, whether you’re building a blog, a heavy-duty content or commerce site, or something else. There are four major areas within a given starter where you will need to do work:

The gatsby-config.js file
The Gatsby configuration file identifies the codebase as a Gatsby site. In order to provide a unique name for the Gatsby site and other critical information, one of the first files developers modify after cloning a starter is the gatsby-config.js file.
Pages, templates, and components in JSX
Chances are that the predefined structure of Gatsby’s pages and components isn’t in full sync with how you prefer to arrange them or with your organization’s needs. Because Gatsby employs JSX as its primary syntax for components, you’ll need some proficiency with JSX. In addition, for pages with a similar structure, you will need templates, which we’ll cover in Chapter 6.
Data from external or internal sources
Whether your data is housed in the filesystem where your Gatsby site is located or in a separate CMS or commerce system located on a different server, you’ll need to substitute the dummy data in the starter with your own authentic data. We’ll cover this in Chapters 4 and 5.
Cascading Style Sheets (CSS) files
CSS is the canonical language for style and presentation on the web, and all Gatsby sites leverage CSS to add important aesthetic elements such as color, layout, and typography to a given Gatsby page. Gatsby is unopinionated about how you approach your CSS and makes a variety of approaches available for use, such as Emotion and Styled Components (discussed later in this chapter).

With the exception of data from external and internal sources, which deserves a much deeper dive, let’s look at each of these typical areas in turn. We’ll create a new project that will guide us through the remainder of Chapter 2 as we explore the gatsby-config.js file, Gatsby pages and components, Gatsby’s layout component, and using CSS with Gatsby.

Creating a New Project from a Starter

In your terminal, execute the following command:

$ gatsby new gtdg-ch2-pages-components gatsbyjs/gatsby-starter-hello-world

Note here that we are creating a new directory, gtdg-ch-2-pages-components, to contain our new Gatsby site, and we’re using the GitHub username and repository strategy to retrieve the Gatsby starter repository. Next, change into this directory:

$ cd gtdg-ch2-pages-components

and open the gatsby-config.js file in the code editor of your choice. For example, to open the file in Visual Studio Code, use:

$ code gatsby-config.js

and for Atom, use:

$ atom gatsby-config.js
Note

Gatsby has no opinion about what code editor you use in developing a Gatsby site. Many developers prefer Visual Studio Code or Atom due to their rich capabilities for language- and framework-specific extensions and debugging tools. These code editors also have the benefit of being openable with a single command.

The gatsby-config.js File

If you followed the steps to open gatsby-config.js in the code editor of your choice, you’ll see the following contents:

/**
 * Configure your Gatsby site with this file.
 *
 * See: https://www.gatsbyjs.com/docs/gatsby-config/
 */

module.exports = {
  /* Your site config here */
  plugins: [],
}

This empty gatsby-config.js file has no configuration options set and no plugins loaded. The very first step to make your Gatsby site your own is to add some information about the site, specifying the page title and other page metadata. Add a new siteMetadata object to the top of your gatsby-config.js file, and add some information about your site. You can use this example to get some ideas:

module.exports = {
  siteMetadata: {
    title: `My New Gatsby Site`,
    description: `Check out Gatsby with this easy-to-use site.`,
    author: `@prestonso`,
  },
  plugins: [],
}

Congratulations! You’ve now made your first Gatsby site your very own by identifying it as a unique Gatsby site with your own information. Now, let’s turn our attention to what’s happening inside the Gatsby site—and that means opening up one of the pages in our starter.

Gatsby Pages and Components

Pages and components are typical entry points for developers when building a Gatsby site. Pages are the higher-level components that Gatsby uses to build a site, while components can be nested within those pages and in each other. Any time you add a new page, Gatsby will automatically recognize it and incorporate it into your site build.

So how exactly does this work? In this section, we’ll take a close look at Gatsby pages, Gatsby components, and how to link between Gatsby pages.

Pages

We’ll begin with the most important atomic unit of Gatsby sites: the page. In Gatsby, any React component defined with a name in the form src/pages/*.js will automatically be recognized by Gatsby as a page and will be rendered as such. In our “Hello World” starter, we already have one page in src/pages, named index.js.

A typical need for any bona fide website is an about page, so let’s add an about page that contains a bit of information about the site. Because Gatsby recognizes any new file named src/pages/*.js as a new component, we can simply create a file named about.js and place it in that directory.

First, create a new file located at src/pages/about.js, and paste the following inside:

import React from "react"

export default function About() {
  return (
    <div>
      <h1>About us</h1>
      <p>Welcome to our about page! Here is some info about us.</p>
    </div>
  )
}

Then, if you aren’t already running gatsby develop, go ahead and start your development server from the root of the project:

$ gatsby develop

Now, if you navigate to https://localhost:8000/about, you’ll see your new about page. And you didn’t have to do any work besides adding a file to the pages directory!

There’s much more to know about pages, including how Gatsby generates pages, how Gatsby builds pages from components, and how to hook into the page-building process. In addition, some pages have templates, a shared format across pages that is used to programmatically render pages of a certain category (such as individual blog articles or product pages). For now, however, this is an adequate introduction to pages in Gatsby and allows us to proceed to Gatsby components.

Components

In Gatsby, components are just like React components in the traditional sense: they are portions of a page or repeatable code that needs to be placed in a separate file for reuse in multiple places, or simply to make the code more maintainable. In the context of a Gatsby page, a component might be a header, footer, or sidebar. It could also be a lead generation form or a contact form, or it could simply introduce additional code that is important to the site, such as an embedded Google Analytics snippet.

Let’s create a footer component that will be used across both our home page and our about page. First, create a new directory located at src/components. Create a file in that directory named footer.js and insert the following code:

import React from "react"

export default function Footer() {
  return <p>&copy; 2020 My Gatsby Site. All rights reserved.</p>
}

Now, let’s modify each of the pages to use our new footer component. First, let’s add the footer to our about page by adding an additional import statement and invoking the component in our JSX:

import React from "react"
import Footer from "../components/footer"

export default function About() {
  return (
    <div>
      <h1>About us</h1>
      <p>Welcome to our about page! Here is some info about us.</p>
      <Footer />
    </div>
  )
}

Now we’ll do the same in src/pages/index.js:

import React from "react"
import Footer from "../components/footer"

export default function Home() {
  return (
    <div>
      <p>Hello world!</p>
      <Footer />
    </div>
  )
}

React allows us to define what properties (props) a component should have by adding attributes to JSX elements. Instead of using the same copyright text on both pages, let’s have the page define what year the copyright statement should have, rather than the footer component itself. Modify src/components/footer.js to the following:

import React from "react"

export default function Footer(props) {
  return <p>&copy; {props.copyrightYear} My Gatsby Site. All rights reserved.</p>
}

Now, on our about page, let’s provide the prop that our footer needs to fill in the missing copyright year:

import React from "react"
import Footer from "../components/footer"

export default function About() {
  return (
    <div>
      <h1>About us</h1>
      <p>Welcome to our about page! Here is some info about us.</p>
      <Footer copyrightYear="2020" />
    </div>
  )
}

Now when you navigate to the about page at https://localhost:8000/about, you’ll see the same copyright message, but this time you’re defining that prop within your use of the footer component rather than in the footer component itself.

Note

There is a special type of component that exists in Gatsby known as the layout component, which is commonly used to define shared behavior across pages. We’ll discuss this in “The Layout Component”.

Linking Between Pages

Now that you have a rudimentary understanding of pages and components and how they interrelate, we can turn our attention to another type of component that exists in Gatsby and is, in fact, unique to the framework: the Gatsby <Link /> component, which facilitates linking between Gatsby pages. Let’s take a look at how Gatsby performs routing between individual Gatsby pages.

First, let’s open our home page and add in a <Link /> component to our about page. Note that we need to import the <Link /> component from Gatsby and use it in our page:

import React from "react"
import { Link } from "gatsby"
import Footer from "../components/footer"

export default function Home() {
  return (
    <div>
      <p>Hello world!</p>
      <p><Link to="/about/">About</Link></p>
      <Footer copyrightYear="2020" />
    </div>
  )
}

Now, let’s add a link back to the home page from our about page:

import React from "react"
import { Link } from "gatsby"
import Footer from "../components/footer"

export default function About() {
  return (
    <div>
      <h1>About us</h1>
      <p>Welcome to our about page! Here is some info about us.</p>
      <p><Link to="/">Home</Link></p>
      <Footer copyrightYear="2020" />
    </div>
  )
}

Success! Now we have linking between two distinct Gatsby pages using the Gatsby <Link /> component.

Note

The Gatsby <Link /> component should be used for any linking between Gatsby pages. For external links or for anchor links, you should still use the HTML <a> tag rather than <Link />. <Link /> does not work for external URLs outside the immediate Gatsby site, as external URLs are not part of Gatsby’s purview.

The Layout Component

Before we turn our attention to CSS, we need to cover one of the most important components in Gatsby, which has a considerable impact on how we leverage CSS. Layout components are sections of your Gatsby site that should be shared across multiple Gatsby pages and that are most frequently used to provide styling across those pages (unlike the footer component we created in the previous section).

By default, Gatsby never applies a particular layout to pages, because it adheres to React’s compositional approach of importing and using nestable components. Component nestability allows for rich hierarchies within layouts on Gatsby sites, and you can create a header and footer that appear on every page, as well as certain components that should only appear on certain pages. Because all Gatsby components are React components, passing data between layout and page components is a trivial problem to solve.

Layout components are important in Gatsby because they are how we, as Gatsby developers, can indicate to Gatsby that pages with different layouts should display different components. On the main page of a Gatsby site, for instance, a global footer and header might be present, but developers may wish to add an additional sidebar with a menu on internal pages.

Gatsby strongly recommends placing your layout components alongside your other Gatsby components within the same directory, such as src/components/. Here’s an example of a rudimentary layout component adapted from the Gatsby documentation, which we would place into a file located at src/components/layout.js:

import React from "react"
export default function Layout({ children }) {
  return (
    <div style={{ margin: `0 auto`, maxWidth: 960, padding: `0 1.5rem` }}>
      {children}
    </div>
  )
}

Note here that we’re using inline styles on the surrounding <div> element to indicate certain styles, but we’ll soon refactor this code.

Tip

You should recast CSS property names that contain hyphens from kebab-case to camelCase in JSX, because kebab-case can lead to issues later on in JavaScript.

Now, we can return to our home page and apply this layout to the page’s contents such that all of the markup on the page is surrounded by our layout component. Any page or template we want to have this layout should use the <Layout> component we’ve defined. Note here that we’re importing the layout we just created into our home page:

import React from "react"
import Layout from "../components/layout"
export default function Home() {
  return (
    <Layout>
      <h1>I'm in a layout!</h1>
    </Layout>
  );
}

And now that we have our first layout component, we can define our first global stylesheet.

Warning

Because Gatsby does not normally surround pages in a layout component by default, the top-level component is the page component itself. This means that when the page component updates during route changes, React will perform asynchronous rendering of all child components contained therein. If you’re using shared components in your layout, such as a navigation menu, those components will unmount and remount in React, thereby breaking CSS transitions or interrupting React state management in those shared components. To avoid this issue, you can wrap page components that shouldn’t get unmounted on page changes with the wrapPageElement API, which is one of Gatsby’s Browser APIs, or the gatsby-plugin-layout plugin, which implements wrapPageElement for you.

Using CSS in Gatsby

There are several different styling approaches in Gatsby that allow you to adjust the typography, colors, and layout of your Gatsby website. In this section, we’ll cover each of the three CSS approaches that Gatsby makes available:

Global styling
In many uses of CSS, a single stylesheet (CSS file) is downloaded and used to style a website. Gatsby also allows you to provide a single CSS file with global scope according to all the usual rules of CSS, or to provide a variety of CSS files that are associated with a component but whose styles still apply globally. Note, however, that without postprocessing the CSS to strip out unused styles, you may have some dead CSS within your global stylesheet. This is the traditional approach that most web developers are already familiar with.
Modular styling
Gatsby also provides modular stylesheets that allow you to scope CSS declarations to individual Gatsby components. In this model, CSS is written traditionally within Gatsby components but processed by JavaScript. This allows for local scoping and avoids unintended consequences elsewhere. Gatsby offers this CSS paradigm off the shelf.
CSS-in-JavaScript (CSS-in-JS)
In recent years, a new paradigm for CSS in JavaScript applications, CSS-in-JS, has emerged. With this approach, CSS declarations are still locally scoped and consumed in JavaScript, but because JavaScript manages the CSS entirely, dynamic styling based on asynchronous events is possible. This approach requires the use of third-party dependencies.

It’s important to note that Gatsby has no opinion on or prescription for which CSS paradigm you should use, and use of all three is widespread in the Gatsby community. In addition, all three of these options have both official and community plugins that can help you avoid any headaches around dependency management. Let’s take a closer look at each.

Global Styling

In traditional CSS approaches, globally scoped CSS is found in external stylesheets that have the .css extension, according to standard CSS specificity and inheritance. There are two ways to use global stylesheets in Gatsby: without a layout component and with a layout component.

Global styling with a layout component

Applying global styles with a layout component is the quickest way to apply an already existing CSS stylesheet to a Gatsby site or to write CSS that adheres to traditional CSS approaches and will work in every browser.

To use global CSS styles with a layout component, we can add a shared layout component that surrounds all shared components across the site, including styles, header and footer components, and other common components like sidebars and navigation menus. Gatsby’s default starter uses this same approach, but to learn how the layout component works with global styles, we’ll use the “Hello World” starter instead.

Create a new Gatsby site on your local machine. Note here that we’re using the GitHub username/repository strategy to target the correct starter:

$ gatsby new gtdg-ch2-global-styling-with-layout 
  gatsbyjs/gatsby-starter-hello-world
$ cd gtdg-ch2-global-styling-with-layout

Next, create a new directory located at src/components and create two new files named layout.js and layout.css within it. The layout.js file represents our layout component, while the layout.css file represents the styles associated with that layout component.

Now, we can take the same styles we defined inline in the previous section and add them to src/components/layout.css:

/* src/components/layout.css */
div {
  margin: 0 auto;
  max-width: 960px;
  padding: 0 1.5rem;
}

For good measure, let’s also add a readily identifiable CSS rule that will be noticeable as soon as we load the page:

/* src/components/layout.css */
div {
  /* Previous lines of CSS */
  background-color: blue;
}

Now, inside src/components/layout.js, let’s import the stylesheet we just created at src/components/layout.css and export the layout component so any other component can use it as well:

import React from "react"
import "./layout.css"
export default function Layout({ children }) {
  return <div>{children}</div>
}

Note that our <div> element no longer needs any inline styles because we’ve applied our global styles to the layout component.

The last step is to update our home page in Gatsby with our layout component so that the home page uses the layout component as well as its associated styles:

import React from "react"
import Layout from "../components/layout"
export default function Home() {
  return <Layout>Hello world!</Layout>
}

If we now run gatsby develop in the root of our project, we’ll see our page containing a <div> that has a blue background color:

$ gatsby develop

There are situations, however, where using the layout component may not be preferable. Next, we’ll discuss how to write global stylesheets without leveraging the layout component.

Global styling without the layout component

There are situations where you won’t want to use a layout component to drive global styles, whether due to the way you’ve architected components in your Gatsby site or because another element of your Gatsby site prevents the use of the layout component. Fortunately, you can hook into Gatsby’s browser API to include a global stylesheet separately from the React paradigm.

Warning

There is no way to apply styles globally without the layout component and leverage CSS-in-JS at the same time. You will need to use shared components (like the layout component) in order to share styles across components in CSS-in-JS.

Let’s spin up a new “Hello World” Gatsby site to take a look at how we can leverage gatsby-browser.js instead of a layout component to drive global styling. First, let’s create a new copy of the “Hello World” starter:

$ gatsby new gtdg-ch2-global-styling-without-layout 
  gatsbyjs/gatsby-starter-hello-world
$ cd gtdg-ch2-global-styling-without-layout

Now, let’s create a stylesheet and save it to src/styles/global.css to reflect our new global stylesheet:

/* src/styles/global.css */
div {
  margin: 0 auto;
  max-width: 960px;
  padding: 0 1.5rem;
  background-color: blue;
}

Then we’ll create a new file named gatsby-browser.js in the root folder of our project, and import our global stylesheet into gatsby-browser.js:

import "./src/styles/global.css"
Note

You can use require instead if you prefer, as in require('./src/styles/global.css'). In addition, Gatsby has no opinion about where you place a global stylesheet with this approach, so the path src/styles/global.css is arbitrary.

While global stylesheets are the primary means by which developers have written CSS for many years, there are significant disadvantages to global styles, including conflicts between names and instances of unintended inheritance. That’s where component stylesheets can help.

Global styling with component stylesheets

While many Gatsby developers use global stylesheets to keep all their styles in one place, others prefer to split their CSS into component-level CSS files or even individual class declaration blocks that apply to a single Gatsby component. You can decompose your global stylesheet into multiple constituent stylesheets to allow team members to work separately without running into each other, only importing those CSS files that you need for a particular page, template, or component.

For instance, you can create individual CSS files for different components in the components directory (for better organization) and import them into your components. Consider a scenario where you need to import a “footer” component that has the same styles that we already applied previously:

/* src/components/footer.css */
div {
  margin: 0 auto;
  max-width: 960px;
  padding: 0 1.5rem;
  background-color: blue;
}

Now, back in our footer component, all we need to do is to import the CSS file:

import React from "react"
import "header.css"

export default function Footer({ children }) {
  return (
    <div>{children}</div>
  )
}
Warning

While this form of using CSS files can lead to independent work streams thanks to the separation of concerns in stylesheets, it doesn’t take advantage of some of the most important ways Gatsby improves CSS performance, because it doesn’t use the layout component strategy, and Gatsby doesn’t manage the styles itself. Leveraging this approach to importing CSS files will remove your ability to take advantage of CSS performance enhancements like dead code elimination.

Because these stylesheets still require global namespaces, as a footer.css file using global selectors will have its styles apply across the entire site as opposed to being scoped solely to a footer component, they can present many of the same issues as global stylesheets do. In the next sections, we’ll discuss how JavaScript can help us scope our CSS locally instead of globally with CSS Modules and CSS-in-JS.

Modular Styling with CSS Modules

Gatsby offers two approaches to writing CSS that is scoped to components: CSS Modules and CSS-in-JS (discussed in the next section). Scoping CSS to individual components permits Gatsby developers to write traditional CSS that is portable and more maintainable. Styles that only apply to a single component will never infiltrate a different component or change how other components are styled.

CSS Modules is a well-known way to write component-scoped CSS. In short, an individual CSS Module is a CSS stylesheet where all class names (and animation names) are scoped locally out of the box. In CSS Modules, CSS styles become JavaScript objects that are passed between components. Because CSS Modules automatically assign unique names to classes and animations, there is no risk of incurring a collision between two identically named selectors across discrete components.

To illustrate this, let’s return to the example in the previous section—a case of traditional CSS being imported into a Gatsby component—and convert it into a CSS Module being imported into the same Gatsby component. All we need to do to our CSS file is rename it and move it to src/components/footer.module.css.

Also, for the purposes of this look at CSS Modules, let’s select a class name rather than a <div> element:

/* src/components/footer.module.css */
.footer {
  margin: 0 auto;
  max-width: 960px;
  padding: 0 1.5rem;
  background-color: blue;
}

Now, modify the code in src/components/footer.js to use the CSS Modules paradigm instead of a direct import of the CSS stylesheet:

import React from "react"
import footerStyles from "./footer.module.css"

export default function Footer({ children }) {
  return (
    <div className={footerStyles.footer}>{children}</div>
  )
}

Note the syntax in our className value that allows us to drill down into our footer styles and find the specific class name we’re looking for: .footer. Because we’ve used an import, we can use any of the styles contained in that stylesheet within the component, and no style will ever escape the scope of the component. CSS Modules will render the class name into a dynamic CSS class name such as footer-module--container--2KckL.

Next, we’ll take a look at how to locally style components with CSS-in-JS.

Note

The Gatsby documentation recommends using CSS Modules if Gatsby developers are interested in the benefits of properly scoping CSS to individual components, as it allows you to take advantage of performance enhancements like dead code elimination and better portability.

CSS-in-JavaScript

CSS-in-JS is a very different approach from CSS Modules in that it focuses on the idea of writing CSS in JavaScript rather than in external CSS files. When using this approach, it’s important to note that some of the traditional syntax of CSS cannot be written in the same way in JavaScript (e.g., backgroundColor is camelCase in JavaScript, whereas background-color in CSS is kebab-case).

CSS-in-JS is a paradigm that emphasizes scoped styling, dead code elimination, and better performance when dynamic styling gets involved. It has the following characteristics:

Component-driven
Because CSS-in-JS uses the same component methodology as React and Gatsby—all CSS comes in the form of components—you’ll often find CSS-in-JS to be more graceful than other methods.
Scoped locally
Like CSS Modules, CSS-in-JS is scoped to individual components by default.
Styled dynamically
If you need asynchronous changes to styles because of client-side changes in component state, you can integrate JavaScript variables that depend on that state into your CSS-in-JS so the value can change based on its surroundings.
Performance-tuned
CSS-in-JS libraries generate unique class names that don’t collide, thus supporting easier caching, automated vendor prefixing, quick loading of the most important CSS styles, and other features.

While CSS-in-JS is very popular in the JavaScript community to handle CSS, it isn’t so straightforward for those coming from traditional CSS, and it can be time-consuming to refactor traditional CSS into CSS-in-JS and vice versa. And because Gatsby has no opinion about which CSS strategy you use, CSS-in-JS invariably requires the introduction of an additional dependency in the form of a CSS-in-JS library.

There are two CSS-in-JS libraries commonly used with Gatsby, and we’ll cover both of them here: Emotion and Styled Components.

Emotion

Emotion is a CSS-in-JS library that builds on other preexisting libraries and allows you to add styles to applications using string or object style declarations. Emotion leverages predictable composition of styles to avoid some of the specificity concerns that accompany traditional CSS use. In addition, Emotion uses source maps and labels to offer a better debugging experience and better caching for performance.

In order to use Emotion, we need to install our first plugin, which we’ll do here after setting up another “Hello World” starter:

$ gatsby new gtdg-ch2-css-in-js-emotion gatsbyjs/gatsby-starter-hello-world

Now that we have our site scaffolded, let’s change directories into the site and add the dependencies that are required for Emotion using NPM:

$ cd gtdg-ch2-css-in-js-emotion
$ npm install gatsby-plugin-emotion @emotion/react @emotion/styled

Our final step is to open gatsby-config.js and add the plugin to the list of plugins there. If you have no other plugins installed, your gatsby-config.js section for plugins will need to look like the following:

module.exports = {
  plugins: [`gatsby-plugin-emotion`],
}

Now, let’s introduce styles for a header component into our Emotion page. Note that Emotion prefers to co-locate styles in the same file as the logic defining how those styles will take effect on JSX elements:

import React from "react"
import styled from "@emotion/styled"
import { css } from "@emotion/react"

const Header = styled.div`
  margin: 0 auto;
  max-width: 960px;
  padding: 0 1.5rem;
  background-color: blue;
  color: white;
`

export default function Home({ children }) {
  return (
    <Header>
      <div>Welcome to my Gatsby site!</div>
    </Header>
  )
}

As you can see, here we’re using a multiline string to define the CSS rules for our header.

Emotion also allows us to add arbitrary declarations that can be used to style individual JSX elements. In the following example, we apply a text-transform property to ensure that the header will be in uppercase on the home page by applying a chunk of CSS to the element:

import React from "react"
import styled from "@emotion/styled"
import { css } from "@emotion/react"

const Header = styled.div`
  margin: 0 auto;
  max-width: 960px;
  padding: 0 1.5rem;
  background-color: blue;
  color: white;
`

const uppercase = css`
  text-transform: uppercase;
`

export default function Home({ children }) {
  return (
    <Header>
      <div css={uppercase}>Welcome to my Gatsby site!</div>
    </Header>
  )
}

When we run gatsby develop, we can see our newly Emotion-styled Gatsby site, as depicted in Figure 2-1.

Figure 2-1. Our Gatsby home page styled with Emotion, with styles pulled in through the css tag

One of the most important benefits of Emotion and other CSS-in-JS techniques is the placement of CSS directly within the definition of your component in JavaScript. But you can also use Emotion to apply global styling to your Gatsby site by adding Emotion as a dependency and using it within your layout component. Using Emotion for global styling with a layout component would obviate the need for a separate layout.css file.

Note

Server-side rendering, or the prerendering of HTML before it reaches the client side (see Chapter 3 for more information on this), functions off the shelf in Emotion. You can choose to use React’s renderToString method or renderToNodeStream method without any additional configuration. Meanwhile, the extractCritical feature deletes unused CSS rules (dead code elimination) so pages can load faster down the line.

Styled Components

Styled Components is another CSS-in-JS library that allows Gatsby developers to write actual CSS inside components, just like Emotion. And like Emotion, Styled Components eliminates the possibility of name collisions and dead code appearing in your production CSS.

Let’s take a look at the exact same example we went through with Emotion to see how Styled Components offers a similar approach. In order to use Styled Components, we need to install its plugin, which we’ll do here after setting up yet another “Hello World” starter:

$ gatsby new gtdg-ch2-css-in-js-styled-components 
  gatsbyjs/gatsby-starter-hello-world

With our site scaffolded, let’s change directories into the site and add the dependencies that are required for Styled Components using NPM:

$ cd gtdg-ch2-css-in-js-styled-components
$ npm install gatsby-plugin-styled-components styled-components 
  babel-plugin-styled-components

Next, we’ll open gatsby-config.js and add the plugin to the list of plugins there. If you have no other plugins installed, your gatsby-config.js section for plugins will look like the following:

module.exports = {
  plugins: [`gatsby-plugin-styled-components`],
}

Our index.js will look similar to in the Emotion example and produce the same result, as seen in Figure 2-2:

import React from "react"
import styled from "styled-components"

const Header = styled.div`
  margin: 0 auto;
  max-width: 960px;
  padding: 0 1.5rem;
  background-color: blue;
  color: white;
`

export default function Home({ children }) {
  return (
    <Header>
      <div>Welcome to my Gatsby site!</div>
    </Header>
  )
}
Figure 2-2. Our Gatsby home page styled with Styled Components—this library allows us to apply styles directly to elements without having to refer to them as we do in Emotion

Just like with Emotion, it’s possible to apply global styles to our layout component, but Styled Components takes a slightly different tack. Styled Components offers a createGlobalStyle method that defines globally scoped styles. This method should be invoked within Gatsby’s layout component to ensure it’s shared across all pages using that layout component.

Here’s an example of a layout component that uses a GlobalStyle object, adapted from the Gatsby documentation. Note here that according to our layout component’s state, we are toggling between two different background colors:

import React from "react"
import { createGlobalStyle } from "styled-components"
const GlobalStyle = createGlobalStyle`
 body {
   background-color: ${props => (props.theme === "blue" ? "blue" : "white")};
 }
`
export default function Layout({ children }) {
 return (
   <React.Fragment>
     <GlobalStyle theme="blue" />
   </React.Fragment>
 )
}

Both Emotion and Styled Components are commonly found in Gatsby implementations. But it’s perfectly fine to use global styling and traditional CSS as well, and Gatsby makes no assumptions about which paradigm of CSS you prefer to use with your site build!

As you probably noticed, we just installed our first two Gatsby plugins. Our next step is to explore Gatsby’s plugin ecosystem and how to extend the core functionality of the Gatsby framework with community plugins.

Extending Gatsby with Plugins

In Gatsby, plugins are Node.js packages that introduce additional functionality that implements Gatsby’s APIs (Gatsby functionality that developers can hook into to implement their own custom code). Plugins are particularly useful because they can help you modularize functionality into tightly scoped chunks of logic. Gatsby plugins run the gamut of use cases, including search engine optimization (SEO), responsive image support, Sass and LESS support for CSS, offline support, sitemaps and RSS feeds, TypeScript and CoffeeScript compilation, Google Analytics embeds, and more.

Note

You can also create your own custom plugins, which we’ll cover in Chapter 9.

As you saw when we installed the Emotion and Styled Components plugins, the authoritative way to install a new Gatsby plugin is to use the NPM installation process to add the dependency to your package.json file. However, Gatsby also requires you to add the plugin explicitly to gatsby-config.js so Gatsby’s aware of it too.

There are several broad categories of plugins that exist in the Gatsby ecosystem:

Source plugins
These plugins are responsible for introducing external data or content from an arbitrary source, whether it is a CMS, a commerce system, static files on the local filesystem, or a web service such as a REST API or GraphQL API (which expose data and are covered at length in Chapter 5). Source plugins translate external data into data consumable through Gatsby’s internal GraphQL API.
Transformer plugins
Transformer plugins are responsible for converting data in one format to another, especially to JSON. For instance, some external data arrives in the form of Markdown, YAML, CSV, or XML, all serialization formats that are ill suited to use in JavaScript. Transformer plugins for each individual format convert other formats into JSON for Gatsby.
External service plugins
Broadly speaking, any plugin that embeds or adds in third-party functionality is an external service plugin that pulls information or code directly from a third party such as Google Analytics, Segment, or Algolia. Though these plugins are very common, they also tend to be much smaller in size than source plugins or transformer plugins.

There are also many plugins that don’t fit into a clear category. To get an idea of what’s available, check out the Gatsby Plugin Library.

Note

Themes are also a type of Gatsby plugin, but they require a full discussion in their own right. We’ll return to them in Chapter 10.

It’s also important to note where plugins are not necessary. Though plugins introduce additional functionality to Gatsby sites, not all additional functionality needs to be added via a Gatsby plugin. For instance, if you wish to use JavaScript packages that provide developer utilities, like lodash or axios, or that integrate libraries that are essential to the functioning of a component, like d3 for visualization, it’s generally best to import the package directly as a dependency in package.json rather than as a plugin. This means that you would install the library normally as an NPM package but refrain from editing anything in gatsby-config.js to reflect the new library’s presence.

As a general rule, to help you decide whether some piece of functionality should be a plugin or a separate library, if the functionality does not hook into or implement Gatsby’s APIs in any way, it’s generally safe to import it solely as a dependency and not write or search for a plugin that contains it. In some cases, however, you can choose between an existing Gatsby plugin and a library: for example, you could use either gatsby-plugin-styled-components, which offers a deeper integration with Gatsby APIs, or the styled-components package itself, which you would need to implement yourself in Gatsby where you wish to use it.

Installing Gatsby Plugins

Recall from our examination of Emotion and Styled Components how the installation process for plugins works. Let’s revisit it here with a typical plugin. To keep things simple, we’ll use gatsby-plugin-google-analytics, which allows us to embed Google Analytics code into our Gatsby site.

You can install a plugin from the root directory of your Gatsby site, and you can install a plugin at any time—at the very start of the development process when your site has just been scaffolded, or well into the project timeline when your site is full of other installed plugins. To install a plugin, run this command, substituting the plugin name for a name of your choosing:

$ npm install gatsby-plugin-google-analytics

In your gatsby-config.js file, ensure that your plugin is represented in the plugins array. If you’re adding a plugin for the first time, you may need to add the plugins array yourself. If you already have plugins in your configuration, you can simply add it as a member to the existing array:

module.exports = {
  plugins: [`gatsby-plugin-google-analytics`],
}

You’ll follow this exact process every single time you need to introduce another plugin into your Gatsby site.

Some plugins also accept options in their definitions in gatsby-config.js. This is usually to configure key parameters specifying how the plugin should behave or credentials that are required for an external service. For instance, a typical options object for gatsby-plugin-google-analytics looks like this:

module.exports = {
  plugins: [
    {
      resolve: `gatsby-plugin-google-analytics`,
      options: {
        // The property ID; the tracking code won't be generated without it
        trackingId: "YOUR_GOOGLE_ANALYTICS_TRACKING_ID",
        // Defines where to place the tracking script - `true` in the head 
        // and `false` in the body
        head: false,
        // Setting this parameter is optional
        anonymize: true,
        // Setting this parameter is also optional
        respectDNT: true,
        // Avoids sending pageview hits from custom paths
        exclude: ["/preview/**", "/do-not-track/me/too/"],
        // Delays sending pageview hits on route update (in milliseconds)
        pageTransitionDelay: 0,
        // Enables Google Optimize using your container Id
        optimizeId: "YOUR_GOOGLE_OPTIMIZE_TRACKING_ID",
        // Enables Google Optimize Experiment ID
        experimentId: "YOUR_GOOGLE_EXPERIMENT_ID",
        // Set Variation ID. 0 for original 1,2,3....
        variationId: "YOUR_GOOGLE_OPTIMIZE_VARIATION_ID",
        // Defers execution of google analytics script after page load
        defer: false,
        // Any additional optional fields
        sampleRate: 5,
        siteSpeedSampleRate: 10,
        cookieDomain: "example.com",
      },
    },
  ],
}

Depending on the nature of your plugin, it may or may not require options.

Loading Local Plugins

It’s also possible to load plugins from your local filesystem, in much the same way you might derive data from the filesystem. Gatsby is able to load plugins from your Gatsby codebase as long as you place them in a top-level plugins directory alongside the src directory. Local plugins are valuable for cases where you may need to introduce proprietary code to a Gatsby codebase or you wish to write your own custom plugins.

The Gatsby documentation provides an example of a project structure that would leverage a local plugin called gatsby-local-plugin:

/my-gatsby-site
└── /src
   └── /pages
   └── /components
└── /plugins
   └── /gatsby-local-plugin
       └── /package.json
       └── /gatsby-node.js
└── gatsby-config.js
└── gatsby-node.js
└── package.json
Note

You can add any number of local plugins to this folder, as long as they all have distinct names.

With local plugins, you don’t need an NPM installation command, but you do need to configure the plugin in gatsby-config.js so that Gatsby is aware of it:

module.exports = {
  plugins: [`gatsby-local-plugin`]
}

To verify your plugin is loading correctly in your Gatsby site, you can add a gatsby-node.js file to the plugins directory (we’ll cover what this file does in Chapter 6) and add a line to the terminal output that is printed when you run either gatsby develop or gatsby build. This line should use one of Gatsby’s build hooks, such as onPreInit (before any other step), which we’ll also discuss in more detail in Chapter 6:

exports.onPreInit = () => {
  console.log("Hey, I’m a local plugin that just got loaded! Look at me!")
}

In your terminal output, the next time you run gatsby develop or gatsby build, you will see the following:

success open and validate gatsby-configs - 0.053s
success load plugins - 1.036s
Hey, I’m a local plugin that just got loaded! Look at me!
success onPreInit - 0.025s
...
Note

You can also load a local plugin from somewhere outside the plugins folder. I’ll cover that approach when we look at writing custom plugins in Chapter 9.

Conclusion

In this chapter, we examined several of the most important foundational concepts in Gatsby in detail in order to prepare us for an examination of common use cases in Chapter 3. In addition, we inspected the Gatsby CLI commands you’ll use most frequently in the day-to-day work of implementing Gatsby, whether that involves spinning up starters quickly, facilitating the use of CSS-in-JS libraries, or installing new plugins.

We also explored the structure of Gatsby projects in terms of pages and components to support your journey into new Gatsby implementations. Because CSS is a baseline requirement for websites today, we also walked through the many possible ways to introduce CSS to your Gatsby site.

In the next chapter, we’ll build on this conceptual foundation and begin to work with common use cases to build certain functionality into a boilerplate Gatsby site, including analytics, form handling, contact forms, search engine optimization, 404 pages, and other common requirements in web development today. In the process, we’ll find practical applications for all of the underpinnings we covered in this chapter.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
44.193.208.105