Skip to content

Commit 6b45985

Browse files
maiieulgioboa
andauthored
fix(qwik-city): custom service-worker.ts code is also being unregistered (#7872)
* fix: custom service-worker.ts code is also being unregistered * chore: changeset * fix: clientOutDir type issue * Update .changeset/thin-horses-bake.md Co-authored-by: Giorgio Boa <[email protected]> * fix: also unregister when service-worker.ts is removed and delete cache in any case * refactor: only check if service-worker.ts is removed to unregister --------- Co-authored-by: Giorgio Boa <[email protected]>
1 parent 4d4e0aa commit 6b45985

File tree

5 files changed

+63
-34
lines changed

5 files changed

+63
-34
lines changed

.changeset/thin-horses-bake.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@builder.io/qwik-city': patch
3+
---
4+
5+
FIX: Your service-worker.js won't be unregistered anymore if you added custom logic to it.
6+
7+
> Note: Qwik 1.14.0 and above now use `<link rel="modulepreload">` by default. If you didn't add custom service-worker logic, you should remove your service-worker.ts file(s) for the `ServiceWorkerRegister` Component to actually unregister the service-worker.js and delete its related cache. Make sure to keep the `ServiceWorkerRegister` Component in your app (without any service-worker.ts file) as long as you want to unregister the service-worker.js for your users.

packages/qwik-city/src/buildtime/runtime-generation/generate-service-worker.ts

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,48 @@ import type { BuildContext } from '../types';
22

33
export function generateServiceWorkerRegister(ctx: BuildContext, swRegister: string) {
44
let swReg: string;
5+
let swUrl = '/service-worker.js';
56

6-
if (ctx.isDevServer) {
7+
// Also unregister if the developer removed the service-worker.ts file since Qwik 1.14.0 and above now use modulepreload by default
8+
if (ctx.isDevServer || ctx.serviceWorkers.length === 0) {
79
swReg = SW_UNREGISTER;
810
} else {
911
swReg = swRegister;
1012

11-
let swUrl = '/service-worker.js';
12-
if (ctx.serviceWorkers.length > 0) {
13-
const sw = ctx.serviceWorkers.sort((a, b) =>
14-
a.chunkFileName.length < b.chunkFileName.length ? -1 : 1
15-
)[0];
16-
swUrl = ctx.opts.basePathname + sw.chunkFileName;
17-
}
18-
19-
swReg = swReg.replace('__url', swUrl);
13+
const sw = ctx.serviceWorkers.sort((a, b) =>
14+
a.chunkFileName.length < b.chunkFileName.length ? -1 : 1
15+
)[0];
16+
swUrl = ctx.opts.basePathname + sw.chunkFileName;
2017
}
18+
swReg = swReg.replace('__url', swUrl);
2119

2220
return `export default ${JSON.stringify(swReg)};`;
2321
}
2422

2523
const SW_UNREGISTER = `
26-
navigator.serviceWorker?.getRegistrations().then((regs) => {
27-
for (const reg of regs) {
28-
reg.unregister();
29-
}
30-
});
24+
"serviceWorker"in navigator&&navigator.serviceWorker.getRegistrations().then(r=>{for(const e of r){const c='__url'.split("/").pop();e.active?.scriptURL.endsWith(c||"service-worker.js")&&e.unregister().catch(console.error)}}),"caches"in window&&caches.keys().then(r=>{const e=r.find(c=>c.startsWith("QwikBuild"));e&&caches.delete(e).catch(console.error)}).catch(console.error)
3125
`;
26+
// Code in SW_UNREGISTER unregisters the service worker and deletes the cache; it is the minified version of the following:
27+
// (() => {
28+
// if ('serviceWorker' in navigator) {
29+
// navigator.serviceWorker.getRegistrations().then((regs) => {
30+
// for (const reg of regs) {
31+
// const url = '__url'.split('/').pop();
32+
// if (reg.active?.scriptURL.endsWith(url || 'service-worker.js')) {
33+
// reg.unregister().catch(console.error);
34+
// }
35+
// }
36+
// });
37+
// }
38+
// if ('caches' in window) {
39+
// caches
40+
// .keys()
41+
// .then((names) => {
42+
// const cacheName = names.find((name) => name.startsWith('QwikBuild'));
43+
// if (cacheName) {
44+
// caches.delete(cacheName).catch(console.error);
45+
// }
46+
// })
47+
// .catch(console.error);
48+
// }
49+
// })();

packages/qwik-city/src/buildtime/vite/plugin.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ function qwikCityPlugin(userOpts?: QwikCityVitePluginOptions): any {
191191
}
192192
}
193193
}
194+
194195
return null;
195196
},
196197

packages/qwik-city/src/runtime/src/sw-component.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ import type { JSXOutput } from '@builder.io/qwik';
55
* JS extensions are allowed) will be picked up, bundled into a separate file, and registered as a
66
* service worker.
77
*
8+
* Qwik 1.14.0 and above now use `<link rel="modulepreload">` by default. If you didn't add custom
9+
* service-worker logic, you should remove your service-worker.ts file(s) for the
10+
* `ServiceWorkerRegister` Component to actually unregister the service-worker.js and delete its
11+
* related cache. Make sure to keep the `ServiceWorkerRegister` Component in your app (without any
12+
* service-worker.ts file) as long as you want to unregister the service-worker.js for your users.
13+
*
814
* @public
915
*/
1016
export const ServiceWorkerRegister = (props: { nonce?: string }): JSXOutput => (

packages/qwik-city/src/runtime/src/sw-register.ts

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,21 @@
22

33
(() => {
44
if ('serviceWorker' in navigator) {
5-
navigator.serviceWorker.getRegistrations().then((regs) => {
6-
for (const reg of regs) {
7-
const url = '__url'.split('/').pop();
8-
if (reg.active?.scriptURL.endsWith(url || 'service-worker.js')) {
9-
reg.unregister().catch(console.error);
10-
}
11-
}
12-
});
13-
}
14-
if ('caches' in window) {
15-
caches
16-
.keys()
17-
.then((names) => {
18-
const cacheName = names.find((name) => name.startsWith('QwikBuild'));
19-
if (cacheName) {
20-
caches.delete(cacheName).catch(console.error);
21-
}
22-
})
23-
.catch(console.error);
5+
navigator.serviceWorker.register('__url').catch((e) => console.error(e));
6+
// We need to delete the cache since we are using modulepreload by default in qwik 1.14 and above
7+
if ('caches' in window) {
8+
caches
9+
.keys()
10+
.then((names) => {
11+
const cacheName = names.find((name) => name.startsWith('QwikBuild'));
12+
if (cacheName) {
13+
caches.delete(cacheName).catch(console.error);
14+
}
15+
})
16+
.catch(console.error);
17+
}
18+
} else {
19+
// eslint-disable-next-line no-console
20+
console.log('Service worker not supported in this browser.');
2421
}
2522
})();

0 commit comments

Comments
 (0)