Before we take a look at the performance improvements I made in the third iteration of my blog, let's take a tour back in time to when I built my first and second blog sites on the Jamstack.
To get straight to the data — click here.
I built my first simple blog site in 2020 using Svelte and Sapper. The blog posts were powered by markdown files stored in the repository, and it was a great starting point.
Throughout the year I continued to write blog posts, iterate and add functionality to the site to help developers use Next.js and Contentful together. But given the amount of features I loaded into the site, this version of my blog began to feel a little over-engineered. It was becoming more difficult to make small updates to the site, and the way I managed the content in such atomic ways felt more suited to a larger product team comprising multiple developers and content editors.
Before we get into the performance improvements I made switching from Next.js to Eleventy, I want to make it absolutely clear that all tools are valid, and me moving from Next.js does not mean I think it's a terrible tool! I think it's a great tool — especially for larger development teams that don't have the time to build their own software design patterns and scaleable architecture from the ground up. It's always super quick to get a large-scale production-ready app launched using Next.js!
Choosing a static site generator or front end framework for your new project should depend on a number of factors, including:
- What the project is and how it might grow (and this could also change!)
- How large your development team is
- Whether you need to cater for an editorial content team
- Who your end-users are, what devices they use, and where they are in the world!
My answers to these questions pushed me in the direction of building with a more lightweight solution than Next.js. Plus, this was a great opportunity to learn how to use yet another static site generator.
Additionally, more and more developers I have connected with over the last few months are using Eleventy to build lean, performant sites. I felt like this would be a good opportunity to learn from others, and help others in the process as well.
Now, let's look at the data!
In this study, success was measured against the following four objectives:
- Reduce network requests
- Improve all Core Web Vitals
- Improve Lighthouse performance scores
Performance was compared between the Next.js site and Eleventy site using three free tools: Google Lighthouse, web.dev/measure and Web Page Test. Lighthouse tests were run in Brave Browser dev tools, Web Page Test runs were conducted via the web app using the London, UK - EC2 server, and web.dev tests were conducted in the browser. Given that I advocate for mobile-first development — and that's where performance is most likely to be impacted given the unpredictable speed of mobile data — all tests were conducted in an emulated mobile environment using a medium 3G network speed, on iPhone 6/7/8.
Using Web Page Test, I looked at the breakdown by MIME type of the home page for both sites.
In comparing the visual design of the Next.js site with the Eleventy site, you might argue that the two home pages are so vastly different that there are bound to be such discrepancies. But this is down to the differences in how Next.js and Eleventy build and bundle files for production.
What's also important to note is that design is performance. I made a bunch of design decisions during the migration with performance in mind and to cut down on third-party dependencies. This included:
- removing the "latest YouTube video" from the home page
- removing Google Analytics from the whole site
- self-hosting fonts rather than requesting them from the Google Fonts CDN
The Eleventy home page makes just 9 network requests, totalling just 325.5kb.
This makes the new home page just 8% of the size of the old home page! The largest payload on the Eleventy site comes from font files — which I could do well to optimise further in the future.
✅ Reduce network requests — success!
Core Web Vitals are currently scored on three aspects of user experience — loading, interactivity and visual stability. These tests were conducted on the home page of both sites using web.dev/measure.
Loading performance is measured by the Largest Contentful Paint (LCP). To provide a good user experience, the LCP should happen within 2.5 seconds of when the page first starts loading.
And the results:
- Next.js site — LCP = 9.9s
- Eleventy site — LCP = 1s
✅ Improve LCP — success!
Interactivity is measured by the First Input Delay (FID) and measures how soon your web application responds to user input such as clicking buttons, selecting text and typing into form fields. It's difficult to accurately measure FID as it involves testing with real users, so we can use the Time to Interactive (TTI) metric to calculate how long a page takes to become fully interactive.
And the results:
- Next.js site — TTI = 11s
- Eleventy site — TTI = 2.5s
✅ Improve TTI — success!
Visual stability is measured by Cumulative Layout Shift (CLS). Have you ever clicked on a part of a web page, only to find that you unexpectedly clicked on something else after a rogue element or image was finally loaded? CLS is where content pops into view once it has loaded, often pushing content down or sideways on the web page — and can be extremely frustrating! A good user experience maintains a CLS score of 0.1 or less.
And the results:
- Next.js site — TTI = 0.002
- Eleventy site — TTI = 0.032
😬 Improve CLS — not really! It's still way below 0.1, which is good! But I'm really not sure what increased the CLS on the Eleventy site! This needs more investigation.
Here are the test results from a single run of web.dev/measure for comparison. Green numbers all round!
Given that I had focussed on the home page only in previous tests, I also tested the Google Lighthouse performance score of various blog posts with different characteristics to ensure I'd made an improvement across the site.
Here's our baseline, showing a great improvement from 73 to 100!
Lighthouse performances scores are often impacted by an "excessive DOM size", which for my blog posts, is usually the result of large code examples and the way the code snippets are highlighted using lots and lots of
<span> tags. This blog post saw a great improvement on performance from 89 to 100.
I did a lot of work on the Next.js blog with regards to optimising image formats for different browsers, and lazy loading those images where supported. The score still improved from 98 to 99, though! Read the blog post linked below to learn more about how to load responsive images in AVIF and WebP using the HTML tag!
✅ Improve Lighthouse performance scores — success!
Reflecting on the journey my blog iterations have taken reminds me of the Second System Effect. The first implementation wasn't scaleable enough for me, the second implementation was slightly over-engineered, and the third iteration is just about right — for now — thanks to all I've learned along the way!
So, do I recommend you build your next blog site with Eleventy? It depends!
People often ask me what front end framework or static site generator they should get started with, and my answer is always — it depends! The most solid advice I can give you is to decide on the features you want, decide how you might need to scale the application (in terms of team size, content management, systems and patterns), and don't be afraid to try things out. You might not get it right first time, but always endeavour to use the right tool for the job. Try not to over-engineer, and always be mindful of what you're asking your site visitors to download to their browsers. You can check out a huge list of static site generators over on Jamstack.org.
Through iterating the technology stack used for my blog, I've learned how to use three front end frameworks, how to power a blog using markdown files or a CMS — and how all of these things contribute to the developer experience, and end-user experience of a website.
As always, I would encourage you to build stuff, learn things, and love what you do. Try things, ship things, and iterate, iterate, iterate.