How to Increase GatsbyJS speed by 100%

2020/05/139 min read

I take nutrition analysis quite seriously as I treat it as a fuel for my body and brain. At this point, I am 5 years in CrossFit, which may not be called this way after 2020 events, but anyway I try to compete and perform at least 3-4 times per year.

To-Do Summary

  • Page structure and routing
  • Components, templates, and their interaction
  • Working with data
  • Plugins
  • SEO-optimization using react-helmet
  • PWA settings

Preparation

  1. Installing Gatsby on a PC
yarn global add gatsby-cli
  1. Cloning minimum project
npx gatsby new gatsby-tutorial https://github.com/gatsbyjs/gatsby-starter-hello-world
cd gatsby-tutorial
  1. Repository initialization
git init
git add .
git commit -m "init commit"
  1. Operability check
yarn start

If there are no errors in the console, and in the browser, at http://localhost:8000 you can see “Hello world!” — so everything works fine. You can try changing the contents of the /src/pages/index.js file to check the hot-reload.

Page structure and routing

To create a page in Gatsby simply place the new file in the /src/pages folder and it will be compiled into a separate HTML page. It is important to note that the URL to this page will match the actual path with the title. For example, let’s add a few more pages:

src
└── pages
    ├── about.js
    ├── index.js
    └── tutorial
        ├── part-four.js
        ├── part-one.js
        ├── part-three.js
        ├── part-two.js
        └── part-zero.js

Content is not important yet, so you can use any text to distinguish pages:

import React from "react";

export default () => <div>Welcome to tutorial/part-one</div>;

Check in the browser localhost:8000/tutorial/part-onelocalhost:8000/about. In this way, you can solve the problem of routing while structuring files. There is also a special createPage API, which allows you to manage the paths and names of pages more flexibly but to work with it we need to understand the data in Gatsby so we will consider it later in the article. We will link the created pages with the help of links — for this we will use the component from the Gatsby package, which was created specifically for internal navigation. Use a regular tag for all external links.

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

export default () => (
  <div>
    <ul>
      <li>
        <Link to="/about">about</Link>
      </li>
      <li>
        <Link to="/tutorial/part-zero">Part #0</Link>
      </li>
      <li>
        <Link to="/tutorial/part-one">Part #1</Link>
      </li>
      <li>
        <Link to="/tutorial/part-two">Part #2</Link>
      </li>
      <li>
        <Link to="/tutorial/part-three">Part #3</Link>
      </li>
      <li>
        <Link to="/tutorial/part-four">Part #4</Link>
      </li>
    </ul>
  </div>
);

/src/pages/index.js

Components, templates, and their interaction

As you know, in any project there are always repetitive elements. For websites, it is a header, footer, navigation bar. Also, pages regardless of content are built on a given structure. Since Gatsby is a compiler for React, the same component approach is used to solve these problems. Let’s create components for the header and the navigation panel.

Please note that the image for the logo is imported in the same way as in a regular React project. This is a temporary and not optimal solution because the picture comes “as is”. A little further we will consider how to do it “correctly” using GraphQL and gatsby-plug-ins:

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

import logoSrc from "../images/logo.png";

export default () => (
  <header>
    <Link to="/">
      <img src={logoSrc} alt="logo" width="60px" height="60px" />
    </Link>
    That is header
  </header>
);

/src/components/header.js

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

export default () => (
  <div>
    <ul>
      <li>
        <Link to="/about">about</Link>
      </li>
      <li>
        <Link to="/tutorial/part-zero">Part #0</Link>
      </li>
      <li>
        <Link to="/tutorial/part-one">Part #1</Link>
      </li>
      <li>
        <Link to="/tutorial/part-two">Part #2</Link>
      </li>
      <li>
        <Link to="/tutorial/part-three">Part #3</Link>
      </li>
      <li>
        <Link to="/tutorial/part-four">Part #4</Link>
      </li>
    </ul>
  </div>
);

/src/components/sidebar.js

And add them to /src/pages/index.js:

import React from "react";

import Header from "../components/header";
import Sidebar from "../components/sidebar";

export default () => (
  <div>
    <Header />
    <Sidebar />
    <h1>Index page</h1>
  </div>
);

Everything works fine but we need to import Header and Sidebar on each page separately which is not very convenient. To solve this problem just create a layout component and wrap it around each page.

import React from "react";

import Header from "./header";
import Sidebar from "./sidebar";

export default ({ children }) => (
  <>
    <Header />
    <div style={{ margin: `0 auto`, maxWidth: 650, backgroundColor: `#eeeeee` }}>
      <Sidebar />
      {children}
    </div>
  </>
);

/src/components/layout.js

Working with data

Now that the site structure is ready you can move on to filling it with content. The classic “hardcode” approach did not suit the creators of the JAM-stack as well as “render content from AJAX-queries.” So they suggested filling the sites with content at compile time. In the case of Gatsby GraphQL is responsible for this which allows you to work conveniently with data streams from any source.

To work with GraphQL from the second version the gatsby package has a StaticQuery component which can be used both on pages and in simple components and this is the main difference from its predecessor — page query. Our site is not yet connected to any data sources so let’s try to output page metadata for example and then move on to more complex things. To build a query you need to open localhost:8000/___ graphql and use the sidebar with the documentation to find available data about the site. And don’t forget about autocomplete.

import React from "react";
import { Link, StaticQuery, graphql } from "gatsby";

export default () => (
  <StaticQuery
    query={graphql`
      {
        allSitePage {
          edges {
            node {
              id
              path
            }
          }
        }
      }
    `}
    render={({ allSitePage: { edges } }) => (
      <ul>
        {edges.map(({ node: { id, path } }) => (
          <li key={id}>
            <Link to={path}>{id}</Link>
          </li>
        ))}
      </ul>
    )}
  />
);

/src/components/sidebar.js

Now using query we get data about the pages we render in the navigation bar. No need to worry about the link not matching the name because all data is collected automatically.

In fact, this is all the data that can be on our site without the use of third-party plugins or without the good old “hardcode” so we move smoothly to the next topic of our article — plugins.

Plugins

In essence, Gatsby is a compiler with a bunch of bonuses which are just plugins. They can be used to configure the processing of certain files, data types, and various formats.Let’s create a file /gatsby-config.js<|em> at the root level of the application which is responsible for the configuration of the compiler and try to configure the first plugin to work with files.Plugin installation:

yarn add gatsby-source-filesystem
module.exports = {
  plugins: [
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `images`,
        path: `${__dirname}/src/images/`
      }
    }
  ]
};

Configuration in file /gatsby-config.js

Remember we talked about “correct” importing pictures into Gatsby?

import React from "react";
import { Link, StaticQuery, graphql } from "gatsby";

export default () => (
  <StaticQuery
    query={graphql`
      {
        allFile(filter: { name: { eq: "logo" } }) {
          edges {
            node {
              publicURL
            }
          }
        }
      }
    `}
    render={({
      allFile: {
        edges: [
          {
            node: { publicURL }
          }
        ]
      }
    }) => (
      <header>
        <Link to="/">
          <img src={publicURL} alt="logo" width="60px" height="60px" />
        </Link>
        That is header
      </header>
    )}
  />
);

Nothing has changed on the site but now the image is substituted using GraphQL instead of a simple webpack-import. At first glance, it may seem that the design is too complex and this only adds problems but let’s not jump to conclusions. For example, if we decided to post thousands of photos on the site we would in any case have to think about optimizing the download of all content. In order not to build your lazy-load process from scratch we would simply add a gatsby-image plugin that would optimize the loading of all images imported using a query.

SEO-optimization using react-helmet

Let’s work with website metadata and to do this we need the following plugins:

yarn add gatsby-plugin-react-helmet react-helmet

react-helmet generates  for HTML pages and in conjunction with Gatsby rendering is a powerful and convenient tool for working with SEO.

import React from "react";
import { graphql } from "gatsby";
import { Helmet } from "react-helmet";

import Layout from "../components/layout";

export default ({
  data: {
    allContentfulArticle: {
      edges: [
        {
          node: {
            title,
            content: {
              childMarkdownRemark: { html }
            }
          }
        }
      ]
    }
  }
}) => {
  return (
    <Layout>
      <Helmet>
        <meta charSet="utf-8" />
        <title>{title}</title>
      </Helmet>
      <div dangerouslySetInnerHTML={{ __html: html }} />
    </Layout>
  );
};

export const query = graphql`
  query($slug: String!) {
    allContentfulArticle(filter: { link: { eq: $slug } }) {
      edges {
        node {
          title
          link
          content {
            childMarkdownRemark {
              html
            }
          }
        }
      }
    }
  }
`;

/src/templates/index.js

Now the site title will always match the name of the article that will significantly affect the issuance of a site in search results. Here you can easily add <meta name=“description” content=“Article description”> with a description of each article separately, allowing the user to understand what the article is about even on the search page. In general, all SEO features are now available and can be managed from one place.

PWA settings

Gatsby is designed to provide first-class performance “out of the box”. It takes care of code splitting and minimization as well as optimization in the form of preloading in the background, image processing, etc. Therefore, the site you create has high performance without any additional settings. These performance features are an important part of supporting a progressive approach to web applications.But in addition to all of the above there are three basic criteria for a site that define it as PWA:

— HTTPS protocol; — presence of manifest.json; — offline access to the site through service workers.

The first point cannot be solved by Gatsby because the domain, hosting, and protocol are a matter of deployment and not development. But I can advise Netlify which easily solves the problem with HTTPS.Let’s move on to other points. To do this install two plugins:

yarn add gatsby-plugin-manifest gatsby-plugin-offline
if (process.env.NODE_ENV === "development") {
  require("dotenv").config();
}

module.exports = {
  plugins: [
    {
      resolve: `gatsby-plugin-manifest`,
      options: {
        name: `GatsbyJS translated tutorial`,
        short_name: `GatsbyJS tutorial`,
        start_url: `/`,
        background_color: `#f7f0eb`,
        theme_color: `#a2466c`,
        display: `standalone`,
        icon: `public/favicon.ico`,
        include_favicon: true
      }
    },
    `gatsby-plugin-offline`,
    `gatsby-transformer-remark`,
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `images`,
        path: `${__dirname}/src/images/`
      }
    },
    `gatsby-plugin-react-helmet`
  ]
};

plugin settings in /src/gatsby-config.js

You can configure your manifest using the documentation, as well as customize the service-workers strategy by overwriting the plugin settings.You will not notice any changes in the development mode but the site already meets the latest requirements of the web world. And when it is placed on the HTTPS:// domain, it will be blazing fast.

Conclusion

Gatsby solves most of the issues that affect the performance of the site just “out of the box”. And if you understand a little more about the intricacies customize it to your needs, and you can get 100% performance on all counts in the Lighthouse which will significantly affect the issuance of the site in search engines (at least in Google).

Tags:

  • technology

Get in touch

Don't hesitate to ask me anything

Recent publications

View all
2020/05/139 min read

How to Increase GatsbyJS speed by 100%

2020/05/130 min read

5 Free services to build stunning landing page for startup

2020/07/130 min read

What is your startup key metric and why you need it?

2020/07/130 min read

When I should outsource as a startup?

2020/06/130 min read

How to make GatsbyJS 100% SEO-friendly?