import { lazy, ComponentType } from 'react' /** * 带自动重试的懒加载。 * * 部署后旧 chunk 文件名(带 hash)被删除,浏览器若缓存了旧 index.html * 仍会请求旧 chunk 导致 "Failed to fetch dynamically imported module"。 * 此时自动刷新页面,让浏览器获取新 index.html 中的新 chunk 引用。 */ export function lazyRetry>( factory: () => Promise<{ default: T } | { [key: string]: T }>, ): React.LazyExoticComponent { return lazy(async () => { try { const m = await factory() // 统一为 { default: T } 格式 if ('default' in m) return { default: m.default } // named export 模式:取第一个导出作为 default const firstKey = Object.keys(m)[0] return { default: m[firstKey] } } catch (err: any) { // 仅对动态导入失败自动刷新,避免其他错误误触发 if ( err && (err.message?.includes('Failed to fetch dynamically imported module') || err.message?.includes('Importing a module script failed') || err.message?.includes('error loading dynamically imported module')) ) { // 防止无限刷新:用 sessionStorage 标记,仅刷新一次 const key = 'lazyRetry:' + (err.message.match(/[\w-]+\.js/)?.[0] || 'unknown') if (!sessionStorage.getItem(key)) { sessionStorage.setItem(key, '1') window.location.reload() // 返回一个永不 resolve 的 Promise,等待页面刷新 return new Promise<{ default: T }>(() => {}) } sessionStorage.removeItem(key) } throw err } }) }