55 lines
1.3 KiB
TypeScript
55 lines
1.3 KiB
TypeScript
|
|
const RELOAD_FLAG_KEY = '__chunk_reload_at'
|
||
|
|
const RELOAD_COOLDOWN_MS = 10_000
|
||
|
|
|
||
|
|
function shouldReload(): boolean {
|
||
|
|
try {
|
||
|
|
const raw = sessionStorage.getItem(RELOAD_FLAG_KEY)
|
||
|
|
if (!raw) return true
|
||
|
|
const at = Number(raw)
|
||
|
|
if (!Number.isFinite(at)) return true
|
||
|
|
return Date.now() - at > RELOAD_COOLDOWN_MS
|
||
|
|
} catch {
|
||
|
|
return true
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function markReload(): void {
|
||
|
|
try {
|
||
|
|
sessionStorage.setItem(RELOAD_FLAG_KEY, String(Date.now()))
|
||
|
|
} catch {
|
||
|
|
// ignore storage failures (private mode, quota)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
export function reloadForStaleChunk(): boolean {
|
||
|
|
if (!shouldReload()) return false
|
||
|
|
markReload()
|
||
|
|
location.reload()
|
||
|
|
return true
|
||
|
|
}
|
||
|
|
|
||
|
|
const CHUNK_ERROR_PATTERNS = [
|
||
|
|
/Failed to fetch dynamically imported module/i,
|
||
|
|
/error loading dynamically imported module/i,
|
||
|
|
/Importing a module script failed/i,
|
||
|
|
/Unable to preload CSS/i,
|
||
|
|
]
|
||
|
|
|
||
|
|
export function isChunkLoadError(err: unknown): boolean {
|
||
|
|
const msg =
|
||
|
|
err instanceof Error
|
||
|
|
? err.message
|
||
|
|
: typeof err === 'string'
|
||
|
|
? err
|
||
|
|
: ''
|
||
|
|
return CHUNK_ERROR_PATTERNS.some((re) => re.test(msg))
|
||
|
|
}
|
||
|
|
|
||
|
|
export function registerChunkReloadHandlers(): void {
|
||
|
|
window.addEventListener('vite:preloadError', (event) => {
|
||
|
|
if (reloadForStaleChunk()) {
|
||
|
|
event.preventDefault()
|
||
|
|
}
|
||
|
|
})
|
||
|
|
}
|