# PWA for Zola

**URL:** <https://zola.discourse.group/t/pwa-for-zola/2090>\
**Category:** Uncategorized\
**Created:** [March 29, 2024, 12:25am UTC](https://zola.discourse.group/t/pwa-for-zola/2090 "2024-03-29T00:25:27Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![charlie137](https://yyz2.discourse-cdn.com/free1/user_avatar/zola.discourse.group/charlie137/32/1140_2.png) [@charlie137](https://zola.discourse.group/u/charlie137)\
**Post date:** [March 29, 2024, 12:25am UTC](https://zola.discourse.group/t/pwa-for-zola/2090/1 "2024-03-29T00:25:27Z")

</div>

I figured out the way to add a PWA without restructuring templates or the workflow: [A capable PWA • charlesrocket](https://failsafe.monster/posts/capable-pwa/)

Thou it would be much easier if I could template the manifest/script files as well.

---

<div class="post-metadata">

**Author:** ![jieiku](https://yyz2.discourse-cdn.com/free1/user_avatar/zola.discourse.group/jieiku/32/741_2.png) [@jieiku](https://zola.discourse.group/u/jieiku)\
**Post date:** [March 30, 2024, 4:44pm UTC](https://zola.discourse.group/t/pwa-for-zola/2090/2 "2024-03-30T16:44:39Z")

</div>

So cool to see another theme adding a PWA! I added a PWA to the Abridge theme a while ago. You are absolutely correct that without a pre cache list you can avoid npm entirely (cache as you go). I wrote the abridge theme mostly for my technical documentation/blog and I wanted to be able to cache the entire site for offline use so abridge uses npm/node to generate the file list, I also use it for a couple other things like minifying and bundling js files.

I completely agree with keeping the workflow simple where possible though, and if Zola gets the ability to template files other than html I will probably craft a way to work within Zola only.

I enjoyed reading your article, Thanks!

---

<div class="post-metadata">

**Author:** ![charlie137](https://yyz2.discourse-cdn.com/free1/user_avatar/zola.discourse.group/charlie137/32/1140_2.png) [@charlie137](https://zola.discourse.group/u/charlie137)\
**Post date:** [March 30, 2024, 5:33pm UTC](https://zola.discourse.group/t/pwa-for-zola/2090/3 "2024-03-30T17:33:55Z")

</div>

Thank you! `Abridge` is fantastic! Helped me a lot. And the CSS is just magic.

What about the background sync? It sounds like one could cache everything without lists. The permission requirement is not as streamlined as a hardcoded cache list, though. Trying to figure out if I can get minimum test coverage before jumping there 🙂

---

<div class="post-metadata">

**Author:** ![jieiku](https://yyz2.discourse-cdn.com/free1/user_avatar/zola.discourse.group/jieiku/32/741_2.png) [@jieiku](https://zola.discourse.group/u/jieiku)\
**Post date:** [March 30, 2024, 6:02pm UTC](https://zola.discourse.group/t/pwa-for-zola/2090/4 "2024-03-30T18:02:40Z")

</div>

On a dynamic server such as php I would think the service worker could get a list of files from the server, and then cache them. I am not sure there is a way to simply tell the background sync find all files and cache them all with a static site, but honestly I have not explored that route. You could also write a template that outputs the list of files to an html page, tinysearch does this, they basically output all of their json data into an html file, to later be consumed by the tinysearch executable, again this would be a lot cleaner if Zola could template files other than html.

If your solution already does what you need then I would not worry about it, but if you are also trying to find a way to cache the entire site, and you find a way to make that work with background sync then please let me know!

> <https://github.com/tinysearch/tinysearch/issues/166>
>
> For Zola sites, the tinysearch json index gets included in the sitemap.xml file.…
> 
> https://endler.dev/sitemap.xml
> 
> !\[2022-10-21\_11-59-02\](https://user-images.githubusercontent.com/106644/197269894-e41cecea-4f24-4c75-be11-ab0b5975f1c8.png)
> 
> I found a report that suggests not rendering the section will resolve the issue, but thats not the case for me: https://github.com/getzola/zola/issues/604
> 
> There is currently a pull request to allow more formats, maybe then we could output/use json instead of html? https://github.com/getzola/zola/pull/1998

> <https://github.com/Jieiku/abridge/blob/master/templates/tinysearch_json.html>

> <https://github.com/Jieiku/abridge/blob/master/templates/macros/create_tinysearch_json.html>

---

<div class="post-metadata">

**Author:** ![charlie137](https://yyz2.discourse-cdn.com/free1/user_avatar/zola.discourse.group/charlie137/32/1140_2.png) [@charlie137](https://zola.discourse.group/u/charlie137)\
**Post date:** [March 30, 2024, 7:47pm UTC](https://zola.discourse.group/t/pwa-for-zola/2090/5 "2024-03-30T19:47:00Z")

</div>

The HTML page actually worked. I built a macro that would iterate over taxonomies, the post section, and post assets that I used to show cached links on the offline page and populate the cache list. But that required the service worker pulling the whole page via `fetch()` - that felt too much. So I built another (invalid) HTML page just for the offline list via the same macro. It was still a little awkward, so I tried to approach it with another strategy, and it also worked.

It looks like I could use the macro to build available assets for the offline page, then access the list via the service worker’s loader script and pass it to the service worker itself using `postMessage()` [ServiceWorker: postMessage() method - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorker/postMessage)

Then “listen” for the message in the service worker and start the background sync if the permission check passes.

If this works, it makes sense to pull available assets directly from the service worker to populate the offline page. I’ll see if I can test it.

---

<div class="post-metadata">

**Author:** ![charlie137](https://yyz2.discourse-cdn.com/free1/user_avatar/zola.discourse.group/charlie137/32/1140_2.png) [@charlie137](https://zola.discourse.group/u/charlie137)\
**Post date:** [March 31, 2024, 12:38am UTC](https://zola.discourse.group/t/pwa-for-zola/2090/6 "2024-03-31T00:38:13Z")

</div>

Currently, I am iterating over section pages and getting the array into the service worker loader (iteration inside the `head`) via script tag attribute. And I can get `add()` working, and the cache path array is correct in the SW console. But I can’t get this array working with `addAll()` for some reason 🙂 Feels like I am almost there, though.

loader:

```auto
let cacheList = new Array(document.currentScript.getAttribute('data-cache'));

const registerServiceWorker = async () => {
  if ("serviceWorker" in navigator) {
    try {
      const registration = await navigator.serviceWorker.register("/sw.js", {
        scope: "/",
      });

      if (registration.installing) {
        console.log("Service worker installing");
      } else if (registration.waiting) {
        console.log("Service worker installed");
      } else if (registration.active) {
        console.log("Service worker active");
        registration.active.postMessage({
          type: "PRECACHE",
          payload: {
            urls: cacheList,
          },
        });
      }
    } catch (error) {
      console.error(`Registration failed with ${error}`);
    }
  }
};

registerServiceWorker();

```

sw `message` event:

```auto
onmessage = (event) => {
  console.log(`Service worker received payload: ${event.data.payload.urls}`);
};

```

**log** :

```auto
Caching the response to http://127.0.0.1:1111/syntax-theme-light.css?h=de41e87d2c9eca203b99 sw.js:20:21
Service worker received payload: ["/posts/information/", "/posts/markup/", "/posts/comments/", "/posts/pwa/", "/posts/audio/", "/posts/video/", "/posts/image/", "/posts/project/", "/posts/data/",] sw.js:35:11
Service worker fetching http://127.0.0.1:1111/webfonts/Pixeboy.woff2

```

`head` partial:

```auto
{% if config.extra.manifest %}
  {% set posts = get_section(path="posts/_index.md") %}
  <script defer src="{{ get_url(path='sw-load.js', trailing_slash=false, cachebust=true) | safe }}" integrity="sha512-{{ get_hash(path='sw-load.js', sha_type=512, base64=true) | safe }}" data-cache='[{% for post in posts.pages %}"{{ post.path | safe }}", {% endfor %}]'></script>
{% endif %}

```

So far it’s just posts, but it works. And I can trigger `add(cacheLink)` with the payload. Now the last piece, `addAll()`…

_ **UPD** _  
`TypeError: Cache got basic response with bad status 404 while trying to add request http://127.0.0.1:1111/[%22/posts/information/%22,%20%22/posts/markup/%22,%20%22/posts/comments/%22,%20%22/posts/pwa/%22,%20%22/posts/audio/%22,%20%22/posts/video/%22,%20%22/posts/image/%22,%20%22/posts/project/%22,%20%22/posts/data/%22,%20]` I see you

pushed `feature-precache` branch - looks like I might be able to sync everything without the sync API, and “pesky” permissions 🙂

---

<div class="post-metadata">

**Author:** ![charlie137](https://yyz2.discourse-cdn.com/free1/user_avatar/zola.discourse.group/charlie137/32/1140_2.png) [@charlie137](https://zola.discourse.group/u/charlie137)\
**Post date:** [March 31, 2024, 5:32pm UTC](https://zola.discourse.group/t/pwa-for-zola/2090/7 "2024-03-31T17:32:26Z")

</div>

```auto
Service worker adding 
Array [<1 empty slot>]
​
0: "['/posts/information/','/posts/markup/','/posts/comments/','/posts/pwa/','/posts/audio/','/posts/video/','/posts/image/','/posts/project/','/posts/data/',]"
​
length: 1
​
<prototype>: Array []

```

```auto
Service worker failed precache TypeError: Cache got basic response with bad status 404 while trying to add request https://feature-precache--halve-z.netlify.app/['/posts/information/','/posts/markup/','/posts/comments/','/posts/pwa/','/posts/audio/','/posts/video/','/posts/image/','/posts/project/','/posts/data/',]

```

```auto
onmessage = (event) => {
  const data = event.data.payload.urls;
  event.waitUntil(
    (async () => {
      const cache = await caches.open(cacheName);
      console.log("Service worker adding" ,data);
      await cache.addAll(data).catch((error) => console.log("Service worker failed precache", error));
    })(),
  );
};

```

Hmm

---

<div class="post-metadata">

**Author:** ![charlie137](https://yyz2.discourse-cdn.com/free1/user_avatar/zola.discourse.group/charlie137/32/1140_2.png) [@charlie137](https://zola.discourse.group/u/charlie137)\
**Post date:** [March 31, 2024, 7:03pm UTC](https://zola.discourse.group/t/pwa-for-zola/2090/8 "2024-03-31T19:03:03Z")

</div>

Got the precache working! Finishing up before pushing

---

<div class="post-metadata">

**Author:** ![charlie137](https://yyz2.discourse-cdn.com/free1/user_avatar/zola.discourse.group/charlie137/32/1140_2.png) [@charlie137](https://zola.discourse.group/u/charlie137)\
**Post date:** [March 31, 2024, 7:54pm UTC](https://zola.discourse.group/t/pwa-for-zola/2090/9 "2024-03-31T19:54:40Z")

</div>

Pushed the current implementation. Now I need to start considering payload size/uplink speed in the precache events.

---

<div class="post-metadata">

**Author:** ![charlie137](https://yyz2.discourse-cdn.com/free1/user_avatar/zola.discourse.group/charlie137/32/1140_2.png) [@charlie137](https://zola.discourse.group/u/charlie137)\
**Post date:** [March 31, 2024, 9:36pm UTC](https://zola.discourse.group/t/pwa-for-zola/2090/10 "2024-03-31T21:36:41Z")

</div>

precache PR [feat(pwa): implement precache by charlesrocket · Pull Request #24 · charlesrocket/halve-z · GitHub](https://github.com/charlesrocket/halve-z/pull/24)

---

<div class="post-metadata">

**Author:** ![charlie137](https://yyz2.discourse-cdn.com/free1/user_avatar/zola.discourse.group/charlie137/32/1140_2.png) [@charlie137](https://zola.discourse.group/u/charlie137)\
**Post date:** [March 31, 2024, 9:41pm UTC](https://zola.discourse.group/t/pwa-for-zola/2090/11 "2024-03-31T21:41:34Z")

</div>

@jieiku precache works great (tho I might need to investigate the kickin/installation)

Now I need to figure out how to approach the network…

---

<div class="post-metadata">

**Author:** ![charlie137](https://yyz2.discourse-cdn.com/free1/user_avatar/zola.discourse.group/charlie137/32/1140_2.png) [@charlie137](https://zola.discourse.group/u/charlie137)\
**Post date:** [April 9, 2024, 7:33pm UTC](https://zola.discourse.group/t/pwa-for-zola/2090/12 "2024-04-09T19:33:39Z")

</div>

Polished cache events and the dynamic list, and started to look for more things to build, but the rest of the PWA features are not very attractive. Support for sync APIs is very limited due to questionable implementations (same for the network) at the moment, and I don’t see it changing anytime soon. But it looks like push notifications are more accessible than I thought—I might get a light and free solution if I can digest that much JavaScript [Setup Push Notification For PWA](https://code.luasoftware.com/tutorials/pwa/setup-push-notification-for-pwa). Downside—possible delays, but I am planning to start with a basic “New Post” with daily notifications, so it should not be noticeable. Rewriting the service worker in Zig/WASM is on the list, but I am not sure yet if I could seamlessly deploy that without a custom helper for Zola.

---

<div class="post-metadata">

**Author:** ![charlie137](https://yyz2.discourse-cdn.com/free1/user_avatar/zola.discourse.group/charlie137/32/1140_2.png) [@charlie137](https://zola.discourse.group/u/charlie137)\
**Post date:** [September 27, 2024, 5:04pm UTC](https://zola.discourse.group/t/pwa-for-zola/2090/13 "2024-09-27T17:04:36Z")

</div>

Service worker notifications merged! [feat(pwa): implement service worker notifications by charlesrocket · Pull Request #34 · charlesrocket/halve-z · GitHub](https://github.com/charlesrocket/halve-z/pull/34)

---

<div class="post-metadata">

**Author:** ![charlie137](https://yyz2.discourse-cdn.com/free1/user_avatar/zola.discourse.group/charlie137/32/1140_2.png) [@charlie137](https://zola.discourse.group/u/charlie137)\
**Post date:** [October 17, 2024, 8:55am UTC](https://zola.discourse.group/t/pwa-for-zola/2090/14 "2024-10-17T08:55:37Z")

</div>

Dynamic cache name [feat(pwa): use dynamic cache name · charlesrocket/halve-z@bd46521 · GitHub](https://github.com/charlesrocket/halve-z/commit/bd46521af7c81cdb7a588e72cb2e3c38b74529e7)

---

<div class="post-metadata">

**Author:** ![charlie137](https://yyz2.discourse-cdn.com/free1/user_avatar/zola.discourse.group/charlie137/32/1140_2.png) [@charlie137](https://zola.discourse.group/u/charlie137)\
**Post date:** [October 21, 2024, 7:57am UTC](https://zola.discourse.group/t/pwa-for-zola/2090/15 "2024-10-21T07:57:23Z")

</div>

It turned out that parameters via SW URL are not a good idea. So I improved stale-revalidate and optimized more for static content.

> **[Release 0.19.1 · charlesrocket/halve-z](https://github.com/charlesrocket/halve-z/releases/tag/0.19.1)**
>
> Bug Fixes
> 
> Fix fetchedResponse() return
> Fix search cache
> Fix offline mode
> Update fetchedResponse log message
> Handle navigation request
> Set 404 title
> 
> Miscellaneous tasks
> 
> Bump cache to v15
> 
> Styling...
