79

So, I have an HTML page with service worker, the service worker cache the index.html and my JS files.

The problem is when I change the JS, the change doesn't show up directly on the client browser. Of course in chrome dev-tools, I can disable cache. But in chrome mobile, how do I do that?

I tried to access the site settings and hit the CLEAR % RESET button. But it still loads the old page/load from cache. I tried to use other browser or chrome incognito and it loads the new page.

Then, I try to clear my browsing data (just cache) and it works.

I guess that's not how it should work right? my user won't know if the page is updated without clearing the chrome browser cache.

Amr Eladawy
  • 4,193
  • 7
  • 34
  • 52
taek
  • 1,009
  • 3
  • 11
  • 14
  • Thanks very much Hashbrown. I use this way to update my application with custom check system I was explain in this page: https://stackoverflow.com/questions/56972246/how-to-update-reactjs-based-pwa-to-the-new-version/56984209#56984209 – Abbas Habibnejad Dec 01 '19 at 08:43

6 Answers6

122

If you know the cache name you can simply call caches.delete() from anywhere you like in the worker:

caches.delete(/*name*/);

And if you wanted to wipe all caches (and not wait for them, say this is a background task) you only need to add this:

caches.keys().then(function(names) {
    for (let name of names)
        caches.delete(name);
});
Hashbrown
  • 12,091
  • 8
  • 72
  • 95
  • 2
    Thanks for this. It is a lot simpler a clearer. I just wrote mine up quickly to answer the question – liam Oct 08 '17 at 18:06
  • 2
    Nah no worries. Yours would be perfect if someone wanted to delete a specific set of caches within the `activate` listener; I just did this in case someone only wanted to dump one/everything – Hashbrown Oct 08 '17 at 23:04
  • 4
    The most compact code is probably `caches.keys().then(cs=>cs.forEach(c=>caches.delete(c)))` or for async functions `(await caches.keys()).forEach(c=>caches.delete(c))` – Pat Mächler Oct 26 '17 at 12:03
  • where I live, You Mr. will be regarded a Mustache ! ( a compliment ) – Khaledonia Jan 04 '18 at 13:58
  • 1
    Note! You should check if `caches` exists. If you want to clear caches outside of the Service Worker check add something like `if (!window.caches) return;`. Also not that `caches` object might not exist on HTTP (e.g. in Chrome). – Nux Apr 20 '18 at 15:00
  • @Hashbrown - Is there a way to accomplish this using Workbox's GenerateSW()? For my purposes, reseting all caches on publish of a new service worker would be ideal. – Adam Youngers May 01 '21 at 19:05
45

Use this to delete outdated caches:

self.addEventListener('activate', function(event) {
  event.waitUntil(
    caches.keys().then(function(cacheNames) {
      return Promise.all(
        cacheNames.filter(function(cacheName) {
          // Return true if you want to remove this cache,
          // but remember that caches are shared across
          // the whole origin
        }).map(function(cacheName) {
          return caches.delete(cacheName);
        })
      );
    })
  );
});
liam
  • 1,918
  • 3
  • 22
  • 28
16

Typically you update the CACHE_NAME in your service workers JS file so your worker installs again:

self.addEventListener('install', evt => {
  evt.waitUntil(
    caches.open(CACHE_NAME).then(cache => cache.addAll(inputs))
  )
})

Alternatively, to clear the cache for a PWA find the cache name:

self.caches.keys().then(keys => { keys.forEach(key => console.log(key)) })

then run the following to delete it:

self.caches.delete('my-site-cache')

Then refresh the page.

If you see any worker-related errors in the console after refreshing, you may also need to unregister the registered workers:

navigator.serviceWorker.getRegistrations()
  .then(registrations => {
    registrations.forEach(registration => {
      registration.unregister()
    }) 
  })
vhs
  • 9,316
  • 3
  • 66
  • 70
7

The most elegant solution, with async/await:

const cacheName = 'v2';

self.addEventListener('activate', event => {
// Remove old caches
  event.waitUntil(
    (async () => {
      const keys = await caches.keys();
      return keys.map(async (cache) => {
        if(cache !== cacheName) {
          console.log('Service Worker: Removing old cache: '+cache);
          return await caches.delete(cache);
        }
      })
    })()
  )
})
Esteban Ortega
  • 155
  • 1
  • 8
  • The service worker is installed in your browser. Your browser will request your remote worker every time (if online) and update its locally installed version for offline use. You can see which files get cached by printing it to console, i.e. console.log('Caching:', event.request.url) in your 'fetch' event after cache.put() – Esteban Ortega Apr 27 '21 at 17:57
1

This is the only code that worked for me. It is my adaptation of Mozilla documentation :

//Delete all caches and keep only one
const cachNameToKeep = 'myCache';

//Deletion should only occur at the activate event
self.addEventListener('activate', event => {
    var cacheKeeplist = [cacheName];
    event.waitUntil(
        caches.keys().then( keyList => {
            return Promise.all(keyList.map( key => {
                if (cacheKeeplist.indexOf(key) === -1) {
                    return caches.delete(key);
                }
            }));
        })
.then(self.clients.claim())); //this line is important in some contexts
});
Shadi Alnamrouti
  • 11,796
  • 4
  • 56
  • 54
  • 4
    `cacheNameToKeep` ?? `[cacheName]` ?? Are those both the same thing? What does `self.clients.claim()` do? – zipzit Oct 31 '19 at 17:51
  • After activation, the service worker will now control pages, but only those that were opened after the register() is successful. In other words, documents will have to be reloaded to actually be controlled, because a document starts life with or without a service worker and maintains that for its lifetime. To override this default behavior and adopt open pages, a service worker can call `self.clients.claim()` – Emeka Augustine Jul 19 '23 at 08:06
0

I was so disperate until I decided to change the code in devtools directly.
This may not clear the cache and replace the file, but at least, it will let you debug the code until you find the perfect way to do that.
Another notice is that closing browser entirly and reopeing your page may help, but this is still a bad practice for debugging!

Tariq
  • 2,853
  • 3
  • 22
  • 29