Logo with initials

Under the hood: Tech Stack

──── 6 mins#Code, #WebGL

Last Updated: January 28, 2021

“What did I get myself into?”

I wondered that many times during the development process. Why on earth did I choose Gatsby, and bother with React, Remark, CSS Modules, and GraphQL? When I could just use the old Jekyll. In this article we’ll have a look at my technical choices.

Disclaimer: For brevity’s sake I’m assuming a fair amount of prior knowledge. If you would like to learn more about something mentioned here, let me know on Twitter.

Requirements

  • Minimal tech lock-in
  • High lighthouse score (95, at least)
  • Try to reduce bundle size as much as possible
  • The reading experience works without JavaScript

Checkout this page for the full list of sources, attributions, and colophon.

Minimal tech lock-in

I don’t want my site to rely on a specific technology too much. I don’t use CSS-in-JS, I hardly use React hooks or component methods, and favour implicit declarations over “Gatsby magic.” Everything should be easy to reproduce with another generator.

I feel like I made the right choice with Gatsby, and it boils down to two time-saving elements: plugins and built-ins.

Do you want a dark mode? Here’s gatsby-plugin-dark-mode. Crazy WebGL graphics with glslify? You’ve got gatsby-plugin-glslify. An RSS feed? Yep. Gatsby even optimises my images, and adds aria-current to active links.

On the Markdown side of the house, I dearly missed Jekyll’s fantastic defaults, but again: Plugins! Remark (the markdown processor) has itself a thriving ecosystem.
See for yourself:

I got custom blocks They expand!

I got footnotes1.

And the table of contents was auto-generated.

I’m also pleased that I didn’t have to fiddle with Gatsby internals too much.

High Lighthouse score

If you don’t believe me:
Cmd + alt + I
Cmd + shift + P
Type “lighthouse”
Click “Generate Report”

Hand-drawn images

I wanted to avoid the situation where you read in dark mode and BOOM 💥 you get a chart on a white background. To remedy this, the drawings change their line and background colours depending on the theme.

The graphics are exported from Excalidraw and automatically inserted as inline SVGs and optimised with SVGO.

It turns out, it’s even more efficient than using normal JPEGs!

The JPEG of a single drawing is about 100KB. An SVG is less than 10KB. But that’s without the font. The font alone is 117 KB, which I stripped down to 38KB with a bit of subsetting magic.

So 2 JPEGs = ~200Kb vs. 2 SVGs + 1 font = 58KB

The more there are, the more worthwhile the savings.

Performance and Bundle size

Throughout the development process of this site I was ruthless when it comes to dependency sizes:

  • I run every dependency through package-size to make sure there isn’t a smaller alternative, and that it’s worth its cost.
  • The fonts are compressed as Woff2 files, self-hosted and stripped of their unused glyphs.
  • Preact is used to make the Gatsby/React runtime at least 30% smaller.
  • Images use WebP compression with the <picture> element where possible.

WebGL sites tend to have needlessly large bundle sizes, here’s my answer to that.

WebGL

This site was another excuse to experiment with 3D graphics, shaders and WebGL. Three.js was ruled out from the start because of its ridiculously big JavaScript footprint. I tried to strip most features out of Babylon.Js but still, the bundle was enormous. I ended up using Regl 👑 which is way more lightweight but more low-level, (you have to write GLSL). It’s battle-tested, has been stable for years2, and isn’t changing any time soon.

I’m keeping an eye on OGL which is an even smaller WebGL library and even gives us a scene graph out-of-the-box, but the API isn’t final yet.

Here’s how they compare (minified size):

  • 632.33 KB – Three.js v0.120.1

  • 110.85 KB – Regl v1.6.1

  • 98.39 KB – OGL v0.0.60

Picking Regl over Three.js saves us 500kb, more than a five-fold decrease in bundle size. Performance was also paramount. My goal was a smooth 60fps experience on my old budget Android.

Thanks to Gatsby’s code-splitting, the WebGL library is only included in the homepage.

Homepage sketch

First, I wanted to create a fractal. They have always fascinated me, whether in code or in nature. There are a lot of fractals to choose from in 2D, but in 3D they’re kind of hard. The only one that I could wrap my head around quickly was the Menger sponge.

Menger Sponge Fractal

The 1st homepage sketch: 160 000 cubes forming a Menger sponge fractal

After adding a bit of instancing magic, there it was. 60fps and all, except boring to look at. I tucked that code away and turned my attention to another piece of Math & Magic that I had wanted to play with: attractors.

The Nosé-Hoover Attractor

The 2nd homepage sketch: Cubes along a Nosé-Hoover attractor

Despite running at 60fps it “felt” sluggish and became boring to look at.

The final attempt at shoehorning adding 3D graphics to this is what you can see on the homepage now.

Gatsby wish list

As with most things in development, there were a few surprises along the way, so here’s my wish list for the Gatsby team:

Become evergreen by default

I wish Gatsby’s relationship with older browsers was an “opt-in” one as opposed to “opt-out.” I prefer a lean website out of the box, with features like WebP enabled and Polyfills removed by default. I would rather add backwards compatibility if necessary. (Right now you have to disable polyfills.)

Disparity in plugin quality

Gatsby makes it easy to find plugins, and to know which ones are maintained by the core team. Despite this, there is a huge variance in the quality of the non-official plugins. I wish more things were parsed out of the plugin repository (like the number of open issues without a response) as some are still referenced despite deal-breaker issues.3

Telemetry

That should absolutely be disabled by default from the stable release.

I understand the idea, but knowing that a seemingly innocuous CLI might transmit data when I’m not explicitly asking it to is scary, and sets a dangerous precedent. The logs may be “anonymised” but doing this is extremely hard and a waste of time.

If it’s not disabled by default, then “How to opt-out of telemetry” should at the very least be part of the kick-start tutorial (like VSCode does) and not buried in the documentation. I would even argue that the CLI should ask for again permission every once in a while.

Drop React altogether in favour of Preact.

I can only hope. I understand why Gatsby wants to to be compatible with all the existing React packages. But in my opinion you don’t need that in a static-site generator. People won’t use react-emoji-picker in a Gatsby site. They need their website to be fast and lightweight.

For now, I’m thankful that the Preact plugin exists and is supported by the core team.

Final words

On top of everything mentioned above, I wrote scripts, GraphQL queries, learned about CSS grids, Exif data, and more. I feel like I’ve come out of it as a better coder.


  1. Here’s a rocket 🚀.
  2. Mikola, the creator of Regl, even moved off-grid to a lava field at one point and no problem happened.
  3. Let me say it loud and clear: People are not obligated to maintain everything they create. I’m just asking Gatsby to help me identify which plugins are in fact, maintained.