Single Page Apps with Gatsby

Last edited on November 04, 2019
Photo by Tim Trad on Unsplash

Gatsby, which is a static site generator, is famous for blogs and documentation websites. But there is no wrong in build full blown React apps with it.

In the case of a blog, Gatsby builds a page for every article at the build time and generates a directory which can be hosted directly. But when it comes to Single Page App (SPA), we have only one index.html at the root, and the components are loaded depending on the route that the user is in.

We can get the benefits of code spitting with some React lazy suspense features with some minimal extra work too.

1const Contact = React.lazy(() => import('../components/Contact'));
2const LazyContact = (props) => (
3 <React.Suspense fallback={'<p>Loading...</p>'}>
4 <Contact {...props} />
5 </React.Suspense>

The Contact component is loaded only when it will be rendered, which is when we hit a particular route. We will have a look at the routes in a moment.

But wait

Before that, we need a gatsby-node.js file to let Gatsby know that we want all the route to end up in index.html

After cloning Gatsby’s Default starter, let’s add this file.

1// gatsby-node.js
3exports.onCreatePage = ({ page, actions }) => {
4 const { createPage } = actions;
5 if (page.path === `/`) {
6 page.matchPath = `/*`;
7 createPage(page);
8 }

Now we are ready.

Components for each Routes

Let’s plan to have two routes, /contact and /about . In src/components we will create basic components like this.

1// src/components/Contact.js
2import React from 'react';
4console.log('contact component');
6export default function () {
7 return <div>Contact Us as you like.</div>;
10// src/components/About.js
11import React from 'react';
13console.log('about component');
15export default function () {
16 return <div>We are a great bunch of people</div>;

I’ve added the console logs to check when this file is loaded. We don’t want it to load at the homepage. Rather only when the route is visited.

Main App

In the main page, which is src/pages/index.js we make use for @reach/router which Gatsby itself, uses for routing.

1// src/pages/index.js
3import React from 'react';
4import { Router, Link } from '@reach/router';
6const Contact = React.lazy(() => import('../components/Contact'));
7const About = React.lazy(() => import('../components/About'));
9const LazyComponent = ({ Component, ...props }) => (
10 <React.Suspense fallback={'<p>Loading...</p>'}>
11 <Component {...props} />
12 </React.Suspense>
15const Home = () => <h2>Hello and Welcome</h2>;
17const IndexPage = () => (
18 <div>
19 <h1>Hi people</h1>
20 <Link to="/">Home</Link>
21 <br />
22 <Link to="/contact/">Contact</Link>
23 <br />
24 <Link to="/about-us">About Us</Link>
25 <br />
27 <input />
29 <Router>
30 <Home path="/" />
31 <LazyComponent Component={Contact} path="contact" />
32 <LazyComponent Component={About} path="about-us" />
33 </Router>
34 </div>

LazyComponent renders the Component we pass to it as a prop under React.Suspense with a fallback.

If you build this project and serve, you can open the Networks tab in the browser console and see that a new JS file is loaded when you hit the /contact route for the first time.

That’s it, this is all we need to make an SPA using Gatsby.

Here is a working codesandbox link -

Aravind Balla

By Aravind Balla who is a friendly human, building things for himself, and sometimes for others. You should hit him up on Twitter!

Copyright whenever. This site is opensource.
mail | twitter | rss