kimlai

kimlai

Pre-caching assets with a service-worker

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!

Most Liked

lucaong

lucaong

I use the same strategy for the ServiceWorker on an offline-first production Rails + JS application with good results since years. While somewhat uncommon, there is no issue in rendering a JS file with EEx when needed.

Of course, LiveView needs some special care when it comes to offline behavior, and depending on your needs, being it a server-side tech, it might not be the best option if offline-first is a strong requirement.

Where Next?

Popular in Questions Top

chrisalley
ExUnit now has describe blocks which is a welcome addition coming from RSpec. In the docs, it states that nested hierarchies of describe ...
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
Fl4m3Ph03n1x
About me? ( if you have nothing better to do than reading about some random guy in the internet :stuck_out_tongue: ) Hello all, this is ...
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
lucidguppy
I have a super simple question about elixir - how would I take a file like this foo bar baz and output a new file that enumerates th...
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
dblack
I’ve got an issue with an app and I’ve no idea of how to troubleshoot it. I’m hoping someone here might have seen something similar. I p...
New
rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list. ...
New
dotdotdotPaul
Okay, I’m having a heck of a time trying to figure out how to best handle the validation of belongs_to associations in Ecto. I’m sure I’...
New

Other popular topics Top

malloryerik
Hi, this is for people who, like me, have had some friction using .html.heex templates in VSCode. The solution seems to be, in a hyphena...
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
Lily
In templates/appointment/index.html.eex: &lt;%= for appointment &lt;- @appointments do %&gt; &lt;tr&gt; &lt;td&gt;&lt;%= appoi...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New
PeterCarter
There are pre-rolled solutions for other frameworks that do work. However, Phoenix does not seem to have these. Have people had good expe...
New

We're in Beta

About us Mission Statement