DEV Community

Cover image for Building a Website With Gatsby.js
Ethan Gustafson
Ethan Gustafson

Posted on

Building a Website With Gatsby.js

Table Of Contents:

This blog is purposed to be a simple overview of creating a website using Gatsby. The Gatsby website will guide you along in creating a website, even if you don't know much about web development. It will teach you topics during the tutorials, but I will walk you through everything all together and will be as direct as possible.

What is Gatsby?

Gatsby.js is an open-source framework that utilizes React.js to generate static websites. What is a static website?

A static website doesn't dynamically change. Dynamic websites render different content depending on the data it receives. A static website will be delivered to you as it is stored. Although Gatsby uses Graphql(which is a query language), there is no database. Instead, data retrieving occurs when the app is being built, from local files.

Plugins, Themes, Starters

There is an abundance of plugins available that add functionality to your application, such as Responsive Images, an RSS feed, Google Analytics, etc.

Gatsby Themes are Plugins that come with pre-configured functionality, data sourcing, and/or UI code. There are "Starters", which are website boilerplates that are pre-configured with a direct purpose in mind, like creating a portfolio.

Installation, Creation

  • Install Gatsby globally with npm install -g gatsby-cli.
  • To create a new website, run gatsby new {your-project-name} {link-to-starter} ({link-to-starter} can be omitted)
  • Run the server with gatsby develop.

If you didn't use a starter, then here are some plugins to help get you started. Gatsby image, react helmet, plugin sharp, and the transformer-sharp plugin should already be configured in gatsby-config.

Each of those plugins can be installed after you create the project.

File Structure

When you open your newly created project, it used gatsby-starter-default to generate everything. You'll see a few gatsby.js files in the root directory, along with the src directory, which contains three folders:

  1. components
  2. images
  3. pages

Note: If you decide to rename the files within these folders, you might have to make sure that when you begin importing other files, that the name of what you are importing matches the casing of the filename. If you don't, the terminal will report warnings to you about modules casing inconsistency concerning certain file imports.

For example, I changed the name of layout.js to Layout.js, and I began receiving warnings about modules with different casing names.

/* It turns out that imports I had in other files like 404.js were: */
import Layout from "../components/layout" 
// When it needed to be 
import Layout from "../components/Layout"
// To remove the warnings
Enter fullscreen mode Exit fullscreen mode

components, images, pages

The pages folder contains your 'routes'. Each new file created will become a new page in your project, where the name of the file will become the name of the URL route. For example, about.js would generate the URL route /about.

You'll find four files inside. 404.js, index.js, page-2.js, and using-typescript.tsx.

Inside of the index.js file, you will see this code:

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

import Layout from "../components/layout"
import Image from "../components/image"
import SEO from "../components/seo"

const IndexPage = () => (
  <Layout>
    <SEO title="Home" />
    <h1>Hi people</h1>
    <p>Welcome to your new Gatsby site.</p>
    <p>Now go build something great.</p>
    <div style={{ maxWidth: `300px`, marginBottom: `1.45rem` }}>
      <Image />
    </div>
    <Link to="/page-2/">Go to page 2</Link> <br />
    <Link to="/using-typescript/">Go to "Using TypeScript"</Link>
  </Layout>
)

export default IndexPage
Enter fullscreen mode Exit fullscreen mode

What's happening here? The index.js file is the file gatsby loads upon starting the server. The contents of this file are rendered and sent to the browser.

Layout is a component in the components directory. In index.js, everything inside of Layout is an argument to the Layout component. If you are doing data retrieving, layout.js is where you can query the data with Graphql to be shown in the browser.

If you look at the return statement, you'll see this code:

return (
    <>
      <Header siteTitle={data.site.siteMetadata?.title || `Title`} />
      <div
        style={{
          margin: `0 auto`,
          maxWidth: 960,
          padding: `0 1.0875rem 1.45rem`,
        }}
      >
        <main>{children}</main>
        <footer style={{
          marginTop: `2rem`
        }}>
          © {new Date().getFullYear()}, Built with
          {` `}
          <a href="https://www.gatsbyjs.com">Gatsby</a>
        </footer>
      </div>
    </>
  )
Enter fullscreen mode Exit fullscreen mode

Everything is wrapped with React Fragments(<></>), and as you can see the JSX represents the body of the HTML document. There is a Header, main, and footer. The Header component is receiving the data retrieved from layout.js.

main is containing children, which were passed into Layout as arguments(from index.js). Every argument Layout takes in will become a child element of the main tag.

After Layout, you will see: <SEO title="Home" />. SEO stands for Search Engine Optimization. All of your page contents are available to search engine crawlers because Gatsby uses Server-Side-Rendering.

The SEO component deals with the metadata in the head element. It uses Graphql to query metadata to be placed in the head.

At the very bottom, you will find this:

Layout.propTypes = {
  children: PropTypes.node.isRequired,
};
Enter fullscreen mode Exit fullscreen mode

What is .propTypes ? In React, propTypes deals with type checking. Type checking is used to ensure that props contain certain prop types.

The children prop is being type-checked. PropTypes define types of data for props. node is any value that can be rendered on the screen. isRequired ensures that the type of data the children prop should be receiving is of the node type.

image.js, header.js

What is gatsby-image? How does it function?

gatsby-image works with gatsby-transformer-sharp and gatsby-plugin-sharp. gatsby-source-filesystem connects your local files together so that gatsby-image can locate them in your Graphql queries. gatsby-image doesn't require any configuration when used within Gatsby.

gatsby-image is used in image.js to handle images. The Gatsby Image API states:

gatsby-image is a React component. It is designed to work with Gatsby's native image processing capabilities powered by Graphql and gatsby-plugin-sharp to optimize image loading for your site.

gatsby-image is not a drop-in replacement for <img />. It’s optimized for responsive fixed width/height images and images that stretch the full-width of a container. There are also other ways to work with images in Gatsby that don’t require GraphQL.

gatsby-image:

  • loads the optimal image size for each device size and screen resolution
  • holds the image in a solid position while your page loads so the elements on the screen don't jump around
  • shows a blur effect on images before they are fully loaded
  • lazy loads images.

There are two types of responsive images supported by gatsby-image, fixed, and fluid. fixed is for images with a fixed width and height. fluid is for images that stretch across a fluid container.

In image.js, you'll find that the return value is either stating the picture wasn't found, or the image with its specified responsive type.

const Image = () => {
  const data = useStaticQuery(graphql`
    query {
      placeholderImage: file(relativePath: { eq: "gatsby-astronaut.png" }) {
        childImageSharp {
          fluid(maxWidth: 300) {
            ...GatsbyImageSharpFluid
          }
        }
      }
    }
  `)

  if (!data?.placeholderImage?.childImageSharp?.fluid) {
    return <div>Picture not found</div>
  }

  return <Img fluid={data.placeholderImage.childImageSharp.fluid} />
}
Enter fullscreen mode Exit fullscreen mode

As you can see, the query and the return specify what type of image it will be. You as a developer will get to choose which kind it is.

Overall, header.js just contains what is in the header element. layout.js contains the Header component as well as the rest of the body. SEO contains what is in the head. index.js loads SEO and Layout, the head, and the body.

gatsby.js files

In the root directory of your project, you'll find four gatsby.js files.

gatsby-browser.js is where you can respond to events within the browser and can wrap your site in additional components.

gatsby-config.js is where you can set the configurations options for your site. Some things you can configure are siteMetaData(where you can store common pieces of data across pages for reuse), plugins, pathPrefix, Polyfill(Gatsby uses the ES6 Promise and not all browsers support it, so Gatsby includes Polyfill by default), etc.

The code in gatsby-node.js is run once in the process of building your site. You can use it to dynamically create pages, add Graphql Nodes, or respond to events during the build lifecycle.

gatsby-ssr.js correlates with Server-Side-Rendering. SSR is where the server renders a web page, then sends it to the browser, instead of letting the browser render the web page. This file will let you alter the content of static HTML files while they are being rendered by the server.

Graphql

Graphql is a query language developed by Facebook. It doesn't interact with a database, it interacts with APIs. Queries allow you to get all the information you need inside of a single request.

Gatsby uses Graphql to interact with local files. This allows you to reuse common pieces of data.

import { useStaticQuery, graphql } from "gatsby";

There are two types of queries you can use in Gatsby, static and page queries.

useStaticQuery is a React Hook that is used to query data with Graphql at build time. React Hooks let you use state and other React features without writing a class.

React Hooks do not work within classes. You can also build your own hooks. Hooks let you use state outside of a class. React preserves the state between re-renders. More on hooks here: Hooks Overview

const data = useStaticQuery(graphql`
    query SiteTitleQuery {
      site {
        siteMetadata {
          title
        }
      }
    }
  `)
Enter fullscreen mode Exit fullscreen mode

When generated with the default starter, Gatsby configures this variable for you in Layout.js. It assigns the query to the variable data. This query executes during build time.

graphql is a Gatsby tag that enables page components to retrieve data from a Graphql query. query is the operation type. In Graphql, there are query, mutation, and subscription types. SiteTitleQuery is the name of the query. The name of your query can be omitted, but it is helpful to include when it comes to debugging.

query SiteTitleQuery {
      site {
        siteMetadata {
          title
        }
      }
    }
Enter fullscreen mode Exit fullscreen mode

site will be the beginning key of the query, it isn't referencing a key in gatsby-config.js. The data we are asking for from gatsby-config.js is title from siteMetadata.

In JavaScript, object properties can be accessed using dot notation. We can access the results of the query with data.site.siteMetadata?.title.

<Header siteTitle={data.site.siteMetadata?.title || `Title`} />
Enter fullscreen mode Exit fullscreen mode

If you haven't seen that question mark before, it is the optional chaining operator.

Top comments (0)