DEV Community

loading...

The trend of web performance and the rise of static-site generators, with Gatsby.js, GraphQL and React.js tutorial.

andrewsmith1996 profile image Andrew Smith ・16 min read

The trend of web performance and the rise of static-site generators, with Gatsby.js,

Out of all the trends in today’s age of web development, the trend of high-end web performance is the one trend that singlehandedly offers the most reward and payoff to both users and web developers alike; with everyday users now expecting websites to offer blazingly fast page speeds, minimal loading times and an engaging and satisfying user experience with absolutely zero frustration.

Over the recent years we’ve seen this expectation fulfilled. As we constantly push the web to do more and more, and add more features to our applications, we begin to see a serious drop in website performance. But with web technologies such as PWAs (progressive web apps), service workers and static site generators combatting this, and ushering out the days of long native application load times and frustrating delays, developers are able to create fast, efficient and reliable applications that offer outstanding web experiences, with little development time.

The bottom line is that performance matters, and Google’s consistent push on this front with its Lighthouse services for PWAs and Accelerated Mobile Pages (AMP) really show how the industry big-boys are now prioritising web performance, and how we all should too.

Google even gives us the stats to back this up. For example, Pinterest increased search engine traffic and sign-ups by 15% when they reduced wait times by 40% (1), and the BBC discovered that they lost an additional 10% of users for every additional second that their website took to load (2).

In particular, due to their blazingly fast page speeds, enhanced security and simple development, deployment and hosting, many web developers are turning to static site generators as a way of building their websites whilst simultaneously achieving their web performance goals.

So, what is a static site generator?

A common misconception with static sites are that they are a new technology, when in fact they’ve been around for years. Static sites were the original method of web development, where vanilla HTML, CSS and JavaScript were used to build websites, featuring no front-end frameworks, libraries or plugins.

Static site generators themselves focus on generating vanilla HTML, CSS and JavaScript sites as the complete output, without any links to databases or server-side processing (thus making their load speeds very fast). These static HTML files are generated by the server and are ready to be returned to the browser. With the ability for static site generators to pull data from anywhere, including a wide range of CMS, APIs and content files.

What are the perks of using static site generators?

  1. Speed. Due to the lack of any back-end system actually delivering the website, no database queries need to be run and no client-server requests need to be processed, and with the server always having the HTML output ready to be delivered to a user, the performance of static sites are often blazingly fast. Furthermore, many static site generators have caching features that further cut down on delays. Essentially, all the server has to do is return a file, which turns out, it’s pretty good at doing quickly…

  2. Security. Again due to the lack of a back-end system, a static site has no database that can be attacked or exploited, there are no plugins or extensions that can be used as routes into a system and there are no areas that anyone can gain unauthorised access to. WordPress (which powers a whopping 34% of websites on the internet) is infamous for being exploited and having security vulnerabilities, but with static sites there isn’t really much damage that anyone can do to a set of plain HTML files.

  3. Robust. Yet another JAMstack perk of having no back-end system. Deployment and scaling of a static site is much simpler, and the application as a whole is generally more stable and robust as a server is actually able to handle a lot of traffic only requesting simple static files.

  4. Ease of development. Static site generators significantly ease the process of development. It’s super easy to get things up and running, with minimal setup and configuration, and once the site is written it’s often just a simple command to deploy the site.

  5. SEO. It’s often the case that web crawlers can’t read complex React.js or Vue.js applications with hundreds of components, which puts them right at the bottom of the SEO barrel. But when your content is static, and you have great page speeds and performance, then you’re sure to be well-off on the SEO front.

What are the drawbacks of using static site generators?

  1. Real-time applications. As the site is restricted to a single set of static HTML files that are generated upon every request, there’s currently no ability for creating an application that hosts real-time data. So say goodbye to any applications that require functionality such as auto-updating news stories, live commenting, live data or any form of messaging applications.

Enter Gatsby.js

Gatsby.js is an open source framework for generating static sites. Based on the JAMstack (https://jamstack.org). Gatsby uses React.js as the front-end framework of choice and GraphQL to power its data layer; ultimately allowing Gatsby to pull data in from a range of sources (basically anywhere) including CMSs such as WordPress, Drupal and Craft CMS, simple markdown files consisting of meta data, fully fledged databases and APIs or local files.

Gatsby also has a tonne of plugins for extending its functionality. Gatsby uses 2 types of plugins, source plugins for “sourcing” data into the application, such as pulling in data from CMSs such as WordPress, and transformer plugins which “transform” data from source plugins into some new data, such as lazy loading images.

React.js

Gatsby uses React.js for building the website’s user interfaces, it’s fast and pretty nice actually (I’m a bit of a React and React Native fanboy), and according to Stack Overflow’s most recent developer survey, is the web framework of choice for 31.3% of developers, is the most loved framework by 74.5% of developers and ranks top as the most wanted web framework.

GraphQL

Gatsby uses GraphQL for its data layer. Originally created by Facebook, GraphQL will allow us to pull data into our website. GraphQL is really powerful, and yields really elegant and efficient solutions. More on GraphQL later.

The Tutorial

In this tutorial we’ll be using Gatsby.js, a popular static site generator used by companies such as AirBnB and Nike. Gatsby.js utilises React.js and GraphQL, and in this tutorial we’ll be building a simple website that displays information about Star Wars films and characters (nerd alert), and then we’ll use Gatbsy.js to output a complete static website, that generates itself during build time whenever a user visits it.

The project we’ll be creating to show the power of Gatsby.js is a simple application that pulls data in from the Star Wars API (SWAPI — https://github.com/graphql/swapi-graphql) and displays content on films and characters from the franchise/universe. We’ll have a simple index page listing films and characters and we’ll be using a simple card layout for displaying each piece of content on the index page.

Gatbsy’s role here involves querying the API and building the static site at runtime (whenever anybody visits the website), resulting in an ultra-fast dynamic set of web pages that load almost instantaneously. Furthermore, when new content is added to the Star Wars API, the static site will automatically pull this new content in and regenerate itself; ultimately creating a somewhat hybrid dynamic-static site.

Step 1 — Installing Gatsby.js

Firstly we’ll need to install Node.js, if you’ve already done this then skip this step, if not then go to https://nodejs.org/en/download/.

Next, we’ll need to use NPM to install the Gatsby.js CLI (command line interface), this will make it easier to create and manage Gatsby projects:

npm install -g gatsby-cli

For reference, you can see all the Gatsby commands available to us by running:

gatsby --help

Gatsby come with a bunch of pre-built project configurations/starter templates that make creating Gatsby projects really simple. We’ll be using the “Hello World” start template, so to create our new Gatsby project run the gatsby new command with the name of our project, then the starter template we’ll be using:

gatsby new star-wars-app [https://github.com/gatsbyjs/gatsby-starter-hello-world](https://github.com/gatsbyjs/gatsby-starter-hello-world)

This will create the basic starter project for us, so run the following commands to start developing the application:

cd star-wars-app
gatsby develop

Then if you head to http://localhost:8000 you’ll see your Gatsby project with a blank hello world template!

Step 2 — Creating our templates

Open up the project in your text editor of choice, I’ll be using VS Code. Open up the /src folder, and inside this there will be a directory called pages. As you’ve probably guessed, here is where all content pages on the site will be held. As we’ve used a starter template, they’ll be a single index.js file that will have a single “hello world” component message in it. Remove this, as we’ll be creating our own components which are used on the index page.

It’s worth noting that Gatsby has the super cool createPage API where you can automatically generate pages based on data, so in theory we could automatically and dynamically create individual film and character pages for all films and characters that we get back from the API. This is a really powerful feature, that really puts Gatsby at the forefront of static site generators, and when leveraged properly can result in a complete website created with minimal coding time. Pretty cool, eh? But for this tutorial we’ll just be using a single index page.

Next, we’ll need to create a folder to create our components. So create a new directory at src called components. So your project structure should be as follows:

src
 pages
   index.js
 components

We’ll be creating two list components, one for the list of films and one for the list of characters. Then we’ll be creating two card components, one to show basic information on each film and one to show information on each character.

Both the films list and characters list components will be shown on the homepage (index.js) and then each list component will show multiple card components.

Firstly, let’s create the films component by creating a filmsList.js file at src/components/films with the following React code:

Here we begin by importing our film card component that we’ll create later, as well as importing React and a scoped CSS module containing styles for our cards, which again we’ll be creating later.

import React from “react”
import FilmCard from ‘./filmCard.js’;
import styles from “../card.module.css”

Then we’re going to use the cards list prop that will be passed through by our index.js file (we’ll get to this later) to create a new array of cards, using the .map() operator. We’ll store all our cards in a constant called “cards”, ready to inject into our

    element.
    const cards = this.props.films.map((film, index) =>
        <li className={styles.film__card} key={film.id}>
            <FilmCard film={film} />
        </li>
    );
    

    Each new card component created in this loop creates a new FilmCard component and passes its film data (such as title, episode number, release date etc) down to it as a prop. We then return a list of cards inside an unordered list element:

    return <ul className={styles.cards__container}>{ cards }</ul>;
    

    Next, let’s create a filmCard.js file at src/components/films with the following:

    Here we’re just creating a card component that will simply show the data that we’ll be returning from the API, such as the episode number, title, director and the opening crawl for that movie. Later on we’ll be coming to how we actually get that data:

    <div>
    
    <h1 className={styles.card__title}>#{this.props.film.episodeId} — {this.props.film.title}</h1>
    
    <h5 className={styles.card__subtitle}>Release Date: <span className={styles.card__copy}>{new Date(this.props.film.releaseDate).toLocaleDateString(“en-US”)}</span></h5>
    
    <h5 className={styles.card__subtitle}>Director: <span className={styles.card__copy}>{this.props.film.director}</span></h5>
    
    <h5 className={styles.card__subtitle}>Opening Crawl: <span className={styles.card__copy}>{this.props.film.openingCrawl}</span></h5>
    
    </div>
    

    We’re following a generic reusable style theme by using the classes card_title, cardsubtitle, card_copy. Nothing too fancy.

    One thing worth noting is that we’re formatting the film’s release date using

    .toLocaleDateString("en-US");
    

    This is because the API returns a JavaScript date object, and we want it to look pretty on our static site 😇.

    Now we’ve got our film components in, we’ll do the same for our character components. Which follow very similarly to our film components.

    And the same for characterCard.js:

    Both sets of components FilmList and CharacterList, and FilmCard and CharacterCard are very similar. The List components just display a list containing multiple cards, and the Card components just show various pieces of information.

    It’s worth noting here that the last bit of data we’re displaying is a list of starships for that character, we’ll be getting an array down from the API so again we’re just using the .map() operator to form a new array of list elements containing just the starship’s name.

    The structure of the project so far should be as follows:

    src
     pages
       index.js
     components
       films
         filmList.js   
         filmCard.js
       characters
         characterList.js
         characterCard.js
    

    Next we’ll head back to the index.js file and import both the FilmList and CharacterList components at the top, so that we can view them:

    Here, we’re creating our home page component, with 2 arrays of objects containing information about the data on films and characters that we’re going to show. Don’t worry, we’ll be seeing this data later when we pull it in from the SWAPI by GraphQL.

    Now we’ll quickly add some styling to our static site.

    As we’re using scoped styling, so we’ll create a file inside our components folder called card.module.css. We’ll be using a number of styles such as title, subtitle, list and copy that we’ll reuse across both film and character cards.

    So add the following code styling to the file:

    Again these styles aren’t massively relevant to the project, they’ll just give us something nice to look at!

    Also create a file called global.css at src/styles and paste in the following:

    This file is a global styles file that will be used across the entire site, here we’re just adding in some basic styles such as the font family.

    So the card.module.css file will contain all styles relating to cards, and the global.css file will contain all styles relating to the application itself.

    You may wonder about the “stars” and “twinkling” div inside the index.js file… this is just to create an animation background of stars twinkling on a black sky background, very nerdy… I know. ✨

    Step 3—Plugging in GraphQL

    So far we’ve not got any data showing in our templates. But now we’ll look into using GraphQL to pull in our data from the SWAPI.

    It’s worth noting however that GraphQL isn’t the only way to pull data into a Gatsby application. Another powerful feature of Gatbsy is that you can pull data from a variety of sources such as markdown files and JSON files, or you can extend Gatsby with source plugins that allow you to query data from CMSs such as WordPress and Craft CMS.

    First, we need to install the GraphQL NPM package for the application:

    npm install --save gatsby-source-graphql
    

    Then we add the following options to our gatsby-config.js file:

    The above just allows us to call the API, and it defines what field we can access the data by (swapi).

    Moving back to our index.js file we need to define the actual query that we’ll be using to retrieve data from the API.

    The beautiful thing about GraphQL is that we can literally specify the exact field names of the information that we want. Rather than returning a massive JSON object full of values, we can specify what exactly we want. We’ll add the following code to our index.js file, which is the query that GraphQL will use to retrieve data from the API:

    The above GraphQL query should be quite self-explanatory. It specifies the information that we want from the SWAPI, including nested data in child objects.

    There’s a lot more data available to us, in fact there’s whole host of data about far more Star Wars things than films and characters and you can find the full list here: https://graphiql.graphcms.com/simple/v1/swapi as well as test out any GraphQL queries here too. But for the purpose of this tutorial we’ll just get basic information on films and characters.

    You can really see the power of GraphQL here, we only request the necessary information from the API instead of returning all information about a film object. We simply just dictate what we want in a predictable and robust manner. GraphQL also has the added benefit that we can returning many resources in a simple request, so instead of completing an additional request to get information on the starships of a character (like we would in a traditional REST API), we can simply append starships onto the end of our characters query. In one simple query we can get a whole host of information from a variety of sources, rather than running multiple separate API calls #GoJamStack

    So, your index.js file should now look like this, with the added query:


    Now we’ve got our query in, we’ll go over our index.js file from earlier and I’ll explain.

    Firstly we’re binding the data retrieved by the API to our template:

    const {swapi: { allFilms, allPersons }} = this.props.data;
    

    Then we’re passing these data bindings to our FilmList component:

    <FilmList films={allFilms} />
    

    And the CharacterList:

    <CharacterList characters={allPersons} />
    

    As you’ll notice here, our earlier bindings to the allFilms and allPersons results are now being used as “films” and “characters” props down to the list components we created earlier.

    We’re also using the following 2 divs to show a fancy twinkling star background in light of our Star Wars theme.

    <div className="stars"></div>
    
    <div className="twinkling"></div>
    

    Now that we’re pulling in the SWAPI data using GraphQL, if you console.log() allFilms and allPersons out you should see the following JSON data in the console:

    Which means our GraphQL query to the SWAPI is successful!

    You’ve seen that from index.js we’re passing our film and character data through to our FilmsList and CharacterList. Below is what our FilmsList component looks like. Here we’re simply just receiving the card props from the parent component (index.js) and creating a new array of FilmCard components with it, then we’re displaying the cards inside an

      .

      This is the same for our CharacterList component

      In our FilmCard component we’ll just display the information we’ve pulled from the API:

      And in the character card component we’ll just do the same for character related information:

      Now we should have a working local website that queries the SWAPI for Star Wars films and characters, passes these results into a list component, which in turn loops through all films and all characters to create card components displaying the information on said films and characters.

      There’s plenty of expansion that could be done to this project, as mentioned earlier there’s a whole host of other Star Wars related information that we could query for and show, and we could even look at dynamically creating pages from the API. But we’ll break off here and build a production version of our site, which would be used to generate the static pages.

      A full version of this project can be seen at: https://github.com/andrewsmith1996/gatsby-js-star-wars-app

      Step 4— Building for Production

      Now that our site is complete, we’ll build it for production.

      First we’ll stop our development serve, and we’ll run the following command:

      gatsby build
      

      Then we can view our production site locally to double check that everything is okay:

      gatsby serve
      

      Now we have a production build of our Gatsby site, ready to go live.

      To prove how fast Gatsby sites really are we’ll run a Google Lighthouse audit, which will give us back some information on page speeds and performance. Google recommends using this as a way to assess the performance of PWA.

      Open the site in incognito mode in Google Chrome, and go over to the Audit tab and click “perform audit”.

      Once the audit has completed, you should see the following statistics about our site:

      The above statistics really do show how well Gatsby performs and how fast it can run due to only returning static content, ultimately conforming to our trend of high-end web performance. Especially given that we’re doing API calls to an external service at runtime.

      Conclusion

      So, we’ve created our sample application in Gatsby, and we’ve seen how powerful, fast and efficient a static site can be and how they can be created with bare minimal code and setup.

      We’ve seen how React can be utilised to maintain the aspect of building a single page application and how GraphQL can be a really elegant solution in terms of querying data for your application. Gatsby.js isn’t the only static site generator that’s out there, there’s Jekyll, Hugo and Gridsome (for Vue.js), which people are saying good things about. But Gatsby.js is a great choice for creating super efficient and extremely fast sites straight off the bat, and with the ability for Gabsty to be extended with plugins, the wide range of data sources that Gatsby can pull from and the ability to dynamically create pages from data with just a few lines of code using its createPage API really set it out there as a top static site generator.

      Static site generators are sure to continue growing, and as the trend of ultra high-end web performance emerges with applications such as PWAs and serverless systems, and the JAMstack becomes more and more popular in the field of web development we’re going to move into a new era of ultra-fast, performance-centred, security conscious client side applications that offer a great experience for both users and developers.

      References:

      1: https://medium.com/pinterest-engineering/driving-user-growth-with-performance-improvements-cfc50dafadd7

      2: https://www.creativebloq.com/features/how-the-bbc-builds-websites-that-scale

      Discussion

      pic
      Editor guide