How I massively improved my website performance by using the right tool for the job
Tags: webdev, jamstack, nextjs, 11ty
Published: 2022-03-30 09:18:00

Great website performance and top notch [Core Web Vitals](https://web.dev/vitals/#core-web-vitals) are key to ensuring your site is fast, accessible and ranks well in search engines. From JavaScript frameworks to static site generators to lightweight build tools — there's a tool for every job! **And choosing the right tool for the job is essential to ensure you maximise performance, accessibility, and developer and end-user experience on your website.**

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](#measuring-performance).

## 2020: Svelte + Sapper

I built my first simple blog site in 2020 using [Svelte and Sapper](https://sapper.svelte.dev/). The blog posts were powered by markdown files stored in the repository, and it was a great starting point.

[View the Svelte site for fun](https://whitep4nth3rcodes.netlify.app/)!

## 2021: Next.js + Contentful

In January 2021, I joined [Contentful](https://contentful.com/developers) as a Developer Advocate, and my focus was helping developers use Contentful with popular front end JavaScript frameworks. In March 2021, I rebuilt my blog site using Contentful and [Next.js](https://nextjs.org/) — a React front-end framework that combines static pre-rendering, server-side rendering and in-built serverless functions.

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.

[View the site to refer to later](https://p4nth3rblog.netlify.app/).

## 2022: Eleventy + Contentful

Fast-forward to January 2022, when I joined the Developer Experience team at [Netlify](https://netlify.com?utm_campaign=devex-san&utm_source=whitep4nth3r-blog&utm_content=netilfy-home). And this got me thinking more about the core value proposition of the Jamstack: **serving highly optimised static pages and assets created during a build process**. Furthermore, the talk I gave in 2021 — [How to prevent the collapse of society by building an accessible web](https://whitep4nth3r.com/talks/how-to-prevent-the-collapse-of-society-by-building-an-accessible-web/) — which highlights that delivering many, many JavaScript files to the browser can hinder performance, accessibility and user experience, made me want to challenge myself to build a website that **delivered as little JavaScript to the browser as possible**.

And so I turned to [Eleventy](https://www.11ty.dev/) — a static site generator built with JavaScript — **that ships no JavaScript to the browser by default**. It's more of a build tool than a front end framework, and gives developers total control of the files and assets that are built and served to a browser from a CDN. The great thing about this migration was that I could continue to use Contentful to manage my content.

## Full disclaimer: all tools are valid tools!

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 your tools

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!

## Measuring performance

In this study, success was measured against the following four objectives:

- Ship less JavaScript to the browser
- 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](https://developers.google.com/web/tools/lighthouse/), [web.dev/measure](https://web.dev/measure/) and [Web Page Test](https://www.webpagetest.org/). 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.

## Ship less JavaScript to the browser

Using Web Page Test, I looked at the breakdown by MIME type of the home page for both sites.

### Before

The Next.js site delivered **33** JavaScript files to browser, totalling **2.94MB**.

![Screenshot from web page test showing the breakdown by MIME type for the Next.js site. The main data point is that there are 33 JS files coming to 2944566 bytes uncompressed.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ee4o0969brwojemhhrxl.png)

### After

The Eleventy site delivers just **1** JavaScript file to browser, totalling just **20.5kb**.

![Screenshot from web page test showing the breakdown by MIME type for the Eleventy site. The main data point is that there is JS file coming to 20525 bytes uncompressed.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gn4r9ydf4tyg5yq9kphc.png)

In comparing the visual design of the [Next.js site](Next.js site) with the [Eleventy site](https://whitep4nth3r.com), 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.

Next.js, by default, ships chunked JavaScript files to the browser for pre-rendering dynamic content from the Next.js server, and for interactivity on the client-side through React. In contrast, Eleventy ships no JavaScript by default, and instead outputs static HTML files as part of the build process.

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

Furthermore, the only JavaScript file that the Eleventy site ships on the home page is to power the time localisation for the "latest Twitch stream" details — and this was a purposeful addition by me.

✅ Ship less JavaScript to the browser — **success**!

## Reduce network requests

As shown in the images above, the Next.js home page made 75 network requests for HTML, CSS, JavaScript, fonts, images and other (JSON etc) files. These network requests totalled 3.98MB.

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**!

## Improve Core Web Vitals

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](https://web.dev/measure/).

### Loading

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

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)](https://web.dev/interactive/#what-tti-measures) 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

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!

### Before

![A screenshot from web.dev measure showing a performance score of 34, LCP of 2.5 seconds, TTI of 11 seconds and CLS of 0.0002 for the next.js site.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hr0spgfrylz9c4h5rzma.png)

### After

![A screenshot from web.dev measure showing a performance score of 100, LCP of 1 second, TTI of 2.5 seconds and CLS of 0.032 for the Eleventy site.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/povvecbv8c3mer2dez2f.png)

## Improve Lighthouse performance scores

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.

### Home page

Here's our baseline, showing a great improvement from 73 to 100!

![Before: 73, After 100](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xnrucgd8582xqmtiznir.png)

### A long blog post with lots of code examples

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.

![Before: 89, After: 100](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xtv72esejtx5lzcgldvy.png)

### A long blog post with lots of images

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](https://whitep4nth3r.com/blog/how-to-load-responsive-images-in-avif-and-webp-using-html-picture-element) to learn more about how to load responsive images in AVIF and WebP using the HTML <picture> tag!

![Before: 98, After: 99](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0w1bqlrt8xb9qk4j8mb4.png)

### A blog post with a YouTube video embed

Eleventy has a thriving community plugin ecosystem, and I used [eleventy-plugin-youtube-embed](https://www.npmjs.com/package/eleventy-plugin-youtube-embed) to optimise my YouTube video embeds. Using this plugin, the third-party YouTube scripts are only loaded if and when someone interacts with the video, rather than loading the JavaScript as soon as the page loads. This greatly improved the performance score from 60 to 98!

![Before: 60, After: 98](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/90f9g7fkhcuzqghjj3i9.png)

✅ Improve Lighthouse performance scores — **success**!

## Qualitative learnings

It took a little while to shift my thinking from Next.js to Eleventy. Next.js has a justifiably opinionated way of architecting a front end application — and that's fine — but in moving to Eleventy, it showed me I had perhaps become too reliant on the patterns of Next.js. In going back to web basics with Eleventy, and focussing on shipping plain HTML, CSS and JavaScript to the browser, I feel like I've refreshed and reinvigorated my knowledge of how the web works natively. And this has equipped me to approach my next Next.js project with a different, more informed mindset.

## The second system effect

Reflecting on the journey my blog iterations have taken reminds me of the [Second System Effect](https://en.wikipedia.org/wiki/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!

## Use the right tool for the job

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](https://jamstack.org/generators).

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.