Fix animation stale reference

This commit is contained in:
2026-07-21 16:03:28 +10:00
parent d2d82ae6ae
commit 9af84760fa
12 changed files with 225 additions and 38 deletions

View File

@@ -1,18 +1,83 @@
<script setup lang="ts">
import { onBeforeUnmount, ref, watch } from 'vue'
import { useRegisterSW } from 'virtual:pwa-register/vue'
import { useNativeRouter } from '@native-vue-router/core'
import { recordPwaUpdateState } from '../pwa'
const native = useNativeRouter()
const { needRefresh, updateServiceWorker } = useRegisterSW()
const reloadPending = ref(false)
let registration: ServiceWorkerRegistration | undefined
let checkTimer: number | undefined
let reloading = false
let checking = false
function reloadWhenIdle() {
if (!reloadPending.value || native.transaction.value || reloading) return
reloading = true
window.location.reload()
}
async function checkForUpdate() {
if (!registration || checking || document.visibilityState === 'hidden' || !navigator.onLine) return
checking = true
recordPwaUpdateState('checking', true)
try {
await registration.update()
if (!reloadPending.value) recordPwaUpdateState('current')
} catch {
recordPwaUpdateState('error')
} finally {
checking = false
}
}
const { needRefresh, updateServiceWorker } = useRegisterSW({
immediate: true,
onRegisteredSW(_workerUrl, workerRegistration) {
registration = workerRegistration
void checkForUpdate()
if (checkTimer !== undefined) window.clearInterval(checkTimer)
checkTimer = window.setInterval(() => void checkForUpdate(), 60_000)
},
onNeedRefresh() {
recordPwaUpdateState('ready')
},
onNeedReload() {
recordPwaUpdateState('ready')
reloadPending.value = true
reloadWhenIdle()
},
onRegisterError() {
recordPwaUpdateState('error')
},
})
function checkWhenActive() {
if (document.visibilityState === 'visible') void checkForUpdate()
}
window.addEventListener('focus', checkWhenActive)
window.addEventListener('online', checkWhenActive)
document.addEventListener('visibilitychange', checkWhenActive)
watch(() => native.transaction.value, reloadWhenIdle, { flush: 'post' })
function update() {
reloadPending.value = true
if (!native.transaction.value) void updateServiceWorker(true)
reloadWhenIdle()
}
onBeforeUnmount(() => {
if (checkTimer !== undefined) window.clearInterval(checkTimer)
window.removeEventListener('focus', checkWhenActive)
window.removeEventListener('online', checkWhenActive)
document.removeEventListener('visibilitychange', checkWhenActive)
})
</script>
<template>
<aside v-if="needRefresh" class="update-toast" role="status">
<span>A fresh build is ready.</span>
<button type="button" :disabled="Boolean(native.transaction.value)" @click="update">Update</button>
<aside v-if="needRefresh || reloadPending" class="update-toast" role="status">
<span>{{ native.transaction.value ? 'A fresh build will open after this gesture.' : 'A fresh build is ready.' }}</span>
<button v-if="needRefresh" type="button" :disabled="Boolean(native.transaction.value)" @click="update">Update</button>
</aside>
</template>