Switching to Gatsby

14 min read

With Jekyll getting long in the tooth, and wanting to force myself to learn a new programming language, I looked at switching this blog over to Hugo or Gatsby. Gatsby won, but here's what I learned.

While I still kinda lurv Jekyll, I'd been wanting to force myself to use languages I'm not particularly a huge fan of, Golang and javascript/typescript. A consistent (and accurate) joke amongst my staff is that I only really enjoy programming in languages that look like Ruby (Elixir and Crystal being the usual suspects here.).

I've found forcing myself to use things in daily use and personal projects to be one of the best ways to get myself proficient in a language. YMMV. But, where I'd normally reach for one language, forcing myself to use another until it doesn't hurt any more has been a consistent win for language learning.

The blog is a good case in point. While Jekyll is a fine static site generator blog software is a great gateway drug for me for messing with either Gatsby and Hugo, the two other static site generators in this case.

Hugo is fast and shares a lot of the same design ideas as Jekyll in my opinion, whereas Gatsby seemed to take a different approach and is built on top of the React frontend framework. In fact, I'd say liking (or wanting) to get across React is probably part of the decision you need to get comfortable with if you are going with Gatsby.

While I have to admit getting stuff up on Gatsby was easy, particularly in terms of front-end issues, bending it to my will and the vagaries of javascript was a little annoying at times and made the migration take longer than I would have liked. Admittedly, if I was better at js this probably would not have been the issue it was, but even then, doing some thing was much harder than it should have been and you do seem to need to know quite a bit about node and react internals in order to really make things easy for yourself (I, obviously, do not... yet) and I have to admit to missing simple tools in ruby land like rake to make my life easier (currently trying to replace those things with MS's Just) as those were not critical path.

There are some very clever things you get with with Gatsby though and despite the fact I think it makes your end build code more complex and opaque there is more than a few things to love about it. This is what worked for me:

Lurving

1. Speed optimizations and frontend ease

Gatsby does a startling number of front end performance optimizations and improvements without you touching a thing. Gatsby automates code splitting, inlining critical styles for performance, image optimization, prefetching resources, and lazy loading plus some other optimizations that make things run fast. It's not just that the site was faster in benchmarks, it was noticeably faster and more responsive as someone using it. And this was out of the box.

The fact that links are preloaded and the thing is basically an in-browser app when loaded now makes the site vastly slicker and more performant. Additionally, some plugins like purging unused css and similar things has made code lighter and contributed to speed as I added in plugins.

Strangely, working through my own css code in places since I could use npm installed libraries, also pointed out to me a few problems I'd made in designing the original site, so more sane organization also made a difference. Am not sure, that could just have been my poorer frontend skills, but I do feel like the site is a lot better organized and efficient now. as noted, with gatsby, it is demonstrably and perceptibly faster.

2. GraphQL for every data source is the bomb

Alright, I have to admit to having been a graphQL sceptic up until the last year, and to be frank, felt that using it in a static site generator was a sign of sheer over-engineering, but it a great innovation. In fact, I'd say this may be the main reasons I finally decided on Gatsby over Hugo.

Basically, allowing any data source to be accessed and queried via graphQL suddenly made a lot of things much, much simpler. In my original system where I'd used a bunch of glue to paste together markdown, external data sources, and even structured data files like yaml, now I've got a consistent way to grab disparate data sources, combine them into single queries, as well as a better way to diagnose them (and an in-built interface at http://localhost:8000/___graphql to both see those capabilities self-documented and test them out.). I know I'm gushing here, but this was actually the biggest thing that made me go... "oh yeah, this is great." There are some quirks in how you need to alter things to deal with this reality, and I have to admit it can seem overly verbose depending on how structured and deep your data is, but overall it's so great I wonder why almost every other static site generator has not adopted it.

3. Amazing plugin ecosystem

One of the things that often irks me with low level programming languages (yeah, looking at you, Go) is having to do things which, for me, should be effectively "lego snap-in" functionality that I should just be able to bolt on and call via library. While Jekyll was decent on this front, it was also because a number of my things were quite simple, and where they weren't I could bend the templating language (Liquid, which I dislike) to my bidding.

The library of plugins available for Gatsby is stunning. There is not a single thing I googled for that didn't have a plug-in I couldn't use to bolt on that functionality. Sure, you can argue it makes me less a programmer, but to be honest, I'm trying to have a blog here, not build a full blown app. From handling rss to sitemaps to responsive images and video, I'd have to say the plugins were all better, not to mention some like gatsby-plugin-s3 which replaced a much more complex ruby and scala wrapper (s3website) for deploying to S3 and handling Cloudfront caching and invalidations (admittedly, s3website is much more feature rich, but again... it's a blog.). Impressed and happy. Configuration on many of these things was straightforward, sensible, and easily modified to my needs.

4. Event handling

While I'm sure js pros will scoff at this one, and really this feels more like an advantage of using React for Gatsby than Gatsby itself, one of the things I've always really disliked about integrating javascript functionality with your designs is event handling. For Gatsby, this is completely painless due to React having fire and forget event handling. Simple, easy, gets it done. Made me rethink my idea whether React was overkill for Gatsby or precisely the right choice here just on this feature alone.

For example, if you're used to using a js file for attaching event handlers to front end events, the fact React gives you this for free and cleans up the entire thing for you in a contained function is amazing, but figuring this out required (for me) quite a bit of digging through blogs, github issues, and the React and bulma docs to figure out what to do (which is why I am putting the entire relevant portions here for whoever needs to find out how to use the navbar-burger menu bar dropdown onClick - excuse the google juice.).

This is how to get the onClick event on the mobile navigation menu working for the Bulma css framework in Gatsby. Note the hamburerHelper() function before the return render and the <a role="button" class="navbar-burger" onClick={ hamburgerHelper } data-target="navMenu" aria-label="menu" aria-expanded="false"> directive in the JSX to trigger it. You do not have to attach an event handler to these things as React sorts that for you automagically. Here was how my navigation menu component (named header.js) looks:

// header.js
import React from 'react'
import { Link, graphql, useStaticQuery } from 'gatsby'

function hamburgerHelper() {
        const nav = document.querySelector('#navMenu')
        if(nav.className == "navbar-menu") {
            nav.className = "navbar-menu is-active"
        } else {
            nav.className = "navbar-menu"
        }
}

const Header = () => {
    const data = useStaticQuery(graphql`
        query {
            site {
                siteMetadata {
                    title
                }
            }
        }
    `)
    return (
        <nav class="navbar is-fixed-top has-shadow" role="navigation" aria-label="main navigation">
        <div class="container">
            <div class="navbar-brand">
                <Link class="navbar-item" activeClassName="navbar-item is-active" to="/">
                    { data.site.siteMetadata.title }
                </Link>

                <a role="button" class="navbar-burger" onClick={ hamburgerHelper } data-target="navMenu" aria-label="menu" aria-expanded="false">
                    <span aria-hidden="true"></span>
                    <span aria-hidden="true"></span>
                    <span aria-hidden="true"></span>
                </a>
            </div>

            <div class="navbar-menu navbar-end" id="navMenu">
            <Link class="navbar-item" activeClassName="navbar-item is-active" to ="/blog">
                Blog
            </Link>
            <Link class="navbar-item" activeClassName="navbar-item is-active" to="/projects">
                Projects
            </Link>
            <Link class="navbar-item" activeClassName="navbar-item is-active" to="/about">
                About
            </Link>
            </div>
        </div>
        </nav>
    )
}

export default Header

5. Interactivity despite being static

While not strictly related to Gatsby as blog software, the fact that there is so much capability to make a static site into something interactive is very compelling.

While I'm resisting the desire to add unnecessary flash, I would actually tackle a bunch of common things people ask me to do right now with a static but interactive frontend to backend commodity services, rather than trying to wing those as programmed functionality or on-server features to avoid running my own servers.

Seriously, kinda the bomb in terms of allowing you to think about serviced functionality through an interface rather than having to manage and deploy production functionality and servers.

Not Lurving

1. Opaque errors and debugging difficulty

Alright, I realize the amount of hate spewed on javascript and ginormous and ridiculous stack trace calls is legion, but particularly for a newbie at Gatsby, when things did go wrong (and particularly between npm run dev and npm run build) it sucked up an inordinate amount of time figuring out what happened.

Not a fan and to be honest, though I've been getting spoiled by clearly thrown errors and even suggestions of how to fix things like in languages like Crystal and Elixir (and even Go Lang). I may try to double down on typescript to see if that helps in this department but definitely made me think twice when thinking about whether I really wanted to move over to a language stack solution that I was beating my head against the table in terms of trying to understand why things went wrong (and to be really damning, the errors were often nothing to do with the actual problem.). For some strange reason, this seems to have improved slightly in recent days and not sure it's because of npm upgrades or me coding js better, or me just getting a better grok on what goes wrong more often.

2. Datetime formats

OK, this one seriously was irksome. And admittedly, a number of my complaints are about javascript, not Gatsby itself, but one of the things I spent a huge amount of time tracking down was js throwing a fit over human readable data formats that seemed bog standard to me.

Ruby has excellent datetime and timezone support, but it is a bit terrifying that this is just so poor in javascript and worse, made a heap of things fail silently in dev but fail in build.

In the end, I scripted something to change all datetime formats in all my old markdown posts (no one should ever have to change source files but they did stretch over 14 years of posts) to make sure they were js-friendly but also because the errors were so opaque I didn't want to ever have to worry again about source datetimes again in the posts as a possible source of error (it took forever for me to figure out that was the problem on posts from a decade ago.). I dislike it when a language bends you to its will, especially when it is counterintuitive to the way us hoomans normally work.

3. Emphasis on over-componentization

More a React thing, and while yes, it is often good to make sure things are componentized in separations of concerns, there's a point at which that starts to become a bit ridiculous (ok, you are talking to someone who wrote his whole blog software in 250 lines of ruby code, 1 file.).

Admittedly, I do know people that love everything being in teeny-tiny little over-tested pieces, but for me, and particularly if you're just getting started with a framework it makes things much, much harder to puzzle out. I personally have used this sparingly, but the framework bends towards you doing this way which means you run into weirdness not doing things the way it wants.

Not ideal, but hardly a deal killer (and some people might even be reading this thinking that it is a feature rather than a bug from their perspective.).

4. The node_modules directory

While never deployed to production (so more a hygiene issue), but especially not being someone used to node programming in general, the size and variety in my node_modules directory of stuff that, I have no idea what much of it is doing, is freaky. Doing a du -h -d 1 | wc -l to count directories on this yields a terrifying 1452 directories! I have to admit, I am already a little concerned, dependency-wise to consider upgrading from what I've currently got working at the moment. I've heard node upgrades do not generally go well in js land.

Conclusion

Summarizing, I'd have to say while I still find Jekyll easier, Gatsby feels very well though out and much more developer friendly for extending things beyond simple content frameworks to enhanced functionality. A more generalized framework for sites and getting up content and interactivity in a node-ish way to make it fast and performant.

Bottom line: if you're a javascript developer, and particularly if you're at all familiar with React (or want to pick it up), using Gatsby is a no-brainer. Switch. If you're coming from another language and are not so comfortable using javascript, especially server-side node, you're going to spend some time cursing curly braces, opaque errors, and npm dependencies than going with something you already know well (I have to say use modern javascript. Makes a huge difference if you use other languages.). I decided to switch over to Gatsby to force me into mystical node-javascript land, if I was going purely on the basis of ease, sticking to Jekyll was a good option (while my site probably didn't do as well as it should hav eon perf benchmarks and audits, it was fast by design though curious to check things out once I've optimized a bit.).

Oh, and one other shout out: I also decided to do the cross-over using Visual Studio Code (rather than emacs or vim), which I have to say is a spectacular environment for doing javascript development (so, yeah Microsoft did a great job here. Please don't balls it up.). A whole bunch of nice touches in it that just make development easier, from non-used functions being dimmed to the IntelliSense directly in-editor just made me feel ultra-productive and probably cut down on a whole bunch of dumb little man errors that most likely would have made me quit javascript forever before I even started. Also, the ability to have the in-editor terminal available was pretty amazing and kind of easily matches the usefulness of having tmux and vim working as a combined environment (though made my screen real estate a bit squinty on my little 2016 Macbook 12".).