After mobile first, offline first and progressive web apps (PWA) are the current trend at the moment.
So, why not to make your eleventy's powered website works in offline too ?
Install PWA-plugin for eleventy
Let’s start by installing eleventy-plugin-pwa
$ npm install eleventy-plugin-pwa --save-dev
In this case, using plugin instead using workbox-cli or other interface like gulp/webpack are easier,
Especially when you're using the eleventy --serve
to test and watch your changes, since this plugin will automatically follow and rebuild our service-worker too.
Adding it to Eleventy config file
As usual, we need to include the plugin in our .eleventy.js
to enable it.
// .eleventy.js
const pluginPWA = require("eleventy-plugin-pwa");
module.exports = (eleventyConfig) => {
//...
eleventyConfig.addPlugin(pluginPWA, {
swDest: "./build/service-worker.js",
globDirectory: "./build",
clientsClaim: true,
skipWaiting: true
});
//...
};
Also you can use it without any configuration, which by default it will set the destination to ${eleventy.outputDir}/service-worker.js
.
For more info about the options, you can read here :
https://developers.google.com/web/tools/workbox/modules/workbox-build#full_generatesw_config
manifest.json
To make it installable on mobile devices, we need to add ./manifest.json
for it.
{
"name": "My Beautiful Website",
"short_name": "okitavera.me",
"icons": [
{
"src": "/assets/img/favicon/192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/assets/img/favicon/512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#ec407a",
"background_color": "#ec407a",
"display": "standalone",
"start_url": "/"
}
copy ./manifest.json
directly using addPassthroughCopy()
(documentation)
module.exports = (eleventyConfig) => {
//...
eleventyConfig.addPassthroughCopy("manifest.json");
//...
};
Also don't forget to mention that file inside your header
<head>
...
<link rel="manifest" href="/manifest.json" />
...
</head>
Registering Service Worker
Now the tricky part is registering service worker.
Because we need our website updated everytime the we had a new content, we need to cache-bust the service worker file.
The simplest ways to do this is using eleventy's addFilter to append a new string everytime we run the eleventy to build our page.
// .eleventy.js
module.exports = (eleventyConfig) => {
//...
// append "?v=timestamp" to the end of str
eleventyConfig.addFilter("cacheBust", (str) => {
const dateNow = Date.now();
return str.concat(`?v=${dateNow}`);
});
//...
};
And finally, we put a simple javascript into our header/footer to register the service-worker.
<script>
if ("serviceWorker" in navigator) {
navigator.serviceWorker
.register("{{ '/service-worker.js' | cacheBust }}")
.then(function() {
console.log("ServiceWorker has been registered!");
})
.catch(console.error);
}
</script>
Update
Since eleventy-plugin-pwa
now use staleWhileRevalidate
method by default, now we can just put our registration scripts without cache-busting tricks.
<script>
if ("serviceWorker" in navigator) {
navigator.serviceWorker
.register("/service-worker.js")
.then(function() {
console.log("ServiceWorker has been registered!");
})
.catch(console.error);
}
</script>
Final
Okay, it's time to test our 5 minutes work.
Lighthouse benchmark:
eleventyJAMstackwebdev