“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.
- Minimal tech lock-in
- High lighthouse score (95, at least)
- Try to reduce bundle size as much as possible
Checkout this page for the full list of sources, attributions, and colophon.
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 blocksThey 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.
If you don’t believe me:
Cmd + alt + I
Cmd + shift + P
Click “Generate Report”
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.
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.
This site was another excuse to experiment with 3D graphics, shaders and WebGL. Three.js was ruled out from the start because of its
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.
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.
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.
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.
As with most things in development, there were a few surprises along the way, so here’s my wish list for the Gatsby team:
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.)
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
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.
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.
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.