A guide for evaluating the effort involved in migrating a webapp to Gatsby

This blog post will serve as a guide for those who wish to migrate their website to Gatsby. This was the vetting process we followed at Hasura.io to check if it was a good idea to move our website to Gatsby.

Why Gatsby?

tl;dr: With Gatsby your pages will load extremely fast. You also get automatic SSR for your react app. Moreover, you can leverage Gatsby’s rich plugin ecosystem to build your apps.

Gatsby is a static site generator for React. A Gatsby site gives you client side code splitting and lazy loading of assets out of the box. This means that Gatsby gives the browser a complete page as a single file. All the necessary CSS and images are embedded in the page. Only the CSS really needed for that page is included. Gatsby also performs prefetching. After a page is loaded, it fetches data for all the other pages that are linked on the loaded page. This makes user navigation extremely fast.

A complete list of what you will get with Gatsby can be found here.

Since Gatsby is built over React, the developer experience is the same as developing a React app. So you get automatic SSR for your react app.

Gatsby also has a mature plugin ecosystem. These plugins handle a lot of use cases and can be leveraged in any Gatsby app. Gatsby is also highly customisable and makes it very easy to develop custom plugins.

When is it most suitable to consider Gatsby?

Gatsby is basically just a react app and you can ideally build any webapp on it. To make the most of its features, it is best to use Gatsby if:

  • You are comfortable developing in React or if your app is already built on React.
  • You require SSR pages for your website.
  • Your website content does not change very frequently (once every half hour or so).

Evaluating the effort

Ok, so you have decided that you want to use a static site generator for your web app and have decided to go with Gatsby.

Start off by splitting your app into

  • Static pages
  • Pages with dynamic content
  • Programatically created pages
  • Non SSR or client side pages

Let’s take a look at what each of these pages are and how they can be implemented on Gatsby.

Static Pages
Getting these setup in Gatsby is very straightforward. If you are okay with the routes that it provides by default, every component inside the src/pages directory will be rendered (index.html at / and every other file at /filename)

Pages with dynamic content
These are pages which rely on some external database to load its contents.

To do this in Gatsby, you will have to

  • Add this data from the external source into the internal Gatsby data store. This can be done with the help of the sourceNodes API and the createNode method in your gatsby-node.js file.
  • Access this data from the internal store in your react components using GraphQL APIs.

If this page also shows some data which updates very frequently, you can basically build a “Hybrid” page. You can read about this in their docs. Going with this method, Gatsby will first render your page and then load the React components. Once the React components are loaded in the browser, you can then fetch the data from your APIs.

Programmatically created pages
Sometimes you will have a set of pages which you would want created based on your data. A set of pages showing details about a Product in an e-commerce website is a good example of this. In this case, based on your data (available products) you will render a page for each product.

Programmatically creating pages includes these steps

  • If you are dependent on external data, then you need to add the external data to the Gatsby’s internal data store.
  • You need to implement the createPages API in the gatsby-node.js file to programatically create the pages.
  • Create your React component for these pages and put the component inside the src/templates directory.

Note: If you want custom routes for your static or dynamic pages, you can use the createPages API and move your component inside src/templates directory.

Non SSR or client side pages
These are pages that are not static and should only be rendered on the client side. These include login pages, a console or a dashboard which is dependent on user sessions.

These can be created with the help of the onCreatePage API in the gatsby-node.js file. You can read up about this here.

Common requirements

You will also have a few other requirements or configurations that are currently working in your app. The ones mentioned below are the ones that we have with hasura.io

  • Webpack configuration
  • Styling
  • Pagination for list pages
  • Redux for state management
  • Routing

Custom Webpack configuration
Gatsby comes with a default webpack configuration. But you can modify this configuration in your gatsby-node.js file by exporting the modifyWebpackConfig function. You can modify the configuration as per the webpack-configurator configuration. Check here for examples and docs.

Styling
In the case of Hasura.io, our requirement was to have support for .scss files and bootstrap. This was also quite easily possible in Gatsby.

There is a Gatsby plugin called gatsby-plugin-sass that can be used to provide support for .scss files out of the box. You can read the documentation here to include it in your project.

As for bootstrap, install it by running npm install --save-dev bootstrap and then include it in your styles with a @import ‘node_modules/bootstrap/scss/bootstrap.scss’;

Pagination
Pagination is a very common use-case for listing pages. Handling pagination is also quite straightforward with Gatsby. You can make use of the gatsby-paginate plugin to get this done easily.

Redux
Gatsby works quite well and easily with Redux. The only configuration required is to provide your store and wrapping a component with the Provider in the gatsby-browser.js and gatsby-ssr.js.

The best way to see this working is to check out the example here.

Routing
Routing is provided out of the box by Gatsby. It does this by rendering every component inside the src/pages directory at the route /<filename>.

For custom routes, you have to export the createPages function inside the gatsby-node.js file and then provide the route path and the path of your component to the createPage method. Usually, these components are placed inside the src/templates directory.

Your build and deployment process

Deploying a Gatsby app is as simple as serving static files.

You start with the build process by running gatsby build and then serve the files in the public/ directory. You can find instructions to deploy Gatsby on various static site hosts here.

The thing to keep in mind is that every time your data changes, you need to run the build process again and then serve the newly built files. Hence, while considering migrating to a static site generator like Gatsby, you need to account for your current build and deploy process and check how it will fit in with Gatsby’s workflow.

Summary

Although porting the features and requirements from our current implementation of hasura.io to Gatsby is possible, there are a few things we are hoping gets better or is figured out before we actually perform this migration:

Data updates

There are two major ways to handle data updates,

  • Setup a cron to rebuild your app every n minutes.

Laggy Updates
The issue with setting up a cron is that your data updates will lag based on the frequency of your data update and your cron. For existing pages, we can handle this by updating the data from the react component after the page has loaded. But if your data change requires a new page to be generated programmatically, they will not show up immediately.

  • Rebuild app for every data change.

Non trivial to setup
You need to setup some form of workflow where you detect data changes and either rebuild on every change or prioritise changes and rebuild only on important updates. Unfortunately, this isn’t something that you will get out of the box and hence will require some time and effort to implement.

Longer build times
As your data keeps increasing, your build times will get longer. Incremental builds are therefore, the need of the hour! Although it is not present in the current version of Gatsby (v1), it is set to come out with the v2 release. So this is just a matter of time.

Incremental builds with Docker
At Hasura, we have a Docker and Kubernetes based deployment process. Utilising the incremental build process of Gatsby will be non trivial. A docker based incremental build process is something that needs to be supported by Gatsby (or maybe we will contribute to Gatsby with a solution).

External Data Source

Currently, if you have an external data source, you need to include it inside Gatsby’s internal data store. You can then access this data using GraphQL APIs from your React components. This process, albeit neat, is a little redundant if you already have an external source which supports GraphQL APIs. You now need to fetch this data during build, convert it to fit Gatsby’s internal store and then specify another GraphQL API to get this data in your React component.

This process can be avoided if Gatsby provides support for GraphQL schema stitching. This will make the experience of developing Gatsby apps with external data sources (which support GraphQL) super awesome. You can conveniently avoid the whole process of retrofitting your data into Gatsby’s internal store and directly query it from your React components.

The Hasura platform provides out of the box GraphQL data APIs and we would like to use them directly. This is also a feature that hopefully is set to come out with the next version (v2) of Gatsby.

Hasura.io migration verdict

Although, Gatsby is awesome, hasura.io migration will have to wait until we have

  • A docker based incremental build and deployment process setup.
  • GraphQL schema stitching

Having said all of the above, a thing to note is that Gatsby is open source and very modular. It is very easy to add features to it. Moreover, Kyle Mathews (Creator of Gatsby) is open to contributions. So, if you wish to use Gatsby and are reluctant because of a few features, you can very easily implement those features by forking the repo or just contributing to Gatsby.

Psst…. Have you tried deploying a Gatsby web-app on the Hasura platform? It is literally the fastest way in the world for deploying fullstack apps to an HTTPS domain (with just a git push).

Get started with a basic Gatsby project here: https://hasura.io/hub/projects/hasura/react-gatsby

All project boilerplates on the Hasura platform come with a Dockerfile and Kubernetes spec files that you can customize as you wish!


Hasura is an open-source engine that gives you realtime GraphQL APIs on new or existing Postgres databases, with built-in support for stitching custom GraphQL APIs and triggering webhooks on database changes.


Hasura

Hasura

The Hasura GraphQL Engine gives you realtime, high performance GraphQL on any Postgres app. Now supports event triggers for use with serverless.

Read More