fix(auth): recover from stale login chunks after logout

This commit is contained in:
朱凯 2026-06-24 17:39:28 +08:00
parent 8413ee3950
commit 92ab2ddae7
2 changed files with 49 additions and 1 deletions

View file

@ -4,6 +4,7 @@ import { Layout } from './layout'
import { getCurrentUser } from '@/api/client'
import { RoleGuard } from '@/shared/components/role-guard'
import { createRequireAuth } from '@/shared/lib/auth-route'
import { clearDynamicImportReloadGuard, recoverFromDynamicImportError } from '@/shared/lib/dynamic-import-recovery'
import { normalizeSearchQuery } from '@/shared/lib/search-query'
/**
@ -25,7 +26,12 @@ function createLazyRouteComponent<TModule extends Record<string, unknown>>(
// Lazy route modules are wrapped in a uniform suspense fallback so route transitions behave
// consistently across public and dashboard pages.
const LazyComponent = lazy(async () => {
const module = await importer()
const module = await importer().catch((error) => {
if (recoverFromDynamicImportError(error)) {
return new Promise<never>(() => {})
}
throw error
})
return { default: module[exportName] as ComponentType<Record<string, unknown>> }
})
@ -477,6 +483,10 @@ export const router = createRouter({
defaultNotFoundComponent: DefaultNotFound,
})
router.subscribe('onResolved', () => {
clearDynamicImportReloadGuard()
})
declare module '@tanstack/react-router' {
interface Register {
router: typeof router

View file

@ -0,0 +1,38 @@
const RELOAD_GUARD_KEY = 'skillhub:dynamic-import-reload'
function resolveErrorMessage(error: unknown): string {
if (error instanceof Error) {
return error.message
}
return String(error ?? '')
}
export function isDynamicImportFetchError(error: unknown): boolean {
const message = resolveErrorMessage(error)
return message.includes('Failed to fetch dynamically imported module')
|| message.includes('error loading dynamically imported module')
|| message.includes('Importing a module script failed')
|| message.includes('ChunkLoadError')
}
export function recoverFromDynamicImportError(error: unknown): boolean {
if (typeof window === 'undefined' || !isDynamicImportFetchError(error)) {
return false
}
if (window.sessionStorage.getItem(RELOAD_GUARD_KEY) === '1') {
window.sessionStorage.removeItem(RELOAD_GUARD_KEY)
return false
}
window.sessionStorage.setItem(RELOAD_GUARD_KEY, '1')
window.location.reload()
return true
}
export function clearDynamicImportReloadGuard(): void {
if (typeof window === 'undefined') {
return
}
window.sessionStorage.removeItem(RELOAD_GUARD_KEY)
}