Skip to content

Commit 5f0d46c

Browse files
committed
upgraded pwa config to be prompt-based (instead of autoUpdate) + located every pwa config into a dedicated PwaReloadPrompt component
1 parent 9b9e79c commit 5f0d46c

File tree

5 files changed

+105
-12
lines changed

5 files changed

+105
-12
lines changed

mobile/src/App.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
<ion-app>
33
<ion-router-outlet />
44
</ion-app>
5+
<pwa-reload-prompt />
56
</template>
67

78
<script setup lang="ts">
89
import { IonApp, IonRouterOutlet } from '@ionic/vue';
10+
import PwaReloadPrompt from "@/components/PwaReloadPrompt.vue";
911
</script>
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<template>
2+
</template>
3+
4+
<script setup lang="ts">
5+
import { useRegisterSW } from 'virtual:pwa-register/vue'
6+
import { pwaInfo } from 'virtual:pwa-info'
7+
import {toastController} from "@ionic/vue";
8+
import {watch} from "vue";
9+
import {reload} from "ionicons/icons";
10+
11+
console.log(pwaInfo)
12+
13+
const {
14+
offlineReady,
15+
needRefresh,
16+
updateServiceWorker,
17+
} = useRegisterSW({
18+
immediate: true,
19+
onRegisteredSW(swUrl, r) {
20+
// eslint-disable-next-line no-console
21+
console.log(`Service Worker at: ${swUrl}`)
22+
23+
r && setInterval(async () => {
24+
// eslint-disable-next-line no-console
25+
console.debug('Checking for sw update...')
26+
await r.update()
27+
}, 60000)
28+
},
29+
})
30+
31+
watch([needRefresh], async ([_needRefresh]) => {
32+
if(_needRefresh) {
33+
const toast = await toastController.create({
34+
message: 'New content available, click on reload button to update.',
35+
duration: undefined,
36+
position: 'top',
37+
buttons: [{
38+
text: 'Reload',
39+
side: 'end',
40+
icon: reload,
41+
role: 'reload',
42+
handler: updateServiceWorker,
43+
}],
44+
color: 'primary'
45+
})
46+
await toast.present()
47+
}
48+
})
49+
50+
const close = async () => {
51+
offlineReady.value = false
52+
needRefresh.value = false
53+
}
54+
</script>
55+
56+
<style lang="scss" scoped>
57+
</style>

mobile/src/sw.ts

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,35 @@
1-
import {registerRoute, Route, setDefaultHandler} from 'workbox-routing';
2-
import {NetworkOnly, StaleWhileRevalidate} from 'workbox-strategies';
1+
import {
2+
NavigationRoute,
3+
registerRoute,
4+
Route,
5+
setCatchHandler,
6+
setDefaultHandler
7+
} from 'workbox-routing';
8+
import {NetworkOnly, StaleWhileRevalidate, Strategy, StrategyHandler} from 'workbox-strategies';
39
import { ExpirationPlugin } from 'workbox-expiration';
4-
import {clientsClaim} from "workbox-core";
5-
import {cleanupOutdatedCaches, precacheAndRoute} from "workbox-precaching";
10+
import {cleanupOutdatedCaches, createHandlerBoundToURL, precacheAndRoute} from "workbox-precaching";
611

712
declare let self: ServiceWorkerGlobalScope & {__WB_DISABLE_DEV_LOGS?: boolean}
813

14+
self.addEventListener('message', (event) => {
15+
if (event.data && event.data.type === 'SKIP_WAITING') {
16+
self.skipWaiting()
17+
}
18+
})
19+
920

1021
// TODO: comment this line if you want to debug workbox (very verbose!) logs in the console
1122
self.__WB_DISABLE_DEV_LOGS = true
1223

13-
cleanupOutdatedCaches()
1424
const wbManifest = self.__WB_MANIFEST
1525
precacheAndRoute(wbManifest);
1626

17-
setDefaultHandler(new NetworkOnly())
27+
cleanupOutdatedCaches()
28+
29+
// To allow working offline
30+
registerRoute(new NavigationRoute(
31+
createHandlerBoundToURL('index.html')
32+
))
1833

1934
// A new route that matches same-origin image requests and handles
2035
// them with the cache-first, falling back to network strategy:
@@ -32,7 +47,20 @@ const imageRoute = new Route(({ request, sameOrigin }) => {
3247
// Register the new route
3348
registerRoute(imageRoute);
3449

35-
// this is necessary, since the new service worker will keep on skipWaiting state
36-
// and then, caches will not be cleared since it is not activated
37-
self.skipWaiting()
38-
clientsClaim()
50+
setDefaultHandler(new NetworkOnly())
51+
setCatchHandler(async (event) => {
52+
const headers: Record<string, string> = {};
53+
event.request.headers.forEach((v, k) => { headers[k] = v; })
54+
console.warn(`CatchHandler called for: ${JSON.stringify({
55+
destination: event.request.destination,
56+
url: event.request.url,
57+
method: event.request.method,
58+
mode: event.request.mode,
59+
cache: event.request.cache,
60+
credentials: event.request.credentials,
61+
headers,
62+
redirect: event.request.redirect,
63+
bodyUsed: event.request.bodyUsed
64+
})}`)
65+
return Response.error();
66+
})

mobile/src/vite-env.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
/// <reference types="vite/client" />
2+
/// <reference types="workbox-precaching" />
3+
/// <reference types="vite-plugin-pwa/client" />
4+
/// <reference types="vite-plugin-pwa/info" />
5+
/// <reference types="vite-plugin-pwa/vue" />
26

37
interface ImportMetaEnv {
48
readonly VITE_FIREBASE_API_KEY: string,

mobile/vite.config.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,14 @@ export default defineConfig(({ command, mode }) => {
1616
type: 'module'
1717
},
1818
strategies: 'injectManifest',
19-
injectRegister: 'inline',
20-
registerType: 'autoUpdate',
19+
injectRegister: null,
20+
registerType: 'prompt',
21+
includeAssets: ['favicon.png'],
2122
srcDir: 'src',
2223
filename: 'sw.ts',
2324
mode: isDevMode?'development':'production',
2425
minify: !isDevMode,
26+
selfDestroying: false,
2527
workbox: {
2628
mode: isDevMode?'development':'production',
2729
sourcemap: isDevMode,

0 commit comments

Comments
 (0)