A long time ago (2017), I wrote about modernizing my blog’s infrastructure.
Guess, what: Time to modernize again!
Back then, I migrated from Drupal to a self-written, Jekyll-inspired static site generator written in Python (my current language of choice for most projects). I spent the majority of the time figuring out how to export my old blog posts from Drupal’s MySQL database and how to convert them into Markdown with YAML front matter. There was also some work in building Jinja templates, trying to somehow make the design look ok.
I use the same system for my other blog, Paleosophie, which is a German, Paleo-nutrition-themed blog. It worked great, and static sites are an awesome way to host your blog, because there are no operational headaches, no security issues, not even the need to install patches, upgrades, and stuff.
Well, almost: over time, my homegrown static site generator started showing its age. Python moved on from version 2 to 3, and the mostly hand-crafted build system that funnels Markdown sources through my static site generator, then uploads them to S3 buckets for hosting became hard to maintain, too.
Simple, on-off solutions and quick fixes started to pile up into some sizeable technical debt.
A more modern blog system
Time to re-think stuff. Here’s what I wanted:
- An easy way to write blog posts and keep them easy to maintain.
- A modern, state-of-the-art build pipeline for converting blog post sources into final, static websites.
- Less time spent on re-inventing wheels, more time for writing posts and individual features.
After some research, I settled on:
- Pelican as my static site generator of choice. It follows the same idea of a Jekyll-style static site generator, but it’s written in Python, well-designed and well-documented. This is the static site generator I wish I had built, but others are smarter developers than me and can pour more energy into it so, great! The key things for me are to keep 100% control over my content (which remains as plain text Markdown), and the ability to control all aspects of my blog, including theming and any special idea I may come up with. Pelican is written in Python, which I like and am reasonably literate in, and it supports Jinja templates just like my old system, plus it supports writing plugins, so I can tweak it any way I like. In fact, there’s a good selection of Pelican plugins and some of them already do exactly what I’d like to do so, bonus.
- For theming, I’m staying with the Jinja templating language. First, it’s the same theming system I used before, second, it’s natively supported by Pelican and third, it’s powerful enough for everything I might want. It’s very Pythonic and extensible, so even when there is anything I might want to do that isn’t supported yet, I can always build a Jinja plugin.
- Similarly, for CSS, layouting and other frontend stuff, I’m staying with Bootstrap, which offers a great selection of layout features and components, as well as ample ways of customizing it. Meanwhile, it moved on to version 5, with even more of that good front-end stuff.
- The biggest change was the back-end that generates it all. My old bunch of scripts and tools became hard to maintain (reminding me all the time to port them to Python 3), and I wanted to learn something new, so I settled on the AWS Cloud Development Kit, or CDK. It’s an open-source software development framework that allows me to define all of my blog infrastructure using “familiar programming languages”, in my case: Python! It comes with a CDK Pipelines library, which supports painless construction of CI/CD pipelines. Now, my blog has a full CI/CD build system, complete with its own Git repository, dev and prod stages, plus manual approval for bringing new releases live when they look good. No more tinkering on the live thing while readers ask themselves what’s going on.
Overall, most of the heavy lifting is now handled by the CDK CI/CD pipeline, Pelican and their respective plugins and classes. At the press of a button, I can completely bring up, tear down, or update my blog including all of it’s hosting infrastructure. Neat!
The migration process
Like all projects, this took longer than expected:
- I started by setting up a basic Pelican blog, then dug into its templating documentation. I found a theme called Elegant, which is arguably “the best Pelican theme” around. Since its author knows a lot more about Pelican than me, it was a great resource and inspiration for learning to build my own theme and how the innards of Pelican work.
- Next, I needed to re-learn how Bootstrap does things (some have changed) and reflect this in my theme templates. I also had to learn the current way of building things in the CSS world, which included crash courses in nvm, npm, sass and their tool chain in order to add some custom colors and settings and leave out unneeded components for a more streamlined Bootstrap variant.
- Then came the article migration part. This was supposed to be easy, since my previous content was in Markdown already. But the devil is in the details, and I wanted to take the opportunity and fix a number of bugs in the old articles that didn’t quite port well before. I ended up writing a long import script with lots of regular expressions to migrate old entries and pages into the new system and fix things.
- This sent me down an extra learning curve about Pygments, which can render code nicely in HTML5 and mostly does the right thing on this blog’s code samples. Mostly. I’ll have to deal with some of its quirks later, though.
- I came up with the idea of adding a proper HTML5 check step based on [W3C’s Markup Validation Service] to my CI/CD pipeline, which generated a couple of editing rounds for my templates until all went through with no errors or warnings.
- Then I wondered how many of those old links I included in my old posts were still valid, with Sun having been bought by Oracle, OpenSolaris becoming a lesser priority and lots of old blogs and websites simply fading away. So I added a link-checker, and it turned out that roughly 150 links had to be fixed. Lots of new regular expressions in my migration script later, those stale links have either been replaced by sensible equivalents, or a short message telling readers that these websites are no longer available.
- Drupal, my old system, and Pelican also had differing opinions on how to generate blog post URLs. The easy part was to configure Pelican to use the same year/month/day/slug scheme as before. However, there were subtle and less subtle differences on how to generate the slug part, which added yet another set of regular expressions and redirections to the import script.
- The old banner was, well, old and since then, display technology improved quite a lot. So it didn’t quite look good anymore at the old resolution. This sent me down a side project of learning how to programmatically build header images using p5js (more on that later). I also upgraded my photo with a cartoon rendition of myself, courtesy of Bitmoji. Now I can generate my banner image at almost any resolution (minus the Bitmoji avatar part, let me know if you know of any better comic avatar service). Actually, thanks to the Pelican image-process plugin, most images in this blog are now offered in different resolutions based on your display’s capabilities. Yay for quality!
- A lot of the old articles on this blog are, well, old, too. Times have changed and what was cool, shiny, or the best thing since sliced bread before, today simply isn’t anymore. I pondered whether I should simply get rid of the old articles, but that would have been rude to any readers of this blog who might have bookmarked or linked to them. Instead, I added little “obsolete” tags to their headlines and an explainer box to the beginning of these articles. Pelican’s customizability and its use of Jinja for theming are already paying off!
- And of course lots of bugs and little things here and there that needed my attention.
Overall, I started in mid-April and now we’re in mid-June so the total overhaul time was two months. I only worked on this for perhaps an hour a day on average, though.
Plus some new requirements!
A couple of things are new here, and hopefully I’ll find the time to add more in the future:
- No more cookies, no more tracking. Seriously. In addition to simply getting rid of Google Analytics plugins, etc., I also removed social Like/Follow buttons that might bring some cookies of their own. Even embedded YouTube or Vimeo videos are now using their “no tracking” versions. I’m verifying my no-cookies-policy with Ghostery which shows me a nice “0” on my own website, which makes me smile.
- No cookies also means no pesky cookie-consent banners, another win!
- There are still Amazon affiliate links on this blog, but they don’t use any widgets anymore that might drag in some cookies or tracking pixels. Instead, I’m rendering book/product boxes on my own using Bootstrap components. They may look slightly less slick, but I hope to improve on them as I learn more about creating layouts with Bootstrap.
- There’s a new contact form now (in Beta). The back end of it is another CDK Pipelines construct that implements a simple web form service using Amazon API Gateway, AWS Lambda, and Amazon Simple Email Service. It provides some sanity checking on the submitted content, then sends the form contents via email to me. I might extend it towards a full commenting system, but need to figure out a few things first. For example, how to implement some simple authentication, so commenters can edit/delete their own posts without interfering with other posts, etc. This may require me to introduce cookies again after all (but under my exclusive control) or maybe I’ll use some magic URL based scheme. Let’s see.
Thank you for reading so far, I hope there was something interesting in the choices I made above, and look forward to hopefully posting more regularly here soon.
While there’s no commenting feature (yet), I do welcome your comments and opinions, so feel free to visit my contact page and leave a comment there.