import type { AsyncComponentLoader, Component } from 'vue'
import { defineAsyncComponent } from 'vue'
/**
* 安全的异步组件加载器
* 防止在组件卸载时继续加载导致的内存泄漏和错误
*/
export function safeAsyncComponent(
loader: AsyncComponentLoader,
options?: {
loadingComponent?: Component
errorComponent?: Component
delay?: number
timeout?: number
suspensible?: boolean
onError?: (error: Error, retry: () => void, fail: () => void, attempts: number) => any
},
) {
const safeLoader: AsyncComponentLoader = () => {
return loader().catch((error) => {
console.error('异步组件加载失败:', error)
// 如果是网络错误或者加载错误,返回一个空的组件
if (error.name === 'ChunkLoadError' || error.message?.includes('Loading chunk')) {
console.warn('检测到代码分割加载错误,尝试重新加载页面')
// 延迟重新加载页面,避免无限循环
setTimeout(() => {
window.location.reload()
}, 1000)
}
// 返回一个错误组件
return Promise.resolve({
template: '
组件加载失败
',
})
})
}
return defineAsyncComponent({
loader: safeLoader,
loadingComponent: options?.loadingComponent,
errorComponent: options?.errorComponent,
delay: options?.delay ?? 200,
timeout: options?.timeout ?? 30000,
suspensible: options?.suspensible ?? false,
onError: options?.onError || ((error, retry, fail, attempts) => {
console.error(`异步组件加载错误 (第${attempts}次尝试):`, error)
if (attempts <= 3) {
retry()
}
else {
fail()
}
}),
})
}
/**
* 创建路由组件的安全加载器
*/
export function createSafeRouteComponent(componentPath: string) {
return safeAsyncComponent(
() => import(/* @vite-ignore */ `/src/views${componentPath}.vue`),
{
delay: 100,
timeout: 10000,
onError: (error, retry, fail, attempts) => {
console.error(`路由组件加载失败: ${componentPath}`, error)
// 对于路由组件,最多重试2次
if (attempts <= 2) {
console.warn(`重试加载组件: ${componentPath} (第${attempts}次)`)
retry()
}
else {
console.error(`组件加载最终失败: ${componentPath}`)
fail()
}
},
},
)
}
/**
* 清理组件缓存,用于解决热更新时的问题
*/
export function clearComponentCache() {
// 在开发环境下清理模块缓存
if (import.meta.hot) {
import.meta.hot.invalidate()
}
}
/**
* 组件安全性检查
*/
export function validateComponent(component: any): boolean {
if (!component) {
console.error('组件为空或未定义')
return false
}
if (typeof component !== 'object' && typeof component !== 'function') {
console.error('组件类型不正确:', typeof component)
return false
}
return true
}