Reasons to Migrate away from Gatsby

Gatsby is a site generation framework. I recently was using it for one of my side projects, sff.life, a site dedicated to small form factor computing (eg: small computers). I decided to migrate away from Gatsby, as it is not a zero cost abstraction for static sites for two reasons:

  • Needless bloat via javascript and JSON bundles
  • Way too many dependencies and releases

Before I give a bit more background and expand on these reasons, I still believe that in many situations, Gatsby benefits outweigh the costs. In this way, Gatsby isn’t “bad” insomuch as one (ie: me) should be privy to exploring the simplest solution first.

Background

I had initially settled on Gatsby as I had used it for another site that I created for a friend. This friend is not technical and so any content they would add would have to be done in a user friendly way. Netlify CMS allows one to make edits in the browser and when coupled with Gatsby, the in-browser preview is quite convincing as one constructs a Gatsby site through Javascript. This made for a great solution for the non-technical and despite the downsides (which we’ll get to), I’d still consider deploying Gatsby + Netlify CMS for non-technical folks.

So since I already had working knowledge of Gatsby, I decided to use it for project for myself, documenting my journey through SFF. I had grand visions of allowing contributors who could help via a non-technical interface. It’s been awhile since I’ve written content for it, as life has gotten in the way until fall, when I plan to breathe life into it again. However, Gatsby has also gotten in the way.

Screenshot of https://sff.life, a site I transitioned away from Gatsby

Screenshot of https://sff.life, a site I transitioned away from Gatsby

Bloat

Gatsby is not lying when it claims that it is blazing fast. It is fast.

But there is a lot of room for improvement.

When using Gatsby, requesting the article How to undervolt your ryzen cpu results in 18 network requests and a total of 504 kB of resources. As a comparison, requesting the article at the time of this post, only 6 requests are made with 143 kB of resources. That’s a 3x reduction in number of requests and data transfer – a marked improvement.

Where did all of the Gatsby bloat come from? Two major factors: javascript and JSON. And here’s the thing, I can’t tell you why Gatsby needs to bring down 300 kB of this stuff. For instance, there is a page-data.json that is fetched (100 kB) that contains the markdown from which the page was converted. Why a static site would need to see how it was rendered is beyond me and I tried to dig frantically in the gatsby docs over several days to find where this was coming from and remove them. No dice. This made me realize that gatsby is adding too many abstractions on top of a site generation for me to be comfortable with.

I believe there are solutions (or more likely – there are plugins) that can help strip away needless javascript and JSON, but this will clearly be going against the Gatsby mantra.

Here’s a couple of statements from the Gatsby team that I’d like to examine that illustrates their viewpoints on JS.

From the creator of Gatsby:

Why remove JavaScript? That disables your React components on the client, slows down page transitions, prevents service workers from preloading page data, etc.

From the 2nd top contributor on removing JS

you would [lose] a lot of functionality like page prefetching and in-browser navigation, lazy image loading, etc.

I agree that javascript is an integral part of the web, and it’s important to use it to the full extent in web apps, but I would prefer it is not shoved down throats for sites that don’t need it.

For non-apps, I do not see the benefit to page prefetching and in-browser navigation. Visitors to a blog most likely arrived via a google search or a link and are interested in only that one page. Therefore priority number one should be loading the initial page as quick as possible so they can see the content. I do not understand why there would be a significant focus on prefetching and navigation – content is king, let’s focus on getting that in front of the user as fast as possible.

To address lazy loading images – I have good news, browsers natively can lazy load images without any JS as shown below

<img src="my-img.jpg" loading="lazy" />

70% of all users’ browsers support lazy loading images. This percentage will only increase in time, and while 70% is not as comfortable as 90, 95, or 99%, when working with a side project, if a majority of your users can take advantage of an emerging standard then I’m happy to drop the JS.

The Gatsby team isn’t blind to natively supported lazy load images as they will also tack on loading="lazy" (or is it via a plugin?) to the generated page.

I’m satisfied with how I’ve addressed their need for JS, and how it’s not as widely applicable as they imagine. Though, interestingly, it also sounds like Gatsby advertises that it is faster than any equivalent site: from the creator of Gatsby:

PWAs are faster and use less data than a normal website. It’s a bit counterintuitive but in 2017, removing JavaScript makes your site slower and waste more data.

The quote is a bit dated, but I don’t think the author has changed opinions. The quote seems to be implying that all sites should be PWAs. A List Apart’s “Yes, That Web Project Should Be a PWA” agrees with that sentiment, though it acknowledges that PWA’s “oft-touted ‘major’ benefits […] are less applicable” for such a simple site like SFF.life. So when a site requires zero javascript, introducing javascript strictly for PWA seems like a inefficient use of my time and the visitor’s resources.

I also am struggling to follow the second half of that statement, “removing JavaScript makes your site slower and waste more data”. I wish the Gatsby creator elaborated or provided a link because intuitively if I serve a page to a visitor who is only ever going to visit once and this page is as small as possible (no js, inlined css, lazy loading images, etc), then adding anything at all will, by definition, make the site slower and consume more data.

I also have a hypothesis that executing javascript is more draining on the battery than not executing it. To me this seems like an obvious statement (doing something should be more taxing than doing nothing). On the topic of javascript and batteries, recently Chromium announced consideration in throttling javascript timers of background tabs to conserve battery. While I believe Gatsby doesn’t use the affected APIs, it’s undeniable that javascript does have a tangible effect on batteries.

Dependencies

To do anything in Gatsby, a plethora of plugins are needed. Sff.life, as simple as it is (a point I can’t stress enough), needed 21 direct dependencies. These 21 dependencies explodes into a 21k line package-lock.json. A large lockfile seems unmanageable, as one of the recommendations for mitigating vulnerabilities introduced via lockfiles is to “Carefully review changes to lockfiles”, but that won’t be happening to a 21k line file that is for a side project.

Don’t get me wrong, I can appreciate a slim core with plenty of extensibility points; however, Gatsby takes it to the extreme. Less than 4% of the commits on the site are authored by me. I’ve made 40 commits and dependency updates are over 1000 commits. This is in the span of less than a year. That’s hard to stomach and makes me numb to dependency updates. I should be attentive, ensuring that nothing nefarious sneaks in or just keeping up with what’s new or bugs fixed, but I just can’t. Waking up to hundreds of emails about new dependencies prompted me to create a separate email folder that is essentially black holed and ignore github notifications.

Just take a look at the Gatsby Github page and see how many releases there are:

Gatsby and their 13,000 releases

Gatsby and their 13,000 releases

Yes over 13,000 releases. This is almost hard to fathom.

There’s a potential monetary cost to all these dependencies updates. Previously I’ve praised Netlify CMS + Gatsby combination, and one of these benefits is that whenever there was an update to the backing repo, Netlify would build and deploy the latest version. The issue is that when there are so many dependency updates, one quickly closes in on the max allowed build minutes on the free tier. I normally have no problem paying for rendered services, but this is not one of those times.

Maybe upselling builds is how GatsbyJS (the business) drives most of their revenue. But if it’s not already the case, it wouldn’t be a bad idea for Netlify (and maybe other CI / CD companies) to sponsor Gatsby. Make it seem that Gatsby should be used for every situation no matter how simple (a hobby project or personal blog) – then watch as the users are unable to cope with pace with dependencies updates and are forced onto paid plans.

The Solution

Can we reduce the bloat and dependencies? If not then this would be a pretty somber post, but it turns out we can. While I will be recounting the solution I settled upon, keep in mind that any dedicated static site generator will probably be sufficient.

Without further ado, I replaced Gatsby with Hugo. You can view the pull request for in depth details on the change, but it was remarkably straightforward, mainly fixing file paths, and adding a custom shortcode so that images are lazy loaded and sized appropriately.

Some notes on why I chose Hugo:

Hugo is a single binary that can be downloaded and installed easily for any platform.

Hugo extended bundles a SASS compiler, so I could install sanitize.css via npm and write SASS that references this dependency. I have hardly any experience with SASS, but the fact that SASS is included out of the box and can reference node_modules made me ditch postcss in a heartbeat. The new package-lock.json file is now 13 lines.

Hugo has a built in image processing pipeline. I make good use of it to create an array of images at varying sizes so that users don’t have to waste data and time downloading a high fidelity image when a smaller one would suffice.

CI Build times have decreased as well. Here are some back of the envelope timings:

  • old (gatsby): 120 seconds
  • new (hugo): 30 seconds

I enjoy that Hugo abstracts away all of their internal dependencies. When Hugo creates a release, it’s implied that it is a bundle of internal dependencies that work well together. One is not always so lucky when piecing together a mish-mash of javascript dependencies.

Conclusion

Hopefully it’s a bit more clear where Gatsby doesn’t shine as bright. I routinely see articles spinning Gatsby as the panacea for all web sites, and I just wanted to add a dissenting view to the conversation. To me, there’s a time and place for Gatsby, but it’s not for those projects that desire minimal maintenance, cost, and bloat.

Comments

If you'd like to leave a comment, please email [email protected]