UNPKG

figma-restoration-mcp-vue-tools

Version:

Professional Figma Component Restoration Kit - MCP tools with snapDOM-powered high-quality screenshots, intelligent shadow detection, and advanced diff analysis for Vue component restoration. Features enhanced figma_compare with color-coded region analysi

485 lines (400 loc) 13 kB
/** * 错误处理服务 * Error Handling Service * * 统一处理组件预览系统中的各种错误 * 提供错误恢复机制和用户友好的错误信息 */ export class ErrorHandlingService { constructor() { this.errorHistory = []; this.errorListeners = new Set(); this.maxHistorySize = 50; this.setupGlobalErrorHandling(); } /** * 错误类型定义 */ static ErrorTypes = { COMPONENT_NOT_FOUND: 'component-not-found', COMPONENT_LOAD_ERROR: 'component-load-error', COMPONENT_RENDER_ERROR: 'component-render-error', NETWORK_ERROR: 'network-error', JAVASCRIPT_ERROR: 'javascript-error', PROMISE_REJECTION: 'promise-rejection', INITIALIZATION_ERROR: 'initialization-error', SCREENSHOT_ERROR: 'screenshot-error', URL_PARAMETER_ERROR: 'url-parameter-error' }; /** * 错误严重程度 */ static ErrorSeverity = { LOW: 'low', MEDIUM: 'medium', HIGH: 'high', CRITICAL: 'critical' }; /** * 处理错误 */ handleError(error, context = {}) { const errorInfo = this.createErrorInfo(error, context); // 添加到历史记录 this.addToHistory(errorInfo); // 记录错误 this.logError(errorInfo); // 通知监听器 this.notifyListeners(errorInfo); // 尝试恢复 this.attemptRecovery(errorInfo); return errorInfo; } /** * 创建错误信息对象 */ createErrorInfo(error, context) { const errorInfo = { id: this.generateErrorId(), timestamp: new Date().toISOString(), message: error.message || String(error), stack: error.stack, type: this.determineErrorType(error, context), severity: this.determineSeverity(error, context), context: { component: context.component || null, url: window.location.href, userAgent: navigator.userAgent, ...context }, recovered: false, recoveryAttempts: 0 }; return errorInfo; } /** * 确定错误类型 */ determineErrorType(error, context) { const message = error.message || String(error); if (message.includes('not found') || message.includes('未找到')) { return ErrorHandlingService.ErrorTypes.COMPONENT_NOT_FOUND; } if (message.includes('Failed to fetch') || message.includes('网络')) { return ErrorHandlingService.ErrorTypes.NETWORK_ERROR; } if (context.type) { return context.type; } if (error.name === 'TypeError' || error.name === 'ReferenceError') { return ErrorHandlingService.ErrorTypes.JAVASCRIPT_ERROR; } return ErrorHandlingService.ErrorTypes.COMPONENT_LOAD_ERROR; } /** * 确定错误严重程度 */ determineSeverity(error, context) { const type = this.determineErrorType(error, context); switch (type) { case ErrorHandlingService.ErrorTypes.COMPONENT_NOT_FOUND: return ErrorHandlingService.ErrorSeverity.MEDIUM; case ErrorHandlingService.ErrorTypes.NETWORK_ERROR: return ErrorHandlingService.ErrorSeverity.HIGH; case ErrorHandlingService.ErrorTypes.INITIALIZATION_ERROR: return ErrorHandlingService.ErrorSeverity.CRITICAL; case ErrorHandlingService.ErrorTypes.JAVASCRIPT_ERROR: return ErrorHandlingService.ErrorSeverity.HIGH; default: return ErrorHandlingService.ErrorSeverity.MEDIUM; } } /** * 尝试错误恢复 */ async attemptRecovery(errorInfo) { const { type, context } = errorInfo; let recovered = false; try { switch (type) { case ErrorHandlingService.ErrorTypes.COMPONENT_NOT_FOUND: recovered = await this.recoverComponentNotFound(errorInfo); break; case ErrorHandlingService.ErrorTypes.COMPONENT_LOAD_ERROR: recovered = await this.recoverComponentLoadError(errorInfo); break; case ErrorHandlingService.ErrorTypes.NETWORK_ERROR: recovered = await this.recoverNetworkError(errorInfo); break; case ErrorHandlingService.ErrorTypes.COMPONENT_RENDER_ERROR: recovered = await this.recoverRenderError(errorInfo); break; default: console.log(`⚠️ 暂无针对 ${type} 类型错误的恢复机制`); } if (recovered) { errorInfo.recovered = true; console.log(`✅ 错误恢复成功: ${errorInfo.id}`); // 通知恢复成功 this.notifyRecovery(errorInfo); } } catch (recoveryError) { console.error(`❌ 错误恢复失败: ${errorInfo.id}`, recoveryError); } errorInfo.recoveryAttempts++; return recovered; } /** * 恢复组件未找到错误 */ async recoverComponentNotFound(errorInfo) { const { context } = errorInfo; if (context.component) { console.log(`🔄 尝试重新扫描组件: ${context.component}`); try { // 动态导入组件发现服务 const { componentDiscoveryService } = await import('./ComponentDiscoveryService.js'); // 重新扫描组件 await componentDiscoveryService.scanComponents(); // 检查组件是否现在可用 const componentInfo = componentDiscoveryService.getComponentInfo(context.component); if (componentInfo) { console.log(`✅ 组件重新扫描成功: ${context.component}`); return true; } } catch (error) { console.error(`❌ 组件重新扫描失败: ${context.component}`, error); } } return false; } /** * 恢复组件加载错误 */ async recoverComponentLoadError(errorInfo) { const { context } = errorInfo; // 尝试清除模块缓存并重新加载 if (context.component) { console.log(`🔄 尝试重新加载组件: ${context.component}`); try { // 等待一段时间后重试 await new Promise(resolve => setTimeout(resolve, 1000)); const { componentDiscoveryService } = await import('./ComponentDiscoveryService.js'); const component = await componentDiscoveryService.loadComponent(context.component); if (component) { console.log(`✅ 组件重新加载成功: ${context.component}`); return true; } } catch (error) { console.error(`❌ 组件重新加载失败: ${context.component}`, error); } } return false; } /** * 恢复网络错误 */ async recoverNetworkError(errorInfo) { console.log('🔄 尝试恢复网络连接...'); try { // 简单的网络连接测试 const response = await fetch(window.location.origin, { method: 'HEAD', cache: 'no-cache' }); if (response.ok) { console.log('✅ 网络连接已恢复'); return true; } } catch (error) { console.error('❌ 网络连接仍然存在问题', error); } return false; } /** * 恢复渲染错误 */ async recoverRenderError(errorInfo) { const { context } = errorInfo; console.log(`🔄 尝试恢复渲染错误: ${context.component}`); try { // 清理可能的DOM状态 const targetElement = document.getElementById('screenshot-target'); if (targetElement) { targetElement.innerHTML = ''; } // 等待DOM清理完成 await new Promise(resolve => setTimeout(resolve, 500)); console.log('✅ DOM状态已清理,可以重新尝试渲染'); return true; } catch (error) { console.error('❌ DOM清理失败', error); } return false; } /** * 生成错误ID */ generateErrorId() { return `error_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; } /** * 记录错误 */ logError(errorInfo) { const { severity, type, message, context } = errorInfo; const logMethod = severity === ErrorHandlingService.ErrorSeverity.CRITICAL ? 'error' : severity === ErrorHandlingService.ErrorSeverity.HIGH ? 'error' : severity === ErrorHandlingService.ErrorSeverity.MEDIUM ? 'warn' : 'log'; console[logMethod](`🚨 [${severity.toUpperCase()}] ${type}:`, { message, context, id: errorInfo.id, timestamp: errorInfo.timestamp }); } /** * 添加到历史记录 */ addToHistory(errorInfo) { this.errorHistory.unshift(errorInfo); // 限制历史记录大小 if (this.errorHistory.length > this.maxHistorySize) { this.errorHistory = this.errorHistory.slice(0, this.maxHistorySize); } } /** * 获取错误历史 */ getErrorHistory() { return [...this.errorHistory]; } /** * 清除错误历史 */ clearErrorHistory() { this.errorHistory = []; } /** * 添加错误监听器 */ addErrorListener(callback) { this.errorListeners.add(callback); return () => { this.errorListeners.delete(callback); }; } /** * 通知错误监听器 */ notifyListeners(errorInfo) { this.errorListeners.forEach(callback => { try { callback(errorInfo); } catch (error) { console.error('🚨 错误监听器执行失败:', error); } }); } /** * 通知恢复成功 */ notifyRecovery(errorInfo) { // 发送自定义事件 window.dispatchEvent(new CustomEvent('error-recovered', { detail: errorInfo })); } /** * 设置全局错误处理 */ setupGlobalErrorHandling() { // JavaScript错误 window.addEventListener('error', (event) => { this.handleError(event.error || new Error(event.message), { type: ErrorHandlingService.ErrorTypes.JAVASCRIPT_ERROR, filename: event.filename, lineno: event.lineno, colno: event.colno }); }); // Promise拒绝 window.addEventListener('unhandledrejection', (event) => { this.handleError(event.reason, { type: ErrorHandlingService.ErrorTypes.PROMISE_REJECTION }); }); console.log('🛡️ 全局错误处理已设置'); } /** * 获取用户友好的错误消息 */ getUserFriendlyMessage(errorInfo) { const { type, context } = errorInfo; switch (type) { case ErrorHandlingService.ErrorTypes.COMPONENT_NOT_FOUND: return `组件 "${context.component}" 未找到,请检查组件是否存在于 src/components 目录中`; case ErrorHandlingService.ErrorTypes.COMPONENT_LOAD_ERROR: return `组件 "${context.component}" 加载失败,可能存在语法错误或依赖问题`; case ErrorHandlingService.ErrorTypes.NETWORK_ERROR: return '网络连接出现问题,请检查网络连接后重试'; case ErrorHandlingService.ErrorTypes.COMPONENT_RENDER_ERROR: return `组件 "${context.component}" 渲染失败,请检查组件代码`; default: return '发生了未知错误,请刷新页面重试'; } } /** * 获取恢复建议 */ getRecoverySuggestions(errorInfo) { const { type, context } = errorInfo; switch (type) { case ErrorHandlingService.ErrorTypes.COMPONENT_NOT_FOUND: return [ '检查组件名称是否正确', '确认组件文件存在于 src/components 目录', '检查组件文件名是否为 index.vue', '尝试刷新页面重新扫描组件' ]; case ErrorHandlingService.ErrorTypes.COMPONENT_LOAD_ERROR: return [ '检查组件语法是否正确', '确认所有依赖都已正确导入', '查看浏览器控制台的详细错误信息', '尝试重新启动开发服务器' ]; case ErrorHandlingService.ErrorTypes.NETWORK_ERROR: return [ '检查网络连接', '确认开发服务器正在运行', '尝试刷新页面', '检查防火墙设置' ]; default: return [ '刷新页面重试', '检查浏览器控制台错误信息', '重新启动开发服务器' ]; } } /** * 获取调试信息 */ getDebugInfo() { return { errorCount: this.errorHistory.length, recentErrors: this.errorHistory.slice(0, 5), listenerCount: this.errorListeners.size, timestamp: new Date().toISOString() }; } } // 创建单例实例 export const errorHandlingService = new ErrorHandlingService(); // 开发环境下的调试功能 if (typeof window !== 'undefined' && import.meta.env && import.meta.env.DEV) { window.errorHandlingService = errorHandlingService; console.log('🔧 ErrorHandlingService 已挂载到 window.errorHandlingService'); }