Cache Busting where service worker is not supported - javascript

I am using sw-precache and sw-toolbox to manage my service worker. Let's say I have a css file which I want to cache
staticFileGlobs: ['public/asset/build/css/m_index.min.css']
It get's added to the service worker on running gulp task as
var precacheConfig = [["public/asset/build/css/m_college.min.css","8d9b0e69820ba2fab83c45e2884bd61f"]
The hash with the file helps me in cache busting when service worker is registered. All works fine.
Now consider a situation where a certain PC or user or browser is unable to register service worker and the file is served through the network to him every time. In this case, the file will get stored in the browser memory because there is no cache busting by default. And it might feed the old file to that user for a lifetime even after the developer has updated the file.
What is the way to handle this scenario?

I would use the Etag response header (https://developer.mozilla.org/en/docs/Web/HTTP/Headers/ETag) to avoid loading obsolete assets for users.

For anyone looking out for answers, there is a simple solution - COOKIES.
While trying to register cookie if something fails set a cookie. This cookie than can be read on the backend before sending files
If the cookie is not set, load files without cache busting else append a cache buster on the end to prevent browser caching where service worker is not running.
Because cookies are the only thing accessible directly on both frontend and backend.

Related

Serving Angular app as a static content in Express Server

I am serving Angular app as a static content in Express Server. When serving static files with Express, Express by default adds ETag to the files. So, each next request will first check if ETag is matched and if it is, it will not send files again. I know that Service Worker works similar and it tries to match the hash. Does anyone know what is the main difference between these two approaches (caching with ETag and caching with Service Workers), and when we should use one over the other? What would be the most efficient when it comes to performance:
Server side caching and serving Angular app static files
Implementing Angular Service Worker for caching
Do both 1 and 2
To give a better perspective, I'll address a third cache option as well, to clarify the differences.
Types of caching
Basically we have 3 possible layers of caching, based on the priority they are checked from the client:
Service Worker cache (client-side)
Browser Cache, also known as HTTP cache (client-side)
Server side cache (CDN)
PS: Some browser like Chrome have an extra memory cache layer in front of the service worker cache.
Characteristics / differences
The service worker is the most reliable from the client-side ones, since it defines its own rules over how to manage the caching, and provide extra capabilities and fine-grained control over exactly what is cached and how caching is done.
The Browser caching is defined based on some HTTP headers from the assets response (Cache-Control and Expires), but the main issue is that there are many conditions in which those are ignored.
For instance, I've heard that for files bigger than 25Mb, normally they are not cached, specially on mobile, where the memory is limited (I believe it's getting even more strict lately, due to the increase in mobile usage).
So between those 2 options, I'd always chose the Service Worker cache for more reliability.
Now, talking to the 3rd option, the CDN checks the HTTP headers to look for ETag for busting the cache.
The idea of the Server-side caching is to only call the origin server in case the asset is not found on the CDN.
Now, between 1st and 3rd, the main difference is that Service Workers works best for Slow / failing network connections and offline, since the cache is done client-side, so if the network is off, then the service worker retrieves the last cached information, allowing for a smooth user experience.
Server-side, on the other hand, only works when we are able to reach the server, but at the same time, the caching happens out of user's device, saving local space, and reducing the application memory consumption.
So as you see, there's no right / wrong answers, just what works best for your use case.
Some Sources
MDN Cache
MDN HTTP caching
Great article from web.dev
Facebook study on caching duration and efficiency
Let's answer your questions:
what is the main difference between these two approaches (caching with ETag and caching with Service Workers)
Both solutions cache files, the main difference is the need to reach the server or stay locally:
For the ETag, the browser hits the server asking for a file with a hash (the etag), depending on the file stored in the server, the server will answer with a "the file was not modified, use your local copy" with a 300 HTTP response or "here is a new version of that file" with a 200 HTTP response and a new file. In both cases the server always decides. and the user will wait for a round trip.
With the Service worker approach you can decide locally what to do. You can write some logic to control what/when to use a local copy (cached) or when go to the server. This is very useful for offline capabilities since the logic is happening in the client, and there is no need to hit the server.
when we should use one over the other?
You can use both together. You can define some logic in the service worker, if there is no connection return the local copies, otherwise go to the server.
What would be the most efficient when it comes to performance:
Server side caching and serving Angular app static files
Implementing Angular Service Worker for caching
Do both 1 and 2
My recommended approach is use both approaches. Although treat your files differently, the 'index.html' file can change, in this case use the service worker (in case there is no internet access) and if there is internet access let the web server answer with the etag. All the other static files (CSS and JS) should be immutable files, this is you can be sure the local copy is valid, in this case add a hash to the files' name (so they are always unique files) and cache them. When you have a new version of your app, you will modify the 'index.html' pointing to new immutable files.

Does the browser consult the cache automatically, if I put some files in the cache using Cache API?

If I put a file in the cache using the Cache API - from the main page, without a Service Worker - will the browser consult the cache automatically, if the request/url I use in cache.put() matches the new/subsequent request?
Or is it always necessary to use the Service Worker, if you want to serve the files that you had previously put into the cache?

JS service-worker and cache storage API with http 302 - how to cache the redirect?

I have a webpage, serverd via https from Tomcat, with serviceworker according to examples for fetching a resource and store it in the cache. If Tomcat is not running, the page is served from the cache storage - so far so good.
My Tomcat configuration contains the redirectPort attribute to redirect http to https. The problem I have: When Tomcat is not running and my webpage is accessed via http, browser shows: Connection refused since the http 302 redirect is not stored in the cache. How I could achieve that?
Unfortunately service workers require https for safety, so you cannot have a service worker intercept an http request.
If you would like to force browsers to visit your page in https you could enable HSTS:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security
The HSTS list can be preloaded in the browser allowing it to work offline. Note, however, you need to be careful when enabling HSTS as if you make a mistake it can be difficult to correct.
Alternatively browsers are slowly moving towards loading https by default unless the user explicitly types http. For example:
https://blog.chromium.org/2021/03/a-safer-default-for-navigation-https.html

Force serviceWorker update when existing "bad" serviceWorker is active and cache first

I have a problem, much like this question, which is a few years old now.
The problem I have is [a] new JS to the app code to unregister the ServiceWorker or skip-waiting is not being parsed because the app code is being served by the old ServiceWorker, and [b] I have full control of the server, but using the Clear-Site-Data: response header isn't working because all of the app's files are being served from the ServiceWorker or cache. It's never seeing that header. The only fresh requests are being made to an API on a different subdomain.
There are users out in the world using this application. What can I do to get clients with the old serviceWorker installed and running in their browser to observe new updates?
The request for the underlying service worker script file during an update check should always bypass both the HTTP cache and the existing service worker's fetch handler.
You should be able to add the Clear-Site-Data: header to the response for the underlying service worker script file returned by your web server and recover in that manner.
Additionally, you should be able to include code in the service worker script file along the lines of what's in that "kill switch" example and it will be run whenever a browser makes an update check, since again, that update check will bypass caches and go against the web server.

How to SSR on specific routes on angular-universal? [duplicate]

I used #angular/service-worker to generate SW for an angular4 web app.
after updating the ngsw-manifest.json to handle dynamic request from the server
I get "Status Code:503 OK (from ServiceWorker)" when offline (after first loading).
Any thoughts?
your problem is related with [Content Security Policy (CSP)] configuration on your web server or proxy nginx. Due you are connecting properly with nginx, the PWA offline feature is not enabled in your browser.
read more on (https://content-security-policy.com/).
The performance strategy works (you can try this strategy), the caveat being dynamic content is only cached on the second page load due to async nature of the service worker. In your ngsw-config.json:
"cacheConfig": {
"strategy": "performance",
"maxSize": 100,
"maxAge": "3d"
}
By default, files that are fetched at runtime are not cached, but by creating a dynamic cache group, matching files that are fetched by the Service Worker will also be cached. Choosing optimizeFor setting of performance will always serve from the cache first, and then attempt to cache any updates. Choosing freshness means that the Service Worker will attempt to access the file via the network, and if the network fails, then it will serve the cached copy.

Categories