Skip to content

Commit 1d7c110

Browse files
committed
feat(admin): handle dynamic chunk load errors with auto reload
1 parent 398b061 commit 1d7c110

3 files changed

Lines changed: 64 additions & 0 deletions

File tree

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { isChunkLoadError, notifyChunkError } from '~/utils/chunk-error'
2+
3+
export function registerChunkErrorHandler(): void {
4+
if (typeof window === 'undefined') return
5+
6+
window.addEventListener('vite:preloadError', (event) => {
7+
if (isChunkLoadError((event as any).payload)) {
8+
event.preventDefault()
9+
notifyChunkError()
10+
}
11+
})
12+
13+
window.addEventListener('unhandledrejection', (event) => {
14+
if (isChunkLoadError(event.reason)) {
15+
event.preventDefault()
16+
notifyChunkError()
17+
}
18+
})
19+
20+
window.addEventListener('error', (event) => {
21+
if (isChunkLoadError(event.error ?? event.message)) {
22+
event.preventDefault()
23+
notifyChunkError()
24+
}
25+
})
26+
}

apps/admin/src/main.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ import { createRoot } from 'react-dom/client'
55

66
import App from './App'
77
import { migrateLegacyProviderType } from './bootstrap/migrate-legacy-provider-type'
8+
import { registerChunkErrorHandler } from './bootstrap/register-chunk-error-handler'
89

910
migrateLegacyProviderType()
11+
registerChunkErrorHandler()
1012

1113
const appRoot = createRootElement()
1214

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { toast } from 'sonner'
2+
3+
const CHUNK_ERROR_PATTERNS = [
4+
'Failed to fetch dynamically imported module',
5+
'error loading dynamically imported module',
6+
'Importing a module script failed',
7+
'Failed to load module script',
8+
'Loading chunk',
9+
'Loading CSS chunk',
10+
'ChunkLoadError',
11+
]
12+
13+
export function isChunkLoadError(error: unknown): boolean {
14+
if (!error) return false
15+
16+
const name = (error as Error).name ?? ''
17+
const message = (error as Error).message ?? String(error)
18+
const combined = `${name} ${message}`
19+
20+
return CHUNK_ERROR_PATTERNS.some((p) => combined.includes(p))
21+
}
22+
23+
const RELOAD_KEY = 'mx-admin-chunk-reload'
24+
25+
export function notifyChunkError(): void {
26+
const reloaded = sessionStorage.getItem(RELOAD_KEY)
27+
if (reloaded) {
28+
sessionStorage.removeItem(RELOAD_KEY)
29+
toast.error(
30+
'A new version of the admin is available. Please refresh the page to update.',
31+
)
32+
return
33+
}
34+
sessionStorage.setItem(RELOAD_KEY, '1')
35+
window.location.reload()
36+
}

0 commit comments

Comments
 (0)