vue2, vite, service worker, firebase hosting, iOS/Apple update too frequent
Has anyone else ran into an issue with vue 2, vite, service workers and firebase hosting whereby Apple devices want to update their service workers more frequently than android devices?
I've set everything up exactly as per the docs, but iOS devices specifically keep doing a service worker refrsh/update even when I haven't uploaded a new build to Firebase.
I know it's only happening with Apple devices because I can query and filter my Google Analytics for refreshes and correlate it to device brand - in the screenshot, Apple devices are updating every day, non-Apple only when I actually released a new build to Firebase.
This is the service work code below:
file - useRegisterSW.js as a mixin
import gaTag from "@/mixins/gaTag";
export default {
mixins: [gaTag],
name: "useRegisterSW",
data() {
return {
updateSW: undefined,
offlineReady: false,
needRefresh: false,
};
},
async mounted() {
try {
const { registerSW } = await import("virtual:pwa-register");
const vm = this;
this.updateSW = registerSW({
immediate: true,
onOfflineReady() {
vm.offlineReady = true;
vm.onOfflineReadyFn();
},
onNeedRefresh() {
vm.needRefresh = true;
vm.onNeedRefreshFn();
},
onRegistered(swRegistration) {
swRegistration && vm.handleSWManualUpdates(swRegistration);
},
onRegisterError(e) {
vm.handleSWRegisterError(e);
},
});
} catch {
console.log("PWA disabled.");
}
},
methods: {
async closePromptUpdateSW() {
this.offlineReady = false;
this.needRefresh = false;
},
onOfflineReadyFn() {
console.log("onOfflineReady");
},
onNeedRefreshFn() {
this.$gaExperience("refreshneeded", true);
console.log("onNeedRefresh");
},
updateServiceWorker() {
this.$gaClickLink("UpgradeApp");
console.log("updating");
this.updateSW && this.updateSW(true);
this.$gaInteraction("updatingserviceworker", true);
},
handleSWManualUpdates(swRegistration) {},
handleSWRegisterError(error) {
this.$gaExperience("swregistererror", error);
},
},
};
This is where it's called in App.vue (relevant parts only)
<template>
<div id="app" style="padding-bottom: 85px">
<b-alert :show="needRefresh" class="position-fixed fixed-bottom py-4 m-0 rounded-0" style="z-index: 2000"
variant="warning" @click="updateServiceWorker()">
<div class="d-flex align-items-center justify-content-between">
New version available!
<b-button @click="updateServiceWorker()" size="sm" variant="outline-primary">Update</b-button>
</div>
</b-alert>
</template>
<script>
import { mapState } from "vuex";
import useRegisterSW from '@/mixins/useRegisterSW'
export default {
components: {
},
mixins: [useRegisterSW],
data() {
return {
refreshing: false,
registration: null,
onLine: navigator.onLine,
showBackOnline: false,
dismissSecs: 3,
};
},
computed: {
},
mounted() {
window.addEventListener("online", this.updateOnlineStatus);
window.addEventListener("offline", this.updateOnlineStatus);
},
beforeDestroy() {
window.removeEventListener("online", this.updateOnlineStatus);
window.removeEventListener("offline", this.updateOnlineStatus);
},
created() {
},
watch: {
onLine(v) {
if (v) {
this.showBackOnline = this.dismissSecs;
setTimeout(() => {
this.showBackOnline = false;
}, 4000);
}
},
},
methods: {
updateOnlineStatus(e) {
const { type } = e;
this.onLine = type === "online";
},
},
};
</script>