Blog Moved to New Server, Mebe Refactoring

Posted on .

After moving Code::Stats to its own server, the old Online.net box this blog was running on was going to waste, and more importantly, wasting my money. So I got a new tiny box from Hetzner and finally got over to dumping the blog on it. But of course I had to use the opportunity to also refactor it a bit…

In addition to the bumped deps and overall cleanup in the backend, the frontend has been rewritten. The previous version had some BuckleScript handling the render speed indicator and other tasks, delegating the code highlighting to Prism.js. As any good side project, it should be reimplemented in a different language periodically. This time it was TypeScript. I've been dealing with it at work and really enjoy working with it.

A curiosity of the frontend's TS code is that NPM is not used. There is only one dependency (Prism.js), which is put in true retro fashion into a vendor/ folder. For other code, the tsc compiler generates ES2017 code that is executable in modern browsers straight away, without the need for bundling. Prism.js and its CSS is dynamically imported on demand to minimize the bandwidth used for a typical request. A demo below:

const msg = "Click button above to load syntax highlighting.";

The approach does have some caveats. Code must be imported with a .js extension in the TypeScript files as tsc does not change the imported file extensions when compiling the files. The files are requested when imported on the top of a file, so if you have deep import chains, there will be more request overhead unless you list the files with a <link rel="preload">. And of course there is no tree shaking and such that bundlers do. But for small projects like these, I just love how frictionless it is. It has made me enjoy frontend work again.

The previous version of the blog used SCSS, but this one just has plain hand written CSS. With custom properties (AKA variables), modern CSS works quite well, except for one part… media queries. You cannot use variables in media queries, so you either have to repeat your breakpoint sizes, or you can do a trick with the :root selector like this:

@media (min-width: 480px) {
  :root {
    --footer-direction: row;
    --footer-item-margin: 0;

    --h-size-factor: 0.85;
    --text-size-factor: 0.95;
    --youtube-height: 300px;
  }
}

So you can set variables in one place and not need to repeat your breakpoints. But of course, if one size of a component uses display: flex and another display: grid with all the associated properties, you can see it will quickly get out of hand. For this blog it worked fine, though, so it's feasible for smaller projects. Here is the settings file that contains the breakpoints and variables for this blog (at the time of writing).

One of the aims was also to get the request size down. Websites today are massive bloated blobs and I wanted to try going the other way. An example request of the front page after deploying gave the following gzipped sizes (includes HTTP overhead):

  • HTML: 7.55 KiB
  • JS: 6.81 KiB
  • CSS: 7.30 KiB
  • XHR: 427 B (analytics request to Tilastokeskus)

That's still more than some Arduinos have total flash memory, but it's quite good for a personal site, I feel. The biggest savings were from using standard fonts and loading Disqus comments on-demand (there's a button that you can click to load them now -- this also prevents Disqus from following you online, which is an added bonus).

So, another year and another set of upgrades. Maybe I'll come back to Mebe again next year, after I've dealt with all my other pending projects. Maybe I'll even write a blog post every now and then! But for now it runs well and lean, and that's enough for me.