Migrating ❤️’s website from Jekyll to Eleventy.

So, as a lot of the audience for this article knows, this isn’t our only site; we also run a gallery dedicated to all the art we’ve commissioned or being gifted of ❤️.

Much like this site, that site was also built on Jekyll. Unlike this site, there is also a large mess of PowerShell to handle things such as generating the gallery pages using specific pieces of YAML metadata to generate image galleries, updating and splitting out a monolithic JSON file containing details of all artwork, and generating image and video thumbnails using two separate folders stored in OneDrive, separate to the repo.

Why PowerShell? Well, it’s what we know.

The current process

The current process for years has been to run two scripts, UpdateData.ps1 and Deploy.ps1.

UpdateData calls functions that scan through the OneDrive folders and update various JSON files - both the main monolithic JSON, and derived JSON files like one containing information on artists. It usually has to be run multiple times; once to pull in initial data from OneDrive (file location, file hash), and again after we’ve filled in information such as a proper title, description, alt text, original link, etc. to update the derived JSON files.

Deploy:

  • Calls functions responsible for creating thumbnails from those OneDrive folders (using the hash from the previous step). This step is here so thumbnails aren’t generated from artwork we want to exclude.
  • Spits out a whole bunch of Markdown files for the different ways someone might theoretically want to view the site (e.g. “only posts from 2018, in a grid, without content warnings”), with the only difference being the YAML front matter.
  • Spits out a bunch of Markdown files for each individual piece of artwork as a post, with the only difference being the YAML front matter.
  • Runs bundle exec jekyll build to build the site. (Or if run with the Test parameter, runs bundle exec jekyll serve instead). This compiles all the Markdown into HTML.
  • At one point, it did attempt to deploy to our DigitalOcean server, but then there was a permissions issue so I fell back on good ol’ reliable FileZilla.

The problem(s)

This setup has always felt fragile. There are obvious points where things can be decoupled - or have been decoupled previously but then reverted for performance reasons (such as using Docker to perform at least the Jekyll build) - but the current setup means that both steps have to be run from my dev machine, and have to be done so manually.

More than that, the build has required other workarounds, particularly on MacOS. For example, after updating Jekyll versions, the supported version of ruby went from 2.6 to 3.1.2. Jekyll’s Mac documentation recommends installing chruby to manage the different versions. chruby modifies .zshrc, using the POSIX source command to load scripts. PowerShell’s Mac version cannot make use of the source command (or at least didn’t use to be able to) - and if using a terminal set directly to launch pwsh as ours is, it subsequently would be stuck not being able to change from the default version of ruby. So, we’d have to launch a new Terminal window (or Kitty/iTerm2 tab) using zsh, launch pwsh from there, and then run Deploy.ps1

Screenshot of VSCode with a descriptive error about where specifically to run this script from if there's a problem.
You can tell from how descriptive this error is how many times we ran into this.

This has made us hesitant to update any part of this. Which kind of just makes the dependency part worse!

Additionally, the reliance on OneDrive is causing its own problems. OneDrive on Mac does not quite get the concept of “always keep on this device”, and will yeet things without warning. My strong suspicion is that this is Apple’s fault with trying to aggressively manage storage space, but it can leave the site in a state where it’s unable to build.

And sure, we have a Windows machine for backup. For now. But OneDrive on there broke a few months ago as well; downloading new files on demand but refusing to download them via “always keep on this device”, and also refusing to upload. (The solution ended up being to sign back into OneDrive via specifically the Photos app and not the OneDrive app itself). And it’s been so long since we tried to build on there I have no idea what state the other dependencies are in. Additionally, we have made the decision that if at all possible, no personal device we own will ever see Windows 11 outside of a VM, meaning that machine has at most 18 months left on Windows. 1 MS don’t make a OneDrive native app for Linux, and I don’t think I’d trust third party ones with the creds.

I Think I Has The Solution

It was while cleaning out my RSS reader that I got reminded that beeps is using Eleventy.

And that the Eleventy image plugin likely can do some of the things we’ve been using PowerShell. Eleventy being node based makes it substantially easier to keep things self contained and minimize external dependencies beyond npm itself. It might build faster, making the other work we need to do easier.

More tabs.

You can generate pages from a big monolithic JSON file (like the one we already use). Have them managed entirely through collections much cleaner than how we’d rolled our own prev/next system (being fair, we could have and should have done this through Jekyll in better ways, but Eleventy does also provide a few shortcuts and unique features to make it easier).

And before too long, we’d created a new git branch, and run brew install npm. The question at least needed answering.

Goals

phase 1 - migration

See how much can be done with a quick and dirty port from Jekyll to try and match functionality.

Starting from scratch would be cleaner, but… well, there’s a lot of stuff written 6 years ago that we don’t have the bandwidth/spoons to completely recreate at the moment.

We did mostly learn from our mistakes; this site would have been the easier one to migrate first. It makes far less use of Liquid filtering (and thus less chance of running into Jekyll specific filters), and far less PowerShell - but at the same time, if we’re going to do this, the bandage needed ripping off first. It was the only way to prevent any fear about doing it.

phase 2 - improve performance

Start gradually unpicking bits and pieces, using Eleventy specific functionality but also things we should have done better in Jekyll, with the goal of speeding up performance when building. There are a lot of inefficiencies that can likely be addressed.

phase 3 - extend functionality

As part of that, start reducing external dependencies on PowerShell and OneDrive; storing images elsewhere. I haven’t yet decided if I want to put them in the repo since they would be an issue to putting stuff up on a public git host, but I want it to be possible to build without reliance, with the eventual goal of maybe having a proper (local) CI/CD process; to try and fully automate at least a staging version of the site.

Part of this would be setting up a proper responsive image pipeline as well, using the Eleventy image plugin.

phase 4 - space phase

Maybe at some point, think about a redesign.

When I set this site up, there were a few goals in mind:

  • Absolutely no JavaScript with anything related to the public site. (What happens during the build process is for the build process only).
  • To be as Web 1.0 as possible without quite being the Space Jam site, while still allowing for a few modern conveniences

The first one is still a requirement. I am still of the opinion that the modern web is bloated, and that the fastest implementation of JavaScript can never match just not having any. There certainly are good uses of Web 2.0 (I’m drafting this post in Obsidian, which wouldn’t be possible without modern web frameworks), we just don’t need them on our own sites.

The second one… it feels worth experimenting with at some point. What it’d be like using a modern <grid>, rather than tables, rounding off the corners, maybe using a little CSS animation when something is highlighted.

But there’s no sense trying to build that on top of a bad foundation. If the code is easier to maintain, if we can get over our Not Invented Here syndrome, then it’s easier to play with.

About this post

This post will only cover goal 1 - what was needed to be done to get it working with equivalent functionality.

None of this code should be treated as best practice for either Jekyll or Eleventy. This is simply looking at what we did 6 years ago, and yelling. Still, if you have also done some of these things, maybe it’ll help you make what changes you need to.

Additionally, if you are looking to migrate a GitHub Pages site specifically, I believe additional configuration is required and you should find an applicable guide for doing that.

Phase zero - Get the site building

Before anything else, we at least need to get the site into a state where it will build in Eleventy - so then we can just leave it running with the built in web server as we make other changes.

Initial pass

Create new branch in source control.

If your Jekyll site isn’t in source control, you should really, really fix that first.

brew install npm # installs npm
npm init -y # initializes npm in current directory

At this moment, take a moment to make sure node_modules is part of .gitignore (or equivalent) before continuing further.

npm install --save-dev @11ty/eleventy # installs eleventy, saving to packages.json
npx @11ty/eleventy

We also create a basic Eleventy config file in eleventy.config.cjs, since in Jekyll, layouts were in _layouts rather than _includes - without including this, it won’t be able to render anything.

/posts/2024/03/eleventy-point-one/
const syntaxHighlight = require("@11ty/eleventy-plugin-syntaxhighlight");

module.exports = function (eleventyConfig) {
    // Enable syntax highlighting
    eleventyConfig.addPlugin(syntaxHighlight);

    eleventyConfig.setLiquidOptions({
        dynamicPartials: false
    });
    return {
        dir: {
            layouts: "_layouts"
        }
    }
};

We’ll be returning to this a few times, but for now, let’s try and build.

ERROR! But of course, that’s expected. We’ve done nothing yet.

(node:1971) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead.
(Use `node --trace-deprecation ...` to show where the warning was created)
[11ty] Problem writing Eleventy templates: (more in DEBUG output)
[11ty] 1. Having trouble rendering liquid template ./about.md (via TemplateContentRenderError)
[11ty] 2. undefined filter: absolute_url, file:/eleventytest/_includes/gallery/galleryimage.html, line:27, col:12, file:./about.md, line:17, col:1 (via RenderError)

Error the first - absolute_url

Jekyll defines a filter, absolute_url that prepends the site URL (as well as a base path, if one is in use).

We are not using a base path, and most things seem to work fine with relative URLs. So for now, we just remove it.

This particular filter is used in a fair few places - this particular one is a fallback message displayed under some animated images.

     {%- if image.Extension == 'avif' -%}
-        <i>Image not displaying correctly or at an incorrect framerate? <a href="{{ URL | replace:'.avif','.gif' | absolute_url }}">Click here for GIF fallback.</a></i><div class="spacer-block"></div>
+        <i>Image not displaying correctly or at an incorrect framerate? <a href="{{ URL | replace:'.avif','.gif' }}">Click here for GIF fallback.</a></i><div class="spacer-block"></div>
     {%- endif -%}

Attempt to build again - ERROR!

[11ty] 1. Having trouble rendering liquid template ./credits.md (via TemplateContentRenderError)
[11ty] 2. undefined filter: group_by, file:/eleventytest/_includes/credits/othercharstable.html, line:1, col:1, file:./credits.md, line:18, col:31 (via RenderError)

Error the second - group_by

group_by is another Jekyll specific filter. For now, we replace it with Liquid’s built in map filter - but this isn’t a change that works by itself.

group_by outputs an array of arrays - with each entry having both the name of the thing being grouped by, and items showing what’s being grouped. map just gives an array of the names.

So, all we actually did during this commit is change group_by to map - at this point we just want the site building rather than fully working.

But for clarity, we’ve combined this with several other commits to the same file after we figured out what was wrong.

This file takes in a precomputed data file about friends’ characters and ties that to an identity for the friend playing them, so we can link out to their social media (if they want that).


-{%- assign players = site.data.otherchars | group_by: "Player" -%}
+{%- assign players = otherchars | map: "Player" | uniq -%}
 <table class="creditstable">
     <thead>
         <th>Player</th>
@@ -7,10 +7,10 @@
     </thead>
     <tbody>
         {%- for player in players -%}
-        {%- assign characters = player.items -%}
+        {%- assign characters = otherchars | where:"Player",player -%}
         <tr>
             <td>
-                {{ player.name }}
+                {{ player }}
             </td>

You might notice a few other changes here beyond just the change in structure, but we’ll cover those later.

Try to build again (after only changing that first line) - ERROR!

[11ty] 1. Having trouble writing to "_site/index.html" from "./index.md" (via EleventyTemplateError)
[11ty] 2. undefined filter: relative_url, file:./_layouts/home.html, line:5, col:24 (via ParseError)

Error the third - relative_url

Much like absolute_url, relative_url is a Jekyll specific filter that adds on the base path if you have to upload to a subdirectory.

We do not have to upload to a subdirectory though, so possibly this was leftover from following a Github Pages focused tutorial or something.

The Eleventy specific filter, if needed, is url.

This is from the layout template for the home page:


-    <p>The <a href="{{ "/credits" | relative_url }}">Credits</a> page lists all the wonderful people who helped make this site possible!</p>
-    <p>The <a href="{{ "/feed.xml" | relative_url }}">RSS</a> link takes you to our RSS feed for staying up to date with all the new posts! Just paste in to your reader of choice!</p>
+    <p>The <a href="{{ "/credits" }}">Credits</a> page lists all the wonderful people who helped make this site possible!</p>
+    <p>The <a href="{{ "/feed.xml" }}">RSS</a> link takes you to our RSS feed for staying up to date with all the new posts! Just paste in to your reader of choice!

We probably should have removed the brackets as well, but this feels like a good candidate to not be a raw HTML layout at some point in future.

Try to build the site and ERROR!

[11ty] 1. Having trouble writing to "_site/404/index.html" from "./404.html" (via EleventyTemplateError)
[11ty] 2. undefined filter: normalize_whitespace, file:/eleventytest/_includes/head.html, line:6, col:41, file:./_layouts/default.html, line:4, col:3 (via RenderError)

Error the fourth - normalize_whitespace

normalize_whitespace is a Jekyll filter replaces all whitespace in a block with one whitepace character. We mainly used this for things like descriptions which could be variable about capturing additional whitespace. The main reason this was here was to get rid of newlines, so the built in strip works pretty well.

Try to build the site and… success.

Nothing actually works, but the server is running. It builds suspiciously quickly.

Inside the generated site directory, we find the following:

Left: Jekyll output; right: Eleventy output

This is a lot less folders than expected, while simultaneously also having some things that shouldn’t be in there, like README.MD.

Ignorance is Bliss

By default, when building a site, Eleventy does something substantially different to Jekyll.

Eleventy will take your .gitignore file and ignore anything defined by it. For most sites, this is probably what you want.

However, because of the issues we had years ago with building the site, the scripts mentioned above are responsible for generating a lot of things, including everything in the _posts directory. Because of that and because running the scripts is mandatory, those are in .gitignore because they’re build artefacts.

To fix this, we can use a .eleventyignore file, along with telling Eleventy to not use .gitignore in the config file we created earlier.

README.MD
powershell/
node_modules/

And in eleventy.config.cjs:

module.exports = function (eleventyConfig) {
     // Enable syntax highlighting
     eleventyConfig.addPlugin(syntaxHighlight);

+    //has to be disabled as otherwise derived data won't work
+    eleventyConfig.setUseGitIgnore(false);
+
     eleventyConfig.setLiquidOptions({

This would have been a good time to add additional entries in the config to change the input directory to make things much neater, and modify .gitignore and the like to match. However, we considered that part of the phase 2 cleanup, rather than the phase 1 ‘get site working with equivalent functionality’

Now the individual pages work… but the navigation between them doesn’t. The CSS is missing. The images are missing. The individual posts are being output to _posts/YYYY-MM-DD-$TITLE_SLUG/ rather than the format they should be in, /gallery/image/YYYY/MM/$TITLE_SLUG/

From this point forward, we’re just summarizing the final output rather than the gnashing of teeth ❤️ ended up doing while figuring this out. They’re still presented roughly in the order of the first commit to that aspect; we’re just leaving out the troubleshooting.

Lieutenant Commander Data

Jekyll supports using JSON files in a _data directory, which are then available for use in code using site.data.FileName.

For example, for artists.json:

{%- for artist in site.data.artists -%}
{{ artist.name }}
{%- endfor -%}

For Eleventy, these still work, and form part of the data cascade, where different sources are all merged into one thing. The difference comes with how they’re accessed - in Eleventy, it’s just{{ FileName }}.

(Other parts of Jekyll’s site configuration have to be recreated manually - for example, site.url pulls from Jekyll’s global configuration _config.yml. To do the same thing in Eleventy, you’d need to create _data/site.json, and add a url field there - or add some special syntax to the Eleventy config file)

A similar change occurs for fields in YAML frontmatter - in Jekyll, it’s{{ page.field }}, in Eleventy, it’s just{{ field }}. There are some circumstances where page is still needed when dealing with arrays of pages, but it isn’t needed in a lot of other circumstances.

Combined, these create some problems if you just remove the prefix when migrating - especially if other parts of the code are assigning variables using the same name. Having an _data/example.json, example field in front matter, and {%- assign example = "foo" -%} is safe in Jekyll because these are three separate variables - at worst you’ll probably cause yourself some confusion later. In Eleventy, the global data file is always given least priority - so if a page has example as a field, the parts of the page that were expecting the array from example.json will end up with either that or foo depending on if the assignment code has been called, and things will break.

And if you happened to do something like {%- assign previous = page.previous -%}, and during the migration, removed the page. without thinking, there’s going to be some issues later.

💡 tip
Make sure variables are unique before you start the migration process.

Don’t Give Me That Sass

Jekyll supports Sass natively. In assets/main.scss, we have a file that just imports from a config file in _sass, which contains a number of other SCSS files for different scenarios (e.g. site navigation, gallery pages).

Eleventy does not support it natively, but they do list a potential way of doing so. However, we ended up using the eleventy-sass plugin instead, just as it seemed like a more feature complete way of doing so. This needed moving the _sass folder into _includes, and updating main.scss accordingly.

But also additionally, Jekyll will copy all directories that aren’t hidden or begin with an underscore by default, unless specifically excluded. Eleventy will only include template files (Markdown, HTML, .liquid, .njk, etc.). To get it to passthrough things like PNGs, that’s another tweak to the Eleventy config file:

const syntaxHighlight = require("@11ty/eleventy-plugin-syntaxhighlight");
+const eleventySass = require("eleventy-sass");

 module.exports = function (eleventyConfig) {
     // Enable syntax highlighting
     eleventyConfig.addPlugin(syntaxHighlight);
+    eleventyConfig.addPlugin(eleventySass);
+    eleventyConfig.addPassthroughCopy("images");
+    eleventyConfig.addPassthroughCopy("assets");

Additionally, due to the change in Sass processing engines from this (and/or whatever Jekyll was using being very out of date), a lot of variable lines in the scss files had to be updated due to a deprecation warning on division outside of the calc() function:

div.title {
-    margin: $spacing-unit auto $spacing-unit/2;
+    margin: $spacing-unit auto calc($spacing-unit/2);
     line-height: 0.85;

Radically Self Simplifying

Jekyll includes the jekyll-feed plugin - which automatically generates an RSS (Atom) feed for you, the way they think it should be done. It will generate as feed.xml, the style info will be at feed.xslt.xml.

Eleventy does not come with its RSS feed plugin, and after installing it, it won’t do anything automatically. Copying from the template mostly worked, but there is one special thing we needed to do:

{%- set rss_posts = collections.singleimage | reverse -%}
{%- for num in range(20) %}
    {%- set post = rss_posts[num] -%}

The Jekyll feed is restricted to the last 10 entries. Because we’re loading images as well in supported clients, we still want to keep sizes small. However, this being our first time working with Nunjucks, what we didn’t realize is that it doesn’t appear to support an equivalent to Liquid’s limit filter (possible we’ve just missed it in the documentation) - so instead it needs a range of indexes.

The impression we’re getting of Eleventy at this point is that it’s very modular and extensible, which is a good thing generally - but also a little annoying if you happened to be using a lot of the things Jekyll came with and now have to manually replace them.

You might have noticed the mention of collections there.

Collectathon

There were multiple reasons for why we wanted to make the switch from Jekyll to Eleventy - but a lot of them hinge in some way on Eleventy’s Collections.

Collections in Eleventy are dynamic ways to link pages together by tag. They can come from any part of the data cascade, or be created in Eleventy’s config file based on more advanced criteria. It’s trivial to use them to automatically generate pages linking to everything in a tag. There are easy filters for quickly iterating over any collection.

Jekyll also has a collections component, but they are entirely static and defined in the config file only, which is the reason we never used them.

Subsequently, we ended up with a lot of bad code trying to do what Eleventy almost gives for free. Bad iteration over all posts in a tag to try and find the previous or next post, using the global {{ site.posts }} and {{ site.tags }} variables in ways they probably shouldn’t have been.

Jekyll probably had better ways to do this than we knew at the time we wrote this code, but still.

When that was slow, we implemented a PowerShell bodge on top; extracting separate JSON files from the big monolith so Jekyll had less to do. (And it was still slow).

For now, we’ve done the bare minimum to fix this - putting the following in _posts/_posts.json (a directory data file) allowed us to use collections.singleimage like we would have done site.posts (and also fixing the issues with permalink format mentioned earlier, which was defined in Jekyll’s _config.yml).

{
    "layout": "singleimage",
    "permalink": "gallery/image/{{ page.date | date: '%Y/%m' }}/{{ title | slugify }}/",
    "tags": [
        "singleimage"
    ]
}

Why didn’t we fix this properly? Mostly because we’d already committed to doing bare minimum fixes in this stage - just enough to get the site running - and all the HTML files generated for Jekyll were using ‘tag’ in their frontmatter when Eleventy expects ‘tags’. Had we not committed to that goal of bare minimum fixes only, for the amount of troubleshooting the prev/next templates alone caused, it would have definitely been preferable to regenerate everything with tags and go from there. It is the first thing on the list for phase 2, though, to strip all the bad code relating to it out and burn it to the ground.

This is also the situation where the page component to a variable is still needed.

Includes or implodes?

Liquid as a templating language is used by both Jekyll and Eleventy, and it supports the ability to include other files in the current template.

For static files, such as the navigation bar, this was working. For files using dynamic content, the file was being included, but none of the content was making it through.

As it turns out, there’s a difference between implementations between Liquid for Ruby, and LiquidJS.

-{%- for thistag in page.tag -%}
-    {%- include gallery/prevnext.html tag=thistag -%}
+{%- for thistag in tag -%}
+    {%- include gallery/prevnext.html prevnexttag:thistag -%}
 {%- endfor -%}

Similarly, Jekyll allows for the dynamic content to be accessed inside the included file with {{ include.content }} (in this case, include.tag). In Eleventy, that’s just {{ content }}, meaning there’s another source of variable name conflicts if you’re not careful (as you can see above!)

There is also another problem here from the differences in Liquid implementations. gallery/prevnext.html was also called without prevnexttag, for handling the previous/next for the “All Images” collection.

In Jekyll/Liquid for Ruby, this is fine:

{%- case include.prevnexttag -%}

{%- when nil -%}

But this doesn’t work properly under LiquidJS after amending to just prevnexttag - because LiquidJS has more states, so it isn’t nil, it’s undefined.

(The conceptually simpler solution was just to split the code covered by this case statement out to its own includes file, and speed up execution just a little by not having to go through an unnecessary case statement for time this code is called. Which is a lot).

Final fixes

Jekyll uses kramdown as its Markdown processor. This gives a lot of things built in, including the ability to link to individual headers via an anchor, the ability to generate a table of contents, and the ability to define HTML attributes for specific blocks of text without them having to be includes.

All of these are more important for this site rather than ❤️’s, but they are used on one page on ❤️’s so they also had to work. It’s good practice, anyway.

Eleventy’s markdown-it processor unsurprisingly does not support these out of the box, so more packages and modules! Here’s the final eleventy.config.cjs, using the setLibrary function to make sure Markdown is processed the way:

const syntaxHighlight = require("@11ty/eleventy-plugin-syntaxhighlight");
const eleventySass = require("eleventy-sass");
const pluginRss = require("@11ty/eleventy-plugin-rss");
const mdIt = require("markdown-it");
const mdAttrs = require("markdown-it-attrs");
const mdAnchor = require("markdown-it-anchor");
const mdToc = require("markdown-it-toc-done-right");

module.exports = function (eleventyConfig) {
    // Enable syntax highlighting
    eleventyConfig.addPlugin(syntaxHighlight);
    eleventyConfig.addPlugin(eleventySass);
    eleventyConfig.addPlugin(pluginRss);

    // uses custom copy of markdown-it rather than built in so it can use the plugins to replicate kramdown.
    // https://dev.to/iarehilton/11ty-markdown-attributes-2dl3
    // https://www.11ty.dev/docs/languages/markdown/
    let mdItOptions = {
        html: true
        //unsure if breaks: true and linkify: true are needed, assuming not
    };
    let mdTocOptions = {
        listType: "ul"
    };
    eleventyConfig.setLibrary("md", mdIt(mdItOptions).use(mdAttrs).use(mdAnchor).use(mdToc,(mdTocOptions)));

    eleventyConfig.addPassthroughCopy("images");
    eleventyConfig.addPassthroughCopy("assets");
    eleventyConfig.addPassthroughCopy(".well-known");
    eleventyConfig.addPassthroughCopy("feed.xslt.xml");
    eleventyConfig.addCollection("posts", function(collectionApi) {
        return collectionApi.getFilteredByGlob("_posts/*.html");
    });


    //has to be disabled for now as otherwise derived data won't work 
    eleventyConfig.setUseGitIgnore(false);

    eleventyConfig.setLiquidOptions({
        dynamicPartials: false
    });
    return {
        dir: {
            layouts: "_layouts"
        }
    }
};

Then all that was needed was swapping out a bit of kramdown specific syntax in the page that used it.

and that’s phase 1

This has been a long post, but I wanted to be thorough in the kinds of issues encountered, particularly with using Jekyll for a purpose that it probably wasn’t designed for (and not the most effective way of doing it). For a simpler blog making less use of weird bits of Jekyll, it’s probably going to be much less of a hassle to migrate, and allow you to start getting to your desired features much faster. If you’re also doing weird things with Jekyll, hopefully this has answered a question you might have had about the migration.

We’re expecting the migration here to go a lot smoother, as an example.

Next comes ripping out so much of the bad code we had to become familiar with again during this process. Maybe at some point after doing this, we’ll actually be comfortable open sourcing some of this.

Asides and appendices

failure to upload

Spent a lot more time than we’d like trying to get this one uploaded, because Jekyll does not realize that Liquid tags inside a codeblock should not actually be processed as Liquid tags, and the {% raw %} tag it suggests to use seems… tempremental.

Not sure if Eleventy also suffers from this, we’ll find that out when it comes time to migrate this site.

Footnotes

  1. This may or may not be attainable as a goal depending on SteamVR progress on Linux by that point.