Service Worker's fetch event never fires - javascript

The question title says it all.
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/react-redux/sw.js').then(() => {
console.log('registered');
}, err => console.log(err));
}
EDIT
It looks like the root of the problem is the path
navigator.serviceWorker.register('/react-redux/sw.js')
if I move the sw code, so that I have
navigator.serviceWorker.register('swRoot.js').then(() => {
then everything works properly. I tried just about everything I can think of above, from dropping the leading slash in /react-redux, to adding a {scope: of './', '/', '/react-redux', and none worked (with some causing errors).
Does anyone know what config magic is needed to be able to load a service worker from somewhere other than the root of your domain?
and then my entire sw.js
self.addEventListener('install', function(event) {
console.log('hello');
try {
console.log('typeof System in install', typeof System);
} catch(e){}
console.log('caching');
event.waitUntil(
caches.open('v1').then(function(cache) {
console.log('caching - getting');
return cache.addAll([
'/react-redux/a.js'
]);
}).catch(function(error){ console.log('error', error) })
);
});
console.log('ADDING FETCH')
self.addEventListener('fetch', function(event) {
console.log('fetching ->', event.request);
event.respondWith(
caches.match(event.request)
.then(function(response) {
// Cache hit - return response
if (response) {
return response;
}
return fetch(event.request);
})
);
});
I never ever get the console.log('fetching ->', event.request); message. I even added this silliness to try to force the issue.
setTimeout(() => fetch('/react-redux/foo.css').then(r => console.log(r)), 1000);
setInterval(() => fetch('/react-redux/foo.css').then(r => console.log(r)), 5000);
I see the fetch events running, but the service worker never says it's hitting those event handlers.
Moreover, I do get notified that the SW is registered, and when I update sw.js, close and re-open, I see all the logging statements indicating that things are installing correctly.

You're on the right track, it seems to be a scoping issue.
To change the scope of a service worker, it must be done when registering, like this:
navigator.serviceWorker.register('scripts/sw.js', { scope: '/' })
Then the server must return the following header in the response to acknowledge this scope change.
Service-Worker-Allowed: /
See this answer

Attach fetch event listener within install event handler
self.addEventListener('install', function(event) {
console.log("install");
try {
console.log('typeof System in install', typeof System);
} catch (e) {}
console.log('caching');
event.waitUntil(
caches.open('v1').then(function(cache) {
console.log('caching - getting');
return cache.addAll([
'a.js'
]);
}).catch(function(error) {
console.log('error', error)
})
);
self.addEventListener('fetch', function(event) {
console.log('fetching ->', event.request);
event.respondWith(
caches.match(event.request)
.then(function(response) {
// Cache hit - return response
if (response) {
return response;
}
return fetch(event.request);
})
);
});
});
plnkr https://plnkr.co/edit/WuJCZSD0V4idG1Ra7VMb?p=preview

Getting fetch interception working seems to require that the registered
service worker be at or above the level of the tree with the HTML file
registering the worker. Below fails.
In Chrome, be sure to look at "Service Worker" under "Application".
Even registering below results in a Service Worker which is activated
and running, but when the location is at or above the HTML page, you
also get an entry listed under "Clients". The presence of this seems
to correspond exactly to when the fetch will be intercepted.

Related

Service worker install event firing before each fetch when no changes to the service worker are made

According to service worker documentation, the install event should only fire once per service worker; however, if I put a console.log inside of the install event listener, I am noticing that before a fetch occurs, the install event is always fired.
Why is the install event for the service worker getting called even when there have been no changes/updates to the SW. Does the service worker's install event get called if it goes idle for a short period of time? This is a problem as the caching is done during install, and if the install event gets called before the fetch occurs, we are updating the cache constantly when it doesn't need to be updated at all.
Thanks for the help!
const CACHE_NAME = 'my-cache-v2';
const cacheAllowList = [CACHE_NAME];
const externalFiles = [
various files here
];
self.addEventListener('fetch', function (event) {
event.respondWith(
self.caches
.match(event.request)
.then(function (response) {
if (response) {
return response;
}
return fetch(event.request);
})
);
});
self.addEventListener('install', function (event) {
// Perform install steps
event.waitUntil(
self.caches.keys().then(function (cacheNames) {
// Add cache
self.caches.open(CACHE_NAME).then((cache) => {
return cache.addAll([
...externalFiles
]);
})
.catch(error => {
console.log('Service worker cache failed: ' + error);
})
})
);
});
self.addEventListener('activate', function (event) {
// All caches not listed here will be deleted.
event.waitUntil(
self.caches.keys().then(function (cacheNames) {
return Promise.all(
cacheNames.map(function (cacheName) {
if (cacheAllowList.indexOf(cacheName) === -1) {
return self.caches.delete(cacheName);
}
})
);
})
);
});
self.addEventListener('push', function(event) {
console.log('[Service Worker] Push Received.');
console.log(`[Service Worker] Push had this data: "${event.data.text()}"`);
const title = 'Push Codelab';
const options = {
body: 'Push notifications',
icon: 'images/icon.png',
badge: 'images/badge.png'
};
event.waitUntil(self.registration.showNotification(title, options));
});
*Edit - Its important to note that this doesn't always happen. Sometimes the fetch works fine without calling install, other times install gets called for seemly no reason before the fetch occurs.

How to make service worker network first then cache

I am trying to set up pwa app. My sw.js is
var urlsToCache = [
'/danger/index.html',
'/danger/css/main.css',
'/danger/css/fontawesome-all.min.css',
'/danger/css/font.css'
];
var CACHE_NAME = 'progressive';
self.addEventListener('install', function (event) {
event.waitUntil(
caches.open(CACHE_NAME)
.then(function (cache) {
return cache.addAll(urlsToCache);
})
);
});
self.addEventListener('fetch', function (event) {
event.respondWith(
caches.open(CACHE_NAME).then(function (cache) {
return cache.match(event.request).then(function (response) {
return response || fetch(event.request).then(function (response) {
cache.put(event.request, response.clone());
return response;
});
});
})
);
});
self.addEventListener('fetch', function (event) {
event.respondWith(
caches.open(CACHE_NAME).then(function (cache) {
return fetch(event.request).then(function (response) {
cache.put(event.request, response.clone());
return response;
});
})
);
});
I want to make sw check for first network, then cache. I got a code from net.
self.addEventListener('fetch', (event) => {
event.respondWith(async function() {
try {
return await fetch(event.request);
} catch (err) {
return caches.match(event.request);
}
}());
});
How to implement it in my sw.js. I asked it because my app not updating the website content in network enabled mode also.
Browser will always reach out to network first and get the service-worker.js I would suggest you to use Workbox instead of manually writing all these code.
Workbox documentation
We should not cache service-worker file as that is a source of truth for browser to know whether any other files have changed. Usually a service-worker file will have a series of files that are cached along with their hashes. When service worker file changes, then browser knows that it needs to take update from server.
Thanks

Service worker returning correct response but still getting 'no internet' error

I am trying to setup a service worker so that my web-app can fully work offline. When I inspect the cache for static-v2 all of my assets that I want are there.
When I make a request and am online my SW is correctly doing the fetch and not falling into my catch statement.
However, when I am offline and I fall through to my cache the correct response is logged with the status of 200 but I get the chrome 'no internet' error.
Another interesting point is even when I comment out the line where I return the cache response and just return the hard coded response I still get the 'no internet' error.
Any help in figuring out why my service worker isn't working as expected would be greatly appreciated.
const CACHENAME = `static-v2`;
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open(CACHENAME).then(function(cache) {
return cache
.addAll([
// your list of cache keys to store in cache
'bundle.js',
'index.html',
'manifest.json',
// etc.
])
.then(() => {
return self.skipWaiting();
});
}),
);
});
self.onactivate = (evt) => {
console.log(`on activate - ${CACHENAME}`);
evt.waitUntil(
caches.keys().then((cacheNames) => {
const deleteOldCaches = cacheNames.map((cacheName) => {
console.log(cacheName);
if (cacheName != CACHENAME) {
return caches.delete(cacheName);
}
return Promise.resolve();
});
return Promise.all(deleteOldCaches);
}),
);
self.clients.claim();
};
self.onfetch = (evt) => {
evt.waitUntil(
fetch(evt.request).catch((err) => {
caches.match(evt.request).then((response) => {
console.log(evt.request.url, response);
if (response) return response;
return new Response('<div><h2>Uh oh that did not work</h2></div>', {
headers: {
'Content-type': 'text/html',
},
});
});
}),
);
console.log(`on fetch - ${CACHENAME}`);
};
I am hosting all of my assets (inc SW) using http-server (https://www.npmjs.com/package/http-server)
It's a simple mistake.
In your fetch event handler, you should NOT call evt.waitUntil. You should call evt.respondWith.

Service Worker fetch event is not being triggered

self.addEventListener('install', function (event) {
console.log('SW Installed');
event.waitUntil(
caches.open('static')
.then(function (cache) {
cache.addAll([
'/',
'/static/js/renderjson.js',
"/static/css/app.css",
'/static/js/contribute.js',
"http://pending.biothings.io/denovodb/metadata",
"http://pending.biothings.io/ccle/metadata",
"http://pending.biothings.io/kaviar/metadata",
"http://pending.biothings.io/biomuta/metadata",
"http://pending.biothings.io/fire/metadata",
]);
})
);
});
self.addEventListener('activate', function () {
console.log('SW Activated');
});
self.addEventListener('fetch', function(event) {
console.log('FETCH',event.request);
event.respondWith(
caches.match(event.request)
.then(function(response) {
if (response) {
// retrieve from cache
console.log('Found ', event.request.url, ' in cache');
return response;
}
// if not found in cache, return default offline content (only if this is a navigation request)
if (event.request.mode === 'navigate') {
return caches.match('/');
}
// fetch as normal
console.log('Network request for ', event.request.url);
return fetch(event.request);
})
);
});
I'm new to PWA's so bear with me, I'm running a tornado server here is the registration:
if ('serviceWorker' in navigator) {
// Use the window load event to keep the page load performant
window.addEventListener('load', () => {
navigator.serviceWorker.register('/static/js/worker.js');
console.log('Service Worker registered');
});
}
I put a few console logs to see if the fetch event was being triggered but nothing seems to be happening, when I check the offline box on the Application tab and refresh the app does not work offline. All the assets are cached correctly and verified they are there. Looks like the last bit is just making the Worker server the right cached files.
For my case specifically, our site just needed to use https for the worker to activate properly. after doing that the listeners worked perfectly. I would recommend using Workbox, a lot easier!

Service worker won't install when I try to cache xxx.worker.js

I have the following service worker code in my Vue app:
main.js
if (navigator.serviceWorker) {
navigator.serviceWorker.register('/service-worker.js').catch(function() {
console.log('Service worker registration failed.');
});
}
service-worker.js
let currCacheName = 'premium-poker-tools-5';
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open(currCacheName).then(function(cache) {
let promise = cache.addAll([
'/',
'app.js',
'c7d016677eb7e912bc40.worker.js',
'f328c7e2b379df12fa4c.worker.js',
'static/logo.png',
'static/favicon.png',
'static/loading.svg',
'static/cards/ace-of-clubs.png',
'static/cards/king-of-clubs.png',
'static/cards/queen-of-clubs.png',
'static/cards/jack-of-clubs.png',
'static/cards/ten-of-clubs.png',
'static/cards/nine-of-clubs.png',
'static/cards/eight-of-clubs.png',
'static/cards/seven-of-clubs.png',
'static/cards/six-of-clubs.png',
'static/cards/five-of-clubs.png',
'static/cards/four-of-clubs.png',
'static/cards/three-of-clubs.png',
'static/cards/two-of-clubs.png',
'static/cards/ace-of-spades.png',
'static/cards/king-of-spades.png',
'static/cards/queen-of-spades.png',
'static/cards/jack-of-spades.png',
'static/cards/ten-of-spades.png',
'static/cards/nine-of-spades.png',
'static/cards/eight-of-spades.png',
'static/cards/seven-of-spades.png',
'static/cards/six-of-spades.png',
'static/cards/five-of-spades.png',
'static/cards/four-of-spades.png',
'static/cards/three-of-spades.png',
'static/cards/two-of-spades.png',
'static/cards/ace-of-hearts.png',
'static/cards/king-of-hearts.png',
'static/cards/queen-of-hearts.png',
'static/cards/jack-of-hearts.png',
'static/cards/ten-of-hearts.png',
'static/cards/nine-of-hearts.png',
'static/cards/eight-of-hearts.png',
'static/cards/seven-of-hearts.png',
'static/cards/six-of-hearts.png',
'static/cards/five-of-hearts.png',
'static/cards/four-of-hearts.png',
'static/cards/three-of-hearts.png',
'static/cards/two-of-hearts.png',
'static/cards/ace-of-diamonds.png',
'static/cards/king-of-diamonds.png',
'static/cards/queen-of-diamonds.png',
'static/cards/jack-of-diamonds.png',
'static/cards/ten-of-diamonds.png',
'static/cards/nine-of-diamonds.png',
'static/cards/eight-of-diamonds.png',
'static/cards/seven-of-diamonds.png',
'static/cards/six-of-diamonds.png',
'static/cards/five-of-diamonds.png',
'static/cards/four-of-diamonds.png',
'static/cards/three-of-diamonds.png',
'static/cards/two-of-diamonds.png',
'static/feedback/1.png',
'static/feedback/2.png',
'static/feedback/3.png',
'static/feedback/4.png',
'static/feedback/flop-selector.png',
'static/feedback/green-grid-squares.png',
'static/feedback/user-set-range-to-simulate-to-street.png',
'static/guides/beginners-guide/1.png',
'static/guides/beginners-guide/2.png',
'static/guides/beginners-guide/3.png',
'static/guides/beginners-guide/4.png',
'static/guides/beginners-guide/5.png',
'static/guides/beginners-guide/6.png',
'static/guides/beginners-guide/7.png',
'static/guides/beginners-guide/8.png',
'static/guides/beginners-guide/9.png',
'static/guides/beginners-guide/10.png',
'static/guides/beginners-guide/11.png',
'static/guides/beginners-guide/12.png',
'static/guides/beginners-guide/13.png',
'static/guides/beginners-guide/14.png',
'static/guides/beginners-guide/15.png',
'static/guides/beginners-guide/16.png',
'static/guides/beginners-guide/17.png',
'static/guides/beginners-guide/18.png',
'static/guides/beginners-guide/19.png',
'static/guides/beginners-guide/20.png',
'static/guides/beginners-guide/21.png',
'static/guides/faq/double-counting/1.png',
'static/guides/faq/hit-percentage-calculation/1.png',
'static/guides/faq/hit-percentage-calculation/2.png',
'static/guides/faq/hit-percentage-calculation/3.png',
'static/guides/faq/insights/1.png',
'static/guides/faq/insights/2.png',
'static/guides/faq/insights/3.png',
'static/guides/faq/insights/4.png',
'static/guides/faq/insights/5.png',
'static/guides/faq/insights/6.png',
'static/guides/faq/insights/7.png',
'static/guides/faq/insights/8.png',
'static/guides/faq/set-checks-to-default/1.png',
'static/guides/quick-guide/1.png',
'static/guides/quick-guide/2.png',
'static/guides/quick-guide/3.png',
'static/guides/quick-guide/4.png',
'static/guides/quick-guide/5.png',
'static/guides/quick-guide/6.png',
'static/guides/quick-guide/7.png',
'static/guides/quick-guide/8.png',
'static/guides/quick-guide/save-load-scenario.png',
'static/home/1.png',
'static/home/2.png',
'static/home/3.png',
'static/settings/equity-calculator-insights-not-visible.png',
'static/settings/equity-calculator-insights-visible.png',
'static/settings/outcome-analyzer-checkboxes-collapsed-1.png',
'static/settings/outcome-analyzer-checkboxes-collapsed-2.png',
'static/settings/outcome-analyzer-checkboxes-included-1.png',
'static/settings/outcome-analyzer-checkboxes-included-2.png',
'static/settings/outcome-analyzer-hands.png',
'static/settings/outcome-analyzer-insights-not-visible.png',
'static/settings/outcome-analyzer-insights-visible.png',
'static/settings/saved-ranges-1.png',
'static/settings/saved-ranges-2.png',
'static/settings/saved-ranges-3.png',
'static/settings/saved-ranges-4.png',
'static/settings/included-selectors/double-slider-selector.png',
'static/settings/included-selectors/log-double-slider-selector.png',
'static/settings/included-selectors/saved-ranges-selector.png',
'static/settings/included-selectors/single-slider-selector.png',
'static/settings/included-selectors/tier-and-category-selector.png',
'static/settings/tiers/tiers.png',
'static/settings/visual/dont-show-num-combos-in-range.png',
'static/settings/visual/green-grid-squares.png',
'static/settings/visual/multicolored-grid-squares.png',
'static/settings/visual/show-num-combos-in-range.png',
]).then(function () {
console.log('Successfully cached everything.')
}).catch(function (error) {
console.log('Problem caching: ', error);
});
return promise;
}).catch(function () {
console.error('Error with caches.open or cache.addAll');
})
);
});
self.addEventListener('activate', function(event) {
event.waitUntil(
caches.keys()
.then(function getOldCachesThatBeginWithPremiumPokerToolsDash (cacheNames) {
return cacheNames.filter(function (cacheName) {
return cacheName.startsWith('premium-poker-tools-') && (cacheName !== currCacheName);
});
})
.then(function removeOldCachesThatBeginWithPremiumPokerToolsDash (oldCachesThatBeginWithPremiumPokerToolsDash) {
let removeCachePromises = [];
oldCachesThatBeginWithPremiumPokerToolsDash.forEach(function (oldCacheThatBeginsWithPremiumPokerToolsDash) {
removeCachePromises.push(caches.delete(oldCacheThatBeginsWithPremiumPokerToolsDash));
});
return Promise.all(removeCachePromises);
})
);
});
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.match(event.request).then(function (response) {
if (response) {
return response;
}
return fetch(event.request);
}).catch(function () {
console.error('Error trying to match event request to cache.');
})
);
});
When I comment out 'c7d016677eb7e912bc40.worker.js' and 'f328c7e2b379df12fa4c.worker.js', it works fine. But when I uncomment them, here's what happens:
I start off going to the Dev Tools and unregistering any service workers and deleting anything in Cache Storage so that I start off with a clean slate.
I load localhost:8080.
The service worker stays in the installing state.
In Cache Storage, I see that c7d016677eb7e912bc40.worker.js and f328c7e2b379df12fa4c.worker.js have been successfully cached.
However, "Successfully cached everything." isn't being logged to the console. But "Problem caching: " isn't being logged either.
I understand that the promise you pass to event.waitUntil() lets the browser know when your install completes, and if it was successful. So clearly there is some issue going on with the promise. But I don't know what the issue is. It's not hitting the .then block or the .catch block, and when I look at Cache Storage in the Dev Tools, it appears that 'c7d016677eb7e912bc40.worker.js' and 'f328c7e2b379df12fa4c.worker.js' are being successfully cached.
Edit: I am using worker-loader. I get the feeling that the issue is related to how the worker files are loaded, but I don't see why there would be a problem, because when I go to localhost:8080/c7d016677eb7e912bc40.worker.js or localhost:8080/f328c7e2b379df12fa4c.worker.js, I get back the JS file.
Also, I have made sure that prefixes in c7d016677eb7e912bc40.worker.js and f328c7e2b379df12fa4c.worker.js are accurate. Eg. that c7d016677eb7e912bc40 and f328c7e2b379df12fa4c are accurate.
Update:
This doesn't work how you think it does:
caches.open(currCacheName).then(function(cache) {
let promise = cache.addAll([
You are defining a variable called promise here, but it doesn't replace cache, which is the promise which needs to be fulfilled.
You have a load of assets to cache and then:
'static/settings/visual/show-num-combos-in-range.png',
]).then(function () {
console.log('Successfully cached everything.')
}).catch(function (error) {
console.log('Problem caching: ', error);
});
You don't return anything here, so .then won't run, but it's not an error, so .catch won't either.
Your cache gets populated, but your promise for extendableEvent.waitUntil() is never settled, so installation never completes.
Either scrap your promise variable / console.logs and return the cache.addAll like this:
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open(currCacheName).then(function(cache) {
return cache.addAll([
'/',
'app.js',
'static/settings/visual/show-num-combos-in-range.png',
])
})
);
});
Or make your function async, like this:
self.addEventListener('install', event => {
event.waitUntil(async function() {
const cache = await caches.open(currCacheName);
await cache.addAll([
'/',
'app.js',
'static/settings/visual/show-num-combos-in-range.png',
]);
}());
});

Categories