Eleventy - Is it time to upgrade to version 3?

A dark purple upgrade icon, a circle with an arrow pointing up, is in the center of the frame. The eleventy possum floating beside it on a balloon. It is cast againt a soft purple background.

Version three of Eleventy has some exciting new features such as async configuration, virtual templates, and ECMAScript Modules (ESM) support. I am keen to upgrade, it unlocks some possibilities for features I’d like to work on!

Version three is still in pre-release. It has reached it first beta (v3.0.0-beta.1). It should be in decent shape, but you are going to be somewhat of a canary tester if you use a pre-release version. You may have a smooth ride or you may hit speedbumps along the way depending on your particular configuration.

After reading some accounts of other people upgrading (Raymond Camden, Helen Chong, and Bob Monsour), it encouraged me to give it a go! I set myself a time limit of three hours. I will need to shelf it for another time if it takes longer than that.

How to upgrade

I made a new branch of my website and followed the instructions in the v3.0.0-beta.1 release notes:

  1. I installed Eleventy v3 beta. You should do this first. I use pnpm as my package manager, so I ran pnpm add @11ty/eleventy@beta to add it as a dependency.
  2. I took the extra step of uninstalling the previous version of eleventy because I wanted to ensure my npm scripts would work. I ran pnpm remove @11ty/eleventy.
  3. I installed the upgrade helper plugin with pnpm add @11ty/eleventy-upgrade-help@3.
  4. I added the plugin to my configuration file (as below). I made sure that it was the last addPlugin() call.
Javascript
// eleventy.config.js
const UpgradeHelper = require("@11ty/eleventy-upgrade-help");

module.exports = function(eleventyConfig) {
// If you have other `addPlugin` calls, UpgradeHelper should be listed last.
eleventyConfig.addPlugin(UpgradeHelper);
};

Version three supports both CommonJS and ESM. I should not need to change anything in theory. Hopefully, I will dodge the breaking changes.

I ran Eleventy in serve mode. It spat out an error! Let’s see if I can fix things up…

Upgrade issues

I encountered three errors and 1 warning.

Error 1 - Tabs are prohibited in YAML frontmatter

The first issue was a complaint about having tabs in YAML frontmatter. It was pointing at the tag.njk file.

Log
[11ty] Problem writing Eleventy templates:
[11ty] 1. Having trouble reading front matter from template ./src/pages/tag.njk (via TemplateContentFrontMatterError)
[11ty] 2. tab characters must not be used in indentation (10:1)
[11ty]
[11ty] 7 | stylesheet: "/assets/stylesheet ...
[11ty] 8 | eleventyComputed:
[11ty] 9 | title: Posts tagged with “{{ ...
[11ty] 10 | →permalink: /blog/tag/{{ tag | ...
[11ty] ------^ (via YAMLException)
[11ty]
[11ty] Original error stack trace: YAMLException: tab characters must not be used in indentation (10:1)
[11ty]
[11ty] 7 | stylesheet: "/assets/stylesheet ...
[11ty] 8 | eleventyComputed:
[11ty] 9 | title: Posts tagged with “{{ ...
[11ty] 10 | →permalink: /blog/tag/{{ tag | ...
[11ty] ------^

The js-yaml library was upgraded from version three to version four. It is more strict on enforcing formatting. Tabs in YAML frontmatter will now break the build.

Replacing the tab in the frontmatter with 2 spaces solves this issue. Thankfully it was only one instance in my project! So it was a quick fix.

Error 2 - Failed version check of Sass plugin

The next issue came from the eleventy-sass plugin that I use for adding Sass support to Eleventy. The plugin has a version check. It does not support version three yet, so it breaks the build.

Rather than getting into the weeds, I just removed it as a plugin from my config. This got rid of the error but also removed the styles from my website! Everything looks rather bland now!

I will circle back later to see if there is a quick solution to this.

Error 3 - A peciular TemplateContentPrematureUseError error

The next error I recieved was a TemplateContentPrematureUseError error as below.

Log
[11ty] Unhandled rejection in promise:
[11ty] Tried to use templateContent too early on ./src/posts/new/2024-08-17-code-embeds/index.md (via TemplateContentPrematureUseError)
[11ty]
[11ty] Original error stack trace: TemplateContentPrematureUseError: Tried to use templateContent too early on ./src/posts/new/2024-08-17-code-embeds/index.md
[11ty] at Object.get [as templateContent] (file:///home/rob/programming/workspace/websites/roboleary-v0_3/node_modules/.pnpm/@11ty+eleventy@3.0.0-beta.1/node_modules/@11ty/eleventy/src/Template.js:612:14)
[11ty] at Object.memberLookup (/home/rob/programming/workspace/websites/roboleary-v0_3/node_modules/.pnpm/nunjucks@3.2.4_chokidar@3.6.0/node_modules/nunjucks/src/runtime.js:201:17)
[11ty] at eval (eval at _compile (/home/rob/programming/workspace/websites/roboleary-v0_3/node_modules/.pnpm/nunjucks@3.2.4_chokidar@3.6.0/node_modules/nunjucks/src/environment.js:527:18), <anonymous>:83:15)
[11ty] at iterCallback (/home/rob/programming/workspace/websites/roboleary-v0_3/node_modules/.pnpm/nunjucks@3.2.4_chokidar@3.6.0/node_modules/nunjucks/src/runtime.js:236:11)
[11ty] at next (/home/rob/programming/workspace/websites/roboleary-v0_3/node_modules/.pnpm/nunjucks@3.2.4_chokidar@3.6.0/node_modules/nunjucks/src/lib.js:258:7)
[11ty] at eval (eval at _compile (/home/rob/programming/workspace/websites/roboleary-v0_3/node_modules/.pnpm/nunjucks@3.2.4_chokidar@3.6.0/node_modules/nunjucks/src/environment.js:527:18), <anonymous>:127:1)
[11ty] at /home/rob/programming/workspace/websites/roboleary-v0_3/node_modules/.pnpm/eleventy-plugin-killer-filters@0.6.0/node_modules/eleventy-plugin-killer-filters/eleventy.config.js:39:9
[11ty] at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

The error pointed to a markdown post. There was nothing special about that post. I removed the post to see if that changed things, it didn’t! It threw the same error but pointed to another post! That’s weird!

After digging through the issues of the Eleventy repo, I discovered that the error has nothing to do with markdown posts. My situation matched the explanation given in the issue - Tried to use templateContent too early in eleventy 3.0.0-alpha.3 on rerender. The actual cause of the issue is the htmlAbsoluteUrls filter that is supplied by the official RSS plugin. I use that filter in a template (feed.njk) to generate my RSS feed. When I deleted feed.njk, the error went away!


With those issues overcome temporarily, my website appeared to running in serve and build modes correctly.

In order for me to publish my website using version 3 beta, I would need to do the following to have my website in the exact same state as before:

  1. To restore my styles, I would need to update the eleventy-sass plugin. It appears that the plugin author has made a new major version supporting Eleventy v3. It requires Node.js v22+ and uses an experimental Node feature. I’m not sure I want to go down that road. And I would need to test it to check on the stability. I will need to delve deeper to make a decision.
  2. Probably the cleanest solution for the RSS feed template (feed.njk) is to convert it to a virtual template. This is not something I want to rush into. My feed has some conditional logic, so it is not a quick conversion. I’d need to test it properly to ensure that the outputs match.

Revising those 2 facets of my website would definitely push me over my 3 hour limit. I will need to shelf this for now.

I can use the time left over to do a quick reconnaissance on converting my configuration to ESM. That is something I’d like to get to eventually also.

What about converting your eleventy configuration to ESM?

My configuration file is split into approximately 40 files, and I have quite a few data files. To feel out the process, I wanted to work with a small subset of my website. I deleted the majority of the pages, templates and markdown files that were using a lot of filters and shortcodes. I edited my config to use the minimum number of imports and was able to get things running.

The only big issue I found was with importing JSON files. You should be able to import a JSON file in Node with the following syntax: import data from './data.json' assert {type: 'json'};. Importing a JSON file in Node is still an experimental feature, it can cause issues.

Eleventy does not handle JSON imports gracefully yet, the problem is outlined in the issue - Import attributes not yet supported (Error thrown from acorn dependency). In serve and watch mode, JSON imports crash operation. You cannot ignore the issue.

There is a workaround with module.createRequire. It will permit importing a JSON file like you would in CommonJS:

Javascript
import { createRequire } from "node:module";
const require = createRequire(import.meta.url);
const data = require("./src/data/site.json");

You could convert your JSON files to JavaScript files also if you prefer. I guess that when Node fully supports JSON imports, this issue will be resolved downstream eventually also.

Conclusion

I got most of the way through upgrading to version three of Eleventy. It will entail rewriting a couple parts of my website for me to get over the line. I don’t have more time to give to that effort right now. I will favour a refresh of my website before I follow through with the upgrade.

Thanks to all the folks who have worked hard on this release! 🙌

Tagged