Dark mode switch icon Light mode switch icon

How to make a PWA out of your Eleventy site

5 min read

While tinkering with one of my projects I ventured to explore how to make a progressive web app out of an Eleventy site. A few months later, I’m happy to report two things. First, it’s perfectly doable. Second, you probably don’t want to do it. But let’s start from scratch.

What is a progressive web app (PWA)?

Mozilla docs define PWA as ‘an app that’s built using web platform technologies, but that provides a user experience like that of a platform-specific app’.

In simpler terms, it’s a website that badly wants to be an app on your phone when it grows up. And it gets very close to that goal. It can be installed and opened on a phone like a typical app - no browser toolbars, can work in the background (even offline), and you can have it as an icon on your phone’s screen. But the mimicry ends there. It’s still a website.

There are valid reasons to make progressive web apps. In some use cases building ‘true’ mobile apps makes no sense (not to mention it’s rather expensive). Being able to use it offline is also a nice benefit.

To create a progressive web app, we need a website (duh!), a web app manifest, an icon, and a service worker.

And what if we have an Eleventy-powered website?

There are plugins for that

I quickly found a few Eleventy plugins generating a service worker. To achieve the goal, they used Google Workbox library and did some monkey-patching around Eleventy build process to generate a list of built files for the service worker.

Eleventy 2.0.0 arrived and all of those plugins were broken for I don’t know how long. And they were roaming around NPM registry like zombies, with their authors nowhere to be found.

Fortunately, with Eleventy 1.0.0 monkey-patching was no longer necessary - we got configuration events, such as eleventy.before and eleventy.after. The latter one was the crucial missing bit to make things work again.

So I made my own fork, fixed what was broken, improved the documentation and published my own fork, called eleventy-plugin-pwa-v2. You can install it via NPM.

If you use any of my Eleventy templates (I currently have two: Bliss and Multiplicity) you likely have this plugin installed and you can enable it with a relevant property in the site configuration.

And what about PWA manifest? App icon?

Both can be created by hand and it’s a one-time process. Mozilla docs has a great explainer on manifest syntax.

In Eleventy, we have even more plugins for that. My go-to solution is eleventy-plugin-gen-favicons by Nick Aldwin. It creates a set of favicons out of a single SVG file according to contemporary best practices (no longer we need Windows Tile icons or Safari Pinned icons folks!) as well as the manifest file we need for our PWA to work.

eleventy-plugin-pwa-v2 + eleventy-plugin-gen-favicons === happiness.

Actually no. Sometimes there’s no happiness

There is something you need to know.

When a person visits your site, the service worker is installed in their browser. And it stays there.

When you update the site, the service worker gets updated as well. You have an option to configure how you want files cached by your service to update (Workbox strategies), but unless the service worker performs full update cycle, your visitor will see the stale copy of your site. This sucks.

The correct approach to this problem is implementing an UI element to prompt the visitor to update the site (a button saying ‘Update is installed, click to refresh’). Or you can force the website refresh with plain rude window.location.refresh(). Either way, it still forces your visitor to wait until the site reloads.

At this point of time I thought to myself: god dammit, most of my sites are a bunch of plain text content with minimal CSS. This is too much hassle for very little gain. It would probably have made sense if my site fetched the content like a ‘real’ web app. But a bunch of statically generated text files? I stopped here and moved on to other fun things.

Even worse, removing a service worker in a way it really gets removed from visitors’ devices requires some effort. You cannot just remove the plugin and call it a day. Your website has to call unregister() method to bring things back to the old normal and hope your visitor opens your site again.

While writing this article, I also found out service worker can be forced to install immediately by skipWaiting() method. I didn’t test it though. Maybe some other time.

And one more thing - don’t be like me and don’t update your DNS servers and PWA caching settings at once. It’s no fun to know some of your visitors see the correct version of your site while others not. But that’s a story for another time.

So to sum up…

If you’re determined to make a PWA out of your Eleventy site - one SVG icon and two plugins will get you covered.

But be sure the benefits outweigh the inconvenience because the road back is bumpy. The worst that can happen is your visitors may be stuck with an old version of your site.

Originally published on by Łukasz Wójcik