You can already do this.
In Anvil, you can serve anything from any route, except for the _
namespace, which is reserved.
e.g. your theme assets are served from _/theme
Just create an @anvil.server.route
e.g. (in a server module)
import anvil.server
from anvil.files import data_files
@anvil.server.route("/assets/sw.js")
def sw(**params):
headers = {
"Content-Type": "text/javascript; charset=utf-8",
"X-Content-Type-Options": "nosniff",
"Cache-Control": "public, max-age=0, must-revalidate",
"Service-Worker-Allowed": "/",
}
with open(data_files["sw.js"]) as f:
return anvil.server.HttpResponse(body=f.read(), headers=headers)
Here i’ve used the files service, since the server module doesn’t have access to our app’s files without doing a network request.
I added this in native libraries
<script type="module">
if ("serviceWorker" in navigator) {
const url = new URL("./assets/sw.js", document.baseURI);
navigator.serviceWorker
.register(url, { scope: "/", updateViaCache: "none" })
.then((sw) => {
console.log("%cService Worker Registered", "color:green", sw);
})
.catch((error) => {
console.error("Service worker registration failed:", error);
});
}
</script>
sw.js
is a simple javascript service worker that just does some logging
// sw.js
self.addEventListener("install", (e) => {
console.log("%cService Worker installed with scope:", "color: green", self.registration.scope);
});
self.addEventListener("activate", (e) => {
console.log("%cService Worker activated", "color: green");
});
self.addEventListener("fetch", (e) => {
console.log("%cService Worker fetching", "color: green", e.request.url);
});
Here’s a clone link.
If you run the app and open the browser console, you should see the service worker logs in green.