I announced it on twitter last week and here you go with my new blog post about the migration from GatsbyJs to 11ty/Eleventy. In this post, I explain to you why I migrated to Eleventy, what were my challenges and how you can avoid them.

I read much about Eleventy the last month and its creator Zach Leatherman. I got curious as I saw that it needs zero client-side JavaScript.

Eleventy is a simpler static site generator.

I try to have about 2 hours to one day a week where I try something new for education purposes. So I decided to try out Eleventy. I thought I could use it for my clients who only need a static landing page. I ended up migrating my whole website from GatsbyJs to 11ty.

Tldr

In this post, I show you why I migrated my website from GatsbyJs to Eleventy, what my challenges were and how you can avoid them. This post tries to outline the main advantages and disadvantages of Eleventy compared to GatsbyJs.


If you like this article, please share it, follow me, check out my RSS feed and subscribe to my newsletter.


Table of Contents

  1. What is Eleventy, and how does it work?
  2. What is GatsbyJs, and how does it work?
  3. Why I struggled with GatsbyJs?
  4. My migration from GatsbyJs to Eleventy
  5. Is GatsbyJs a wrong choice?
  6. Next steps
  7. Conclusion

What is Eleventy, and how does it work?

Eleventy is a simple static site generator. That’s it. It uses data and templates to generate HTML files you can upload to your hoster and serve them statically.

That is almost all you need to say about Eleventy. It is fascinatingly simple. Of course, we are going to dive deeper, and there is a lot more to mention, but the paragraph above describes 11ty in its core concept.

You start with Eleventy by choosing your preferred template engine. Probably the easiest is markdown. The following file shows a simple markdown example for eleventy. Eleventy uses your file structure to generate HTML files.

index.md

# My custom headline

Now let’s run this simple example with: npx @11ty/eleventy. This command will generate a _site directory with an index.html containing the following markup.

_site/index.html

<h1>My custom headline</h1>

What if you have more complex content that you can not display with markdown? Eleventy supports multiple template engines you can use.

Template engines

  • HTML *.html
  • Markdown *.md
  • JavaScript *.11ty.js
  • Liquid *.liquid
  • Nunjucks *.njk
  • Handlebars *.hbs
  • Mustache *.mustache
  • EJS *.ejs
  • Haml *.haml
  • Pug *.pug
  • JavaScript Template Literals *.jstl

Layouts

While I tried out some of the templates, I recognized how fast I was able to create pages. I went with Nunjucks as it is very flexible. In no time a created pages and wrapped them with layouts. Layouts are some special templates in Eleventy you can refer from your pages. A layout for our example above could look like this:

index.md

---
layout: main.njk
---

# My custom headline

_includes/main.njk

---
title: My tutorial
---

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Why I migrated my website from GatsbyJs to Eleventy</title>
</head>
<body>
... contents
</body>
</html>

The layout in the _includes folder wraps the index.md page and outputs all to the _sites folder.

Data Cascade

Working with data in eleventy is actually very simple. The data is merged from different sources before the engine renders the template. The data-merging is called Data Cascade and it contains the following parts.

  1. Computed Data
  2. Front Matter Data in a Template
  3. Front Matter Data in Layouts
  4. Template Data Files
  5. Directory Data Files (and ascending Parent Directories)
  6. Global Data Files

Configuration

You can use Eleventy without any configuration, but if you want to add some additional features or use a plugin you can add it to your .eleventy.js file and expand the functionality.

Filters and Shortcodes

With filters and shortcodes you can expand the template functionality. For example, you could define a shortcode that renders a button or a filter that formats a date.

What is GatsbyJs, and how does it work?

Gatsby is a static site generator as well. It is React-based and uses GraphQL. It is preconfigured and has used many tools you need to implement usually by yourself like webpack or a service worker. Gatsby uses the pages directory to create each page for your site. It has a huge community and a wide range of plugins with whom you can expand the functionality of your website.

It builds its data-layer with GraphQL and transforms your JSON, markdown files or external API data to nodes which you can use and query in your templates. You can start very fast with your first GatsbyJs site with the Quick Start on the GatsbyJs documentation site. Last year I did a web performance experiment and chose GatsbyJs because they promise a blazing fast site.

Why I struggled with GatsbyJs?

GatsbyJs is an excellent framework, and while many developers do not like ReactJs because of its performance bottlenecks, I found myself happy with my developing experience. If you didn’t read through my web performance experiment I had some trouble last November after I launched my site. I knew I would have some performance issues to face, but I wasn’t expecting such big ones.

My site was slow even while I used blazing-fast GatsbyJs. Of course, there were many issues which weren’t related to Gatsby, but Gatsby was part of the problem. I spend hours over hours to optimize my site. Even though I know what I am doing, it was quite hard and took much longer than developing my website from scratch.

Gatsby needs much client-side JavaScript to work. If you work on web performance, you know, it’s good to reduce client-side JavaScript to a minimum. If you are not into that topic check out how the browser parses JavaScript in my blog post about JavaScript high performance and especially my series about the Business Value of Speed where I go through the sequence of steps the browser needs to process before it can paint a pixel.

I wanted to reduce the amount of JavaScript and was quite successful with a plugin called gatsby-plugin-preact it replaces React with Preact and cut the bundle files size of my framework-[hash].js from ~40kB to 8.6kB. That was great, but at the same time, it was a bit strange to erase the developing framework React at build time.

Nevertheless, I still struggled with all of my components. I did some research and found the plugin gatsby-plugin-no-javascript. It removes JavaScrpt at build time. I looked at the file size and was happy for a moment. Just for a moment because I knew it breaks my site. I’ll tell you the truth. I wasn’t able to reduce the amount of JS to a proper file size. While I write this post, I still have 81.8kB of JavaScript for the main app rendering my mostly static site.

Not to mention that I use lazy loading like a freak so additionally, I have 20 requests to JS files that are loaded later between 2kB and 25kB. You could say let’s reduce the JavaScript of our components. I did this for hours. I deleted code, I changed libraries, and I removed functionality.

My migration from GatsbyJs to Eleventy

Here comes Eleventy. At this time now, I migrated all my content to 11ty and implemented all interactions with JavaScript that I need. I now have one main.js of 2.2kB and two bundles that are lazy-loaded with webpack on the pages that needs them. One with 941 B and one with 678 B. I didn’t remove any functionality.

The following table shows you the size of all MIME Types before and after the migration.

Before

MIME TypeBytesUncompressed
js247,435675,335
image59,60659,606
html23,21090,011
other22,530110,534
css2,1266,455

After

MIME TypeBytesUncompressed
font65,55265,552
image50,26350,263
js21,59052,300
html18,74285,866
css3,23110,972
other3361,148

So where did I started? index.js. Nope. As my home page is an overview page I started with my last blog post. I write my blog posts in markdown and use frontmatter in the head of the file for additionally information. This blog post you currently reading looks like this:

---
tags:
- 'javascript'
- 'webperformance'
layout: layouts/post.njk
article: true
title: 'Why I migrated my website from GatsbyJs to Eleventy'
date: '2020-08-05'
author: Marc Radziwill
seo:
{
follow: 'index,follow',
title:
'blog: Why I migrated my website from GatsbyJs to Eleventy - Marc
Radziwill',
description:
'Eleventy is the new runner up in the JAMstack community. Read why I
struggled with GatsbyJs and why I choose Eleventy for my website >>',
}
categories: ['javascript', 'webperformance', 'business']
keywords:
- webperformance
- frameworks
image:
{
src: ./src/blog/business-value-of-speed-part-two-metrics-and-mapping-of-business-values/images/business-value-of-speed-part-two-metrics.jpg,
alt: 'alt text',
title: 'image title',
}
readingDependencies: You must be at least a level beginner to make this happen
readerLevel: beginner
published: true
isTechArticle: true
---

These files have quite some information in it. In Gatsby, I needed to create NodeFields to query them. So for every entry, I did:

createNodeField({
name: 'title',
node,
value: node.frontmatter.title,
})

In Eleventy and due to their data cascade these values are already accessible in template file for example if you loop through a collection of pages with in the data Object like this:

{%- for page in collections.all -%}
<h2>{{ page.data.title }}</h2>
{%- endfor -%}

After one hour, I migrated all my posts content without the images. I was convinced and decided to migrate my entire content. That was what I was looking for.

I continued by defining a layout for my base pages and my blog pages to serve different CSS and JS files. I built the main components and Nunjunk partials like the header and the footer, and I created some shortcode components like a button.

One week later, I am ready for my first test with my site running completely on Eleventy. I was fast. Faster than I ever thought I could be re-writing my whole website. But I also was struggling with some parts.

My Image pain

Images were my biggest problem. My site contains a lot of header images that I want to render in a picture-tag with correct sizes and formats that the browser can decide which image it should download. Gatsby has a smooth plugin that handles images, and for Eleventy, I chose the plugin eleventy-img and wrote a Nunjunk async shortcode to render the images before the blog content starts.

Async image shortcode

{% resImage theme.logo.src, "alt text", theme.logo.options, "title text" %}

That worked quite well for all Nunjunk templates, but I could not use them in my blog posts as they are based on markdown. For all markdown images below the fold, I implemented a workaround. There might be a better solution, and it still feels a bit dirty, but for now, it works.

First I encounter all img tags with an eleventy transformer for all html files that are in my _site folder. I us the npm package basichtml to make the content of each page selectable and query all images with document.querySelectorAll('.post-content :not(picture) img[src]:not([srcset]):not([src$=".svg"])'.

I loop through them and create a picture-tag with the help of my resImage async shortcode. The idea to this and some part of the code is from Nicolas Hoizey - Eleventy Image Responsiver. After all, images are converted to a picture-tag with the correct source path, I use the eleventy-plugin-lazyimages to use native image loading for my images.

Additionally, I wanted to have my image files located where the blog post file is. This makes it easier for me to maintain them and to cross-post them to dev.to, for example.

So my file structure looks like this:

blog
│───blog-post-1
│ └───images
│ image-1.png
│ image-2.png
│ index.md

eleventy-plugin-lazyimages wasn’t able to locate the relative path from the blog post. I know that this usually should work, but I wasn’t able until now to make it work. For now, I use the absolute path starting with ./src/blog/blog-post-1/images/image-1.png. This results in a confusing pah in my _site directory like _site/assets/images/src/blog/blog-post-1/images/image-1/9cd1e3v7-300.jpeg. That is definitely something I need to improve. I would recommend using the image folder for all images if you are facing the same issues.

Is GatsbyJs a wrong choice?

No, not at all. Gatsby was a wrong choice for me, having my requirements and wanting to have a site without much JavaScript, but GatsbyJs provides some great features. If you are struggling with JavaScript, you should consider migrating to Eleventy as well. Eleventy is fast and flexible not only while you are developing but also during runtime.

Next steps

I migrated my website in one week from Gatsby to Eleventy. So for the moment, I am delighted and satisfied. For sure there are still some open tasks which I will work on the next weeks. If you are thinking about migration, I recommend you to try out Eleventy. It is fun, and you will love it! ♥️ Check out my current result.

Conclusion

In this post, I tried to show you why I migrated my website from GatsbyJs to Eleventy and why I think this is important for a fast site.

If you like this article, smile for a moment, share it, follow me, check out my RSS feed and subscribe to my newsletter.

Cheers Marc