I’ve spent the last few weeks distracting myself from things by dabbling with Eleventy (11ty) – “a simpler static site generator”. I’d been meaning to take a look at it for a while, having decided that it was time to break away from WordPress (for this site at least), and I was sure that static was the way to go. I’ve used Hugo and Gatsby before, but all the cool kids are talking about 11ty, so I thought I’d make the most of the lockdown and give it a go whenever I had an hour or so free.

11ty logo

What you’re looking at now are the fruits of that labour. If you were familiar with the old site, you probably wont notice much different; it’s the same basic design and structure, with only a few visual tweaks. Behind the scenes though, big tings.

All things considered, the whole process was pretty smooth, and I could definitely have been done much sooner if I’d given it more than my casual attention. I’ve enjoyed the excuse to learn something new and I’ve appreciated the comprehensive documentation which has helped me make sense of things. I’m also indebted to the people who’ve made their own 11ty work public on GitHub. I didn’t use any of the base builds that are floating around, but I did pick up all sorts of bits from all over the place (particularly Kristoff Michiels, Sarah Fossheim, Tatiana Mac, and James Doc). My own contribution is here: https://github.com/mattnortham/ma11northam though I’m certainly not presenting it as any sort of standard.

Likewise, here are a few notes on the process that are by no means a ‘guide’, but might help you if you’re getting to grips with 11ty (and will serve as a reminder to me when I next come to do this). They’re conveniently split into 11 points which I PROMISE was not intentional, but I’ll happily accept.

  1. Getting content out of WordPress
  2. Handling images
  3. Markdown It
  4. Dates
  5. Console.logging
  6. Building collections
  7. Content management
  8. Deploying to your own hosting
  9. Performance
  10. Liquid
  11. Some other little things

Getting content out of WordPress 🚚

I used WP Gatsby Markdown Exporter to grab my existing content. It does a great job at converting posts into the correct format and packaging it up in manageable directories (as well as a copy of all uploaded media). That bit was quick. What took much longer though, was the tidying up. I had a lot of front matter that I didn’t want any more, and some of the content itself needed amending (image markup & media embeds were the main culprits). I still haven’t finished going through all those old posts yet (I’m back to 2018 so far) but though it’s tedious, it’s actually pretty useful in terms of prompting me to review and audit it all. I’ve sanitised tags, fixed broken links, and formatted posts with a bit more consistency. Well worth it.

A side by side view of the exported front-matter and my amends

Handling images 🖼

It took me a while to get images behaving in a satsifactory way and I still haven’t really got it sorted. My main problem was in serving them up from the markdown files, and though it’s not entirely resolved (adding a class, anyone? <figure>?), I do at least have them lazyloading (with a <noscript> fallback) after rolling my own Markdown It plugin (more on that later).

Some of the many images in my photo galleries

I’ve also made use of a couple of shortcodes to render appropriately sized images in my liquid templates, which was uber important due to the number of images I’ve got in the photography section. It doesn’t go as far as responsive images yet, but does at least show small images where I want small images, and big ones where I want big ones. A little bit like this:

// Usage: {% smallImg "PATH-TO-IMAGE", "The alt", "align-left" %}
smallImg: (img,  alt,  className) =>  {
let i = img.lastIndexOf('.');
let imgPath = img.substring(0, i);
let ext = img.substring(i +  1);
let size = '-sm';
let theImage = `${imgPath}${size}.${ext}`;
if (className == "lazy-img")
return `<img data-src="${theImage}" alt="${alt}" class="lazy-img img-small ${className}">
<noscript><img src="${theImage}" alt="${alt}" class="img-small"></noscript>`
else
return `<img src="${theImage}" alt="${alt}" class="img-small ${className}">`
}

Markdown It 🗒

Speaking of Markdown It, setting the typographer option is a must " " 👀.

const mdOptions  =  {
	html:  true,
	breaks:  true,
	linkify:  true,
	typographer:  true
};

The plugin I bodged together to wrap images (which you can see here) was inspired by markdown-it-plugin-data-src.

const imgDataSrc  =  require("./src/_11ty/[imgDataSrc.js");
...
eleventyConfig.setLibrary("md",  markdownIt(mdOptions).use(imgDataSrc));

The reason I made my own was because I wanted to use a different lazyloading method, as well as the <noscript> too. For the JS, I’m making use of vanilla-lazyload, as that’s what I had before and I’ve not got any reason to stop using it. (It’s now the only bit of JS that gets applied sitewide).

Dates 📅

I made use of luxon to create a couple of date filters, for blog posts and the RSS feed.

readableDate:  (dateObj)  =>  {
    return DateTime.fromJSDate(dateObj,  {zone:  'gmt'}).toLocaleString(DateTime.DATE_FULL);
},
timeStamp:  (dateObj)  =>  {
    return DateTime.fromJSDate(dateObj,  {zone:  'gmt'}).toFormat('yyyy-LL-dd HH:mm:ss');
}

But the built in date filters are also pretty good, using the syntax from strftime like {{ post.date | date: "%B %Y" }} (which outputs April 2020). In fact, I can’t 100% remember why I created those filters when I could possibly have used those 🤔.

Still not found a simple way of adding the day suffix (st/nd/rd/th) for the readable date though.

Console.logging 🌴

Console log is a pretty recent addition. As a unashamed fan of debugging in this way, I appreciated that this is now built in. You can use it for any bit of data. I mostly found it useful to check what was making it into collections, but tbh it’s a bit of a messy way to work, as the log gets output alongside all the build notifications when running --serve in the terminal.

{{ featuredImage | log }}

Screenshot of the 11ty build output

Building collections 📦

There’s a lot written about creating collections, and handling blog posts was pretty straightforward. I liked the approach I found in Kristoff’s code of having the main post collection, and then other collections where all posts are grouped by tag and/or category. It’s a little more legwork, but made more sense to me when it came to rendering archive pages.

Beyond blog posts, I did find it a little tricky to come up with a way of managing my image galleries. I wanted to have a collection of all my images that I could loop through by tag, without creating pages for them all (because I had hundreds and it was taking a while to build, not to mention I didn’t ever link to them) – that’s where permalink: false in the frontmatter came in.

But then I wanted to have pages created only for photos with a particular tag (‘print’, indicating you can buy a copy of it). To do that, I needed to create pages from a subset of the main collection, by using ---js instead of vanilla frontmatter, which allows me to apply a before callback. You can see it on my print.liquid file.

...
pagination: {
    data: "collections.allPhotos",
    size: 1,
    alias: "photo",
    before: function(data) {
      return data.filter(function(item){
          return item.tags.includes("print");
      })
    }
}

What I’ve ended up with does feel a little convoluted, with 5 collections on the go for my photography (as well as all the blog collections). But it works, and it’s quick to build, so that’ll do for now.

Content management 🗃

I’m not really using a CMS at the moment. Plenty of talk out there about using Netlify CMS but I haven’t made any move in that direction yet. What I am using is stackedit to assist with my markdown where needed (I’ve never relly gelled with it, though it’s growing on me), and handcoded blocks for my liquid pages such as about me.

I’ve also retained a fragment of my WordPress set up to manage my photos. All the details for them are curated in WP then made available as a json file which I manually copy across to the 11ty _data directory as photos.json. That then gets picked up by front matter pagination to create the collections I mentioned before.

It’s fine. I don’t intend to change content much, but if it becomes unmanageable, I’ll look into a different approach.

Deploying to your own hosting 🚀

Contrary to general concensus, I’m not using Netlify to host my site. I already have my hosting and domain and SSL configured and paid for, so I wanted to stick with it. Frustratingly, I couldn’t find much in the way of documentation to go along with how to deploy to anywhere other than Netlify (or GitHub Pages), but I got there in the end.

I’m making use of GitHub Actions, having created a workflow file to watch for any commits to the main branch. It runs the 11ty build command then pushes it to a built branch thanks to an action intended for use with GitHub pages, and that’s where I was stuck for a while. I’ve used a GitHub workflow making use of SFTP before, but couldn’t get it to work in this particular set up.

Eventually, I opted for a middleman (👋 Buddy) which fills the CI gap with a pipeline that watches my built branch and then finally deploys via SFTP. It sounds more complicated than it is, and yes – it’s FTP 👴🏻, but I’m really pleased with how quick and seamless it actually is.

My Buddy configuration

Performance 🏎

Everyone raves about the performance gains that can come from using a static site generator like 11ty, and rightly so. The improvements can be dramatic and they’re of course very welcome. #perfmatters.

But… I’d actually worked really hard to get my old site performing well. Yeah it was WordPress but that doesn’t automatically mean ‘slow’. So when it came to testing this new site, the improvements were so minimal – and the issues that existed were of course the same. I would hope that it goes without saying but “just using” 11ty isn’t going to immediately grant your Lighthouse wishes.

There are other benefits away from the digits at the top, but it’s those numbers that get you on the 11ty Leaderboards [I still don’t know how? I want to be on there!], and purely on those numbers, my WP site more than held its own.

Old performance scores compared to new performance scores
Sidenote: on my old WP site, I made use of some randomly generated SVG wave transitions to slightly mask the minimal loading times between pages, and while I still love the effect, I thought it probably unnecessary with this new site so they’re gone (I may still bring them back 👀 they were pretty).

Liquid 💦

I used Liquid for my template files (primarily out of respect to Liquid Swords – word to GZA – and I’m loving how easy it is to use. But most people seem to use Nunjucks, so some of the syntax differences caught me out, such as…

🤔 set in Nunjucks == capture in Liquid (src).

🤔 In Liquid, elseif is actually written elsif because of course, why would it need that second ‘e’(?) 🙄 (src).

🤔 Within a forloop, to use a counter, I tried {{ assign i++ }} but it didn’t do anything. The docs recommend using increment: {{ increment myVar }} but spits it out on the page. So I ended up finding forloop.index and using {% assign num = forloop.index %} in order to track the iteration.

🤔 or doesn’t seem to work in liquid templates, despite it being referenced widely. Plenty of examples of 11ty code show things like: <title>{{title or metadata.title }}</title> but I had to change it to messier looking if statements to get it to work:
<title>{% if title %}{{title}}{% else %}{{metadata.title }}{%endif%}</title>

… and finally 🏁

A few little things that made me pull my hair out before realising they were simple fixes.

👉 When using a 11ty.js data file (like I am to generate different image sizes), you need to add them to the templateFormats in the eleventy config or they don’t get picked up. This took me a LONG time to realise: templateFormats: ["md","html","liquid","11ty.js"]

👉 If you’ve got tags being set in Frontmatter and a directory data file, and want to merge them, use deep merge: eleventyConfig.setDataDeepMerge(true)


And that’s it.

If I’m honest, I didn’t really have anything against the old WordPress site other than the ongoing fear of losing everything whenever there was an update 😬. I managed to do pretty much anything I needed to do, and I was comfortable developing with it. But, I’d had that site for 14 years and when you add on and add on to something for that long… It felt right to change it up and start from fresh (albeit, with the same design and some of the same CSS). It’s good to get out of your comfort zone. 11ty ticks a lot of front-end developer boxes for me, and I’m looking forward to working with it some more 🎉.

Some things left to do / look at

  • Related posts
  • Blog search
  • Service workers
  • Fonts that aren’t on Google
  • CMS
  • Colour theme switcher
  • Responsive images… images with captions
  • Actual pagination on the archive pages
  • Various bits of content to migrate / create
    1. Blog posts back to 2008
    2. A lot more photo collections
    3. TIL
    4. Work portfolio

Pop back soon to see the progress 👋