Hi everyone,
I’m trying to add a service worker to a Phoenix 1.5 app to display an offline page when the user has no network connectivity. To do this I need to cache some static assets (css, fonts and an image) along with the html page itself.
Following this cookbook, I would need something like
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open('pre-cache:v1').then(function(cache) {
return cache.addAll([
'/css/app.css',
'/images/logo.svg',
'/fonts/some-font.woff2',
'/offline.html',
]);
})
);
});
Since I’m using Phoenix, my static assets are “digested” using mix phx.digest
when the app is deployed to production, so I need to cache the files using their hashed names. I also want the service worker to work locally, where the filenames do not contain a cache-busting hash. I also would like to avoid adding a build step. Something like workbox would require to run their cli after mix phx.digest
has run, so it’s quite awkward to make it work in conjunction with webpack to get reloading etc. when working locally (I did something like this in the past and it was not great to work with).
Basically I need a way of getting the name of some assets, with the hash in production, and without the hash locally, which is exactly what Routes.static_path/2
does, and put the result inside a javascript file.
So what I came up with it to generate the service-worker.js
file using EEx
by doing this:
# router.ex
scope "/", MyApp do
get "/service-worker.js", SomeController, :service_worker
end
# some_controller.ex
def service_worker(conn, _) do
conn
|> put_resp_content_type("application/javascript")
|> render("service_worker.js")
end
# service_worker.js.eex
...
caches.open("pre-cache:v1").then(cache => cache.addAll([
"<%= Routes.static_path(@conn, "/css/app.css") %>",
"<%= Routes.static_path(@conn, "/images/logo.svg") %>",
"<%= Routes.static_path(@conn, "/fonts/some-font.woff2") %>"
"/offline.html",
]));
...
It seems to work nicely, but I don’t think that I’ve ever seen EEx
being used to render anything but html, so I’m wondering if I missed something here (security issues, or a simpler way of doing this).
Thanks!