I have been working on pwa project and i opened two cache
one is static-cache and another one is dynamic-cache i am able to delete one cache at a time by using this code
self.addEventListener('activate', event => {
console.log('Activating new service worker...');
const cacheWhitelist = [staticCacheName];
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.map(cacheName => {
if (cacheWhitelist.indexOf(cacheName) === -1) {
return caches.delete(cacheName);
}
})
);
})
);
});
i want to delete both caches at same time
Your code looks already good. In my case, I use the following code to delete the SW caches:
if ('caches' in window) {
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.filter(cacheName => {
// You can have some custom logic here, if you want
// to delete only some caches
// If you return TRUE, the cache will be deleted
}).map(cacheName => {
return caches.delete(cacheName);
})
);
})
}
The caches.keys() method returns the keys of the CacheStorage, an interface representing the storage for the Cache objects that can be accessed by the service worker.
I wrote an article about service workers and caching strategies, if you want to deepen the topic.
Not an expert but I think using filter like this will work.
cacheNames.filter(cacheName => {
if (cacheWhitelist.indexOf(cacheName) === -1) {
return caches.delete(cacheName);
}
try this:
self.addEventListener( "activate", event => {
event.waitUntil(
//wholesale purge of previous version caches
caches.keys().then( cacheNames => {
cacheNames.forEach( value => {
caches.delete( value );
} );
} );
} );
Related
My service worker is not rendering the offline.html page that I have created. It's just showing the real web page before clearing cache. After clearing cache it is showing the usual connection lost page in offline mode instead of showing the offline.html page I have created. I have unregistered it one time. That's the reason for it. I'm attaching the screenshot of serviceworker.js file here: serviceworker.js.
It is a react app I converted to PWA.
Here is my serviceworker.js:
const CACHE_NAME = "version-1";
const urlsToCache = ["index.html", "offline.html"];
const self = this;
//installing SW
self.addEventListener("install", event => {
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => {
console.log("Opened Cache")
return cache.addAll(urlsToCache)
})
)
})
//fetching request
self.addEventListener("fetch", event => {
event.respondWith(
caches.match(event.request)
.then(() => {
return fetch(event.request)
.catch(() => caches.match("offline.html"))
})
)
})
//activating SW
self.addEventListener("activate", event => {
const cacheWhiteList = [];
cacheWhiteList.push(CACHE_NAME)
event.waitUntil(
caches.keys()
.then(cacheNames => Promise.all(
cacheNames.map(cacheName => {
if (!-cacheWhiteList.includes(cacheName)) {
return caches.delete(cacheName)
}
})
))
)
})
When I try to access http://localhost/visites/ it should fetch the precached file visites/index.php . So I guess I have to indicate somewhere that this particular route matches that file, do you have any idea on how I can do that?
I leave my SW code here just in case:
const cacheName = 'v1';
const cacheAssets = [
'accueil.php',
'js/accueil.js',
'visites/index.php',
'js/visites.js',
'js/global.js',
'css/styles.css',
'charte/PICTOS/BTN-Visites.png',
'charte/STRUCTURE/GESTEL-Logo.png',
'charte/PICTOS/BTN-Animaux.png',
'charte/PICTOS/BTN-Deconnexion.png',
'charte/PICTOS/BTN-Fermes.png',
];
// Call Install Event
self.addEventListener('install', e => {
console.log('Service Worker: Installed');
e.waitUntil(
caches
.open(cacheName)
.then(cache => {
console.log('Service Worker: Caching Files');
cache.addAll(cacheAssets);
})
.then(() => self.skipWaiting())
);
});
// Call Activate Event
self.addEventListener('activate', e => {
console.log('Service Worker: Activated');
// Remove unwanted caches
e.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.map(cache => {
if (cache !== cacheName) {
console.log('Service Worker: Clearing Old Cache');
return caches.delete(cache);
}
})
);
})
);
});
// Call Fetch Event
self.addEventListener('fetch', e => {
console.log('Service Worker: Fetching');
e.respondWith(fetch(e.request).catch(() => caches.match(e.request)));
})
You can include some logic in your fetch handler that accounts for this routing information:
self.addEventListener('fetch', e => {
// Use a URL object to simplify checking the path.
const url = new URL(e.request.url);
// Alternatively, check e.request.mode === 'navigate' if
// you want to match a navigation to any URL on your site.
if (url.pathname === '/visites/') {
e.respondWith(caches.match('visites/index.php'));
// Return after responding, so that the existing
// logic doesn't get triggered.
return;
}
e.respondWith(fetch(e.request).catch(() => caches.match(e.request)));
});
I have migrated my existing website to PWA.
My website is very simple made using HTML, JQuery and javascript.
Previously the caching mechanism was dependent on manifest.appcache.
Now when I try to cache the files using service worker none of the file are getting cached.
I have checked my service worker is registered and everything seems fine but files are not getting stored in cache.
I tried clearing the cache but no help.
I am sharing my service worker code below since it is production code I can not share all file names.
I used this site to learn PWA.
const staticCacheName = 'site-static-v4';
const dynamicCacheName = 'site-dynamic-v4';
const assets = [
"index.shtml",
"fallback.html",
"manifest.webmanifest"
];
// cache size limit function
const limitCacheSize = (name, size) => {
caches.open(name).then(cache => {
cache.keys().then(keys => {
if(keys.length > size){
cache.delete(keys[0]).then(limitCacheSize(name, size));
}
});
});
};
// install event
self.addEventListener('install', evt => {
//console.log('service worker installed');
evt.waitUntil(
caches.open(staticCacheName).then((cache) => {
console.log('caching shell assets');
cache.addAll(assets);
})
);
});
// activate event
self.addEventListener('activate', evt => {
//console.log('service worker activated');
evt.waitUntil(
caches.keys().then(keys => {
//console.log(keys);
return Promise.all(keys
.filter(key => key !== staticCacheName && key !== dynamicCacheName)
.map(key => caches.delete(key))
);
})
);
});
// fetch event
self.addEventListener('fetch', evt => {
//console.log('fetch event', evt);
evt.respondWith(
caches.match(evt.request).then(cacheRes => {
return cacheRes || fetch(evt.request).then(fetchRes => {
return caches.open(dynamicCacheName).then(cache => {
cache.put(evt.request.url, fetchRes.clone());
// check cached items size
limitCacheSize(dynamicCacheName, 15);
return fetchRes;
})
});
}).catch(() => {
if(evt.request.url.indexOf('.html') > -1){
return caches.match('fallback.html');
}
})
);
});
Below is the screenshot of my empty cache storage.
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.
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);
});
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);
})
);
})
);
});
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()
})
})
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);
}
})
})()
)
})
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
});
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.
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);
});
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);
})
);
})
);
});
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()
})
})
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);
}
})
})()
)
})
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
});