A new, static, blog


It's time, finally, for me to do what every other developer with a blog does — write a blog post about my blog setup. I have unquestionably over-engineered this, but that's gotta be half the fun, right? So without any further ado, let's go through the process of how I put this together.

A window into the developer

The main reason this blog exists is to show people what sort of developer I am. Shockingly, that's not a constant. My old blog setup, which I've archived but not deleted for the sake of being honest with myself, was that of a React developer. It looks like a giant mess to me now, but I guess hindsight is always more critical of bundle size and code complexity or something like that. The point is, I'm not a React developer any more, so what sort of developer am I? And what sort of blog does that developer create?

One day, I'm going to be a practical sort of developer. The sort that clicks the "Can I have a Jekyll site please" button on GitHub Pages, and never thinks about it again. I'm not that developer yet though, so for now the fun (read: over-engineering) continues.

For the last year, I've been working for Tiny Technologies. I might even write a blog post about it some time. For now though, I'll say that building a rich text editor that's optimised for compatibility with different site setups has changed every view I held about browsers0. Some key differences in how I think now vs earlier:

Nothing can be done without React or another framework.The native browser APIs are very powerful these days.
Nesting 30 layers of divs to get the layout you want is normal.Sometimes people actually want to look at the inspector to debug something.
I can just put a banner up telling people not to use old browsers.I wish I could just put a banner up telling people not to use old browsers.
And most importantly…
I only care about the HTML that fits my use-case.I need to understand everything a user could conceivably make out of HTML, and how it's meant to work.

Now that's not to say that I hate React now. I really miss using it, and having that comfort layer between me and the DOM — especially for things like forms or quickly reorganising HTML structures when I change my mind about something. What I'm trying to say here isn't that I hate having a framework between me and the DOM, I'm just not so scared of the alternative any more.

And that lack of fear is what led me to believe that this would be a good idea:

My website isn't going to render on the client side

That's not a particularly courageous statement though. Server side rendering is a well-established pattern, and even predates client side rendering. Except, because I'm pretty cheap when it comes to hosting for side projects, I don't want to have a server. So where will the rendering happen? In the compiler.


At time of writing, "Blog-pack" doesn't really mean anything and doesn't come up when I search for it, if that's no longer the case then I'm sorry.

You've heard of webpack? That tool that you use to package things for the web? I set it up to package things for my blog. Writing it out, that sounds like such a simple task, but it was anything but. What it comes down to is that I wanted to operate on HTML files, and webpack wanted to operate on JavaScript files.

I really wanted 3 tools to come together and work for me with this:

And I gotta say, 2/3 of the way through that list we were having a real good time. Both of those plugins are built to emit good HTML files from webpack. Unfortunately, html-loader is built to turn your HTML file into a pretty JavaScript module. It does a fantastic job of finding all of the <img src and <link href elements that you want the build system to resolve… and then it turns them into require calls.

Immediately, my zero-practicality brain jumped in with a solution: just write your own HTML loader! How hard could it be to coerce webpack into importing those assets without shelling out to require, right? So I tried it. I really did. I read (some of) the source, I read the docs, I logged semi-private webpack objects and APIs at runtime to see how they worked. You ever tried swimming against a strong current? Webpack is not built for this use case, and it let me know every chance it got.

So we turn to my zero-practicality brain's least favourite solution: compromise. I did still need to do some webpack-based processing of certain elements (extracting SVG icons from the @fortawesome/... folders in my node modules, for example). But for some things, like stylesheets, I just had to go with the flow a little. Behold, my entire index.js:

import './styles/page_layout.scss';
import './styles/content.scss';
import './styles/navbar.scss';

// This file doesn't do any processing. It just plays nice with webpack.

And if you look in your inspector, you'll see a little JS bundle filled with sweet nothings that's been downloaded as part of this page.

My templating system

One other important thing I've learned at Tiny is how scary HTML is. You know the infamous stackoverflow post about how you shouldn't parse HTML with regex? Turns out you shouldn't parse it with anything else either if you can get away with it. HTML is incredibly complex to deal with programmatically, and the browser (which does not make it look easy) makes it look so much easier than it really is. And so you can imagine my shock to see that it's pretty much industry standard for static site generators to ask handlebars to interpolate some strings together and call it HTML. Like I'm sure it works, but at what cost? And how fragile is it?

I'm not a fan of treating HTML as strings, and I am a fan (now) of using DOM APIs to make the scary bits of HTML go away. So my "templating engine" just loads the HTML up in jsdom, and calls document.querySelector('main').innerHTML =1. It seemed a little weird to not have any {{}} in my templates at all, but honestly the more I work with it the more I like it.


The other nice advantage of pre-rendering everything is that suddenly my website is fast. I'm serving up2 plain HTML files, with plain CSS, all from a plain old CDN. There's nothing here to slow it down.

I'm not going to quantify things, because it's not worth the effort it would take to set up a meaningful benchmark. But I will say this: there's no more loading spinners here.