Why I rebuilt my blog with Eleventy

by Patrick Chong

My first intro to Javascript frontend frameworks is through Vue.js in 2017. I really like Vue’s Single File Components and how similar the Vue syntax is to HTML. Naturally, I transitioned to the batteries loaded Nuxt.js that already sets up Vue Router, Vuex, SSR etc under the hood. In fact I built the first iteration of this blog with Nuxt’s static mode and the very helpful Nuxt Content module.

As much as the status quo works, I’ve never been very happy with the long Javascript build process, the large Javascript bundles that are created (and have to be downloaded), and the Vue.js hydration process that needs to happen on the client-side. Given these limitations, I started looking for better alternatives. After all, the main reason why I like Vue is because I could create reusable components. For the most part, I was looking for templating, not reactivity.

There are already common templating languages such as Pug, Handlebars and Mustache, but they’re often used with servers like Express, and there aren’t a ton of places to host a server for free with no downtime/cold starts. I’m sure there’s a way to prerender a site using Express with one of the template languages above and some Markdown files, it doesn’t seem to be a very common solution.

Hence I began my SSG exploration! I tried Hugo and Eleventy. Hugo because it is touted as the most performant solution. Eleventy because it has gathered a lot of traction despite being quite new, and is currently powering web.dev, A11y Project and eslint.org, organisations that care a lot about best practices (which I assume to mean that Eleventy does conform to their definition of best practices).

My limited experience with Hugo was quite confusing. I tried and retried a couple of starter templates but felt stuck trying to understand Hugo’s config.toml and templating syntax, as well as working out a development process with asset compilation in the theme folder and Hugo’s own site generation process. Overall my takeaway was that It’s hard to customise a Hugo site, especially with limited Go experience. Since I do want to be able to customise freely, and didn’t want to spend too much time trying to figure out Go, I decided to not pursue Hugo for now (though I’m pretty sure I’ll revisit it someday).

Which leads me to Eleventy, which was much easier to understand since it’s all Javascript. I did run into some teething troubles, mostly with trying to recreate Vue Single File components in Eleventy (There’s eleventy-plugin-vue, but I wasn’t too keen on trying that as it’s pretty experimental). I ended up using the Nunjucks template language because it’s similar to Python’s Jinja2 that I have experience with. Nunjuck’s Macros and Eleventy’s shortcodes + paired shortcodes provided a functional way to create components, although I definitely wish for a nicer syntax to create universal components/paired shortcodes in Eleventy instead of declaring them in Javascript strings. I was stuck with slow rebuilds in development with the starter template that I used, but that gave me an opportunity to peek under the hood of how Eleventy works, and it’s really suprising how easy it was to create an Eleventy plugin with the fix that I came up with (blog post coming soon on that).

And there we have it, why I ended up rebuilding this blog with Eleventy. Appreciate the very supportive Eleventy community on Discord who have helped me with my questions. Eleventy isn’t perfect, but it’s pretty good at its job right now and it’s still improving. I look forward to how much more awesome it will be when V1 is launched! 😍

Edit 1:
I use Alpine.js as a replacement for Vue.js on this blog. I’ve not mixed Alpine components with Nunjucks macros yet, but I do foresee possible issues with code duplication when declaring Alpine components with the Alpine Data syntax. Will have to explore further on this.

P.S. It was pretty exciting to get a 100 Lighthouse score on mobile, not surprising since Eleventy itself doesn’t inject any scripts, and Eleventy Img handles image processing so well. Thankfully Alpine.js and the Tailwind CSS (with PurgeCSS) have minimal impact on the site’s load time.

Patrick Chong blog lighthouse score