Reputation: 107
I noticed that the fetch event of a service worker is no longer triggered when the service worker script itself is loaded in the browser. For example, when we have a new version of a service worker, the old service workers fetch event is not triggered. As consequence, the old service worker can no longer check the content of the new service worker.
I'm sure this was possible before and I would like to know if this is a bug or if any changes were made regarding to that. I did not find anything in the official repository or W3C draft regarding to this change.
To verify that the fetch event is not triggered I programmed a small example service worker with a version number (see code). I have tested it the following way:
Example 'sw.js':
const version = 1;
console.log(`SW with v${version} executed`);
async function onFetch(event) {
// Not triggered for sw.js
console.log(`fetching: ${event.request.url} with v${version}`);
return await fetch(event.request);
}
async function onInstall() {
console.log(`sw v${version} install`);
await self.skipWaiting();
}
async function onActivate() {
console.log(`sw v${version} activate`);
await self.clients.claim();
}
self.addEventListener('fetch', event => event.respondWith(onFetch(event)));
self.addEventListener('install', event => event.waitUntil(onInstall()));
self.addEventListener('activate', event => event.waitUntil(onActivate()));
As we can see from the logs, the sw.js file was not fetched, but another fiel (test.js) was fetched before the new service worker was installed. I included the test.js javascript file to see if the service worker was fetching anything. So from this test we can see that the fetch event is not triggered for service worker script itself.
What I would like to know is, is there any way to fetch the new service worker javascript file before it gets loaded within the old service worker? Are there any other events that make this possible? I do not need to intercept the script from executing or replacing the old service worker. I just want to check the content of the new service worker before it is loaded.
EDIT:
<html>
<body>
<h1>hello</h1>
<script src="test.js"></script>
<button onclick="runFetch()">fetch</button>
<h2 id="swVersion"></h2>
<script>
navigator.serviceWorker.register('/sw.js'); // First Installation
fetch('/sw.js'); // Triggers fetch event, but is independent from update routine.
async function runFetch() {
console.log(await fetch('/sw.js'));
}
</script>
</body>
</html>
Upvotes: 0
Views: 2965
Reputation: 56044
The service worker update check that is initiated by the browser always bypasses all service worker fetch
handlers. It might end up being fulfilled by the HTTP Cache, although all modern browsers default to also bypassing the HTTP Cache and going straight to the network.
I'm fairly confident that no browser has ever triggered the previous service worker's fetch
event handler when performing the service worker update check, as that's explicitly forbidden by the service worker specification (the service-workers mode of the update request is required to be set to 'none'
). This helps developers avoid scenarios in which an old service worker could get "stuck" if it did something incorrect when processing the fetch
event for a new service worker.
I'm not sure why you might have thought otherwise—perhaps you are thinking about the HTTP Cache interaction. Or perhaps you're thinking about a scenario in which a web app explicitly calls fetch('service-worker.js')
to check to see if a service worker exists at a given URL, which will trigger the fetch
handler of the service worker in control of a given page. But calling fetch('service-worker.js')
is very different from the service worker update check.
Upvotes: 1