const { resolve } = require('path') const { existsSync, statSync } = require('fs') const ApiCollector = require('./modules/api-collector') const TriggerAnalyzerSimple = require('./modules/trigger-analyzer-simple') const CallChainTracer = require('./modules/call-chain-tracer') const FileGenerator = require('./modules/file-generator') const RouteAnalyzer = require('./modules/route-analyzer') const ComponentRelationshipAnalyzerAST = require('./modules/component-relationship-analyzer-ast') /** * 模块化路由映射插件 * 收集直接映射关系 */ function routeMappingPlugin() { // 检查是否在静默模式下运行 const isSilentMode = process.env.ROUTE_MAPPING_SILENT === 'true' || process.argv.includes('--silent') // 日志函数 const log = (message) => { if (!isSilentMode) { console.log(message) } } return { name: 'route-mapping-phase1', // 防重复生成机制 _lastGenerationTime: 0, _generationInProgress: false, _generationCooldown: 10000, // 10秒冷却时间 _maxGenerationsPerMinute: 3, // 每分钟最多生成3次 _generationCount: 0, _generationWindowStart: 0, // 初始化模块 _apiCollector: new ApiCollector(), _triggerAnalyzer: new TriggerAnalyzerSimple(), _callChainTracer: new CallChainTracer(), _fileGenerator: new FileGenerator(), _routeAnalyzer: new RouteAnalyzer(), _componentRelationshipAnalyzer: new ComponentRelationshipAnalyzerAST(), // Webpack插件接口 apply(compiler) { const self = this // 在编译开始前就生成映射文件 compiler.hooks.beforeCompile.tapAsync('RouteMappingPlugin', (params, callback) => { if (self._shouldSkipGeneration()) { callback() return } try { self.collectDirectMappings() callback() } catch (error) { callback(error) } }) // 备用钩子,确保在beforeRun时也执行 compiler.hooks.beforeRun.tapAsync('RouteMappingPlugin', (compilation, callback) => { if (self._shouldSkipGeneration()) { callback() return } try { self.collectDirectMappings() callback() } catch (error) { callback(error) } }) }, // Vite插件接口 buildStart() { this.collectDirectMappings() }, // 在开发模式下也执行 configureServer(server) { if (this._shouldSkipGeneration()) { return } this.collectDirectMappings() }, // 检查是否应该跳过生成 _shouldSkipGeneration() { const now = Date.now() // 如果正在生成中,跳过 if (this._generationInProgress) { return true } // 如果在冷却期内,跳过 if (now - this._lastGenerationTime < this._generationCooldown) { return true } // 检查每分钟生成次数限制 if (now - this._generationWindowStart > 60000) { // 重置计数窗口 this._generationCount = 0 this._generationWindowStart = now } if (this._generationCount >= this._maxGenerationsPerMinute) { return true } return false }, // 检查是否需要重新生成文件 - 优化版本:每次都生成 _shouldRegenerateFile() { // 为了优化调试,每次都重新生成文件 return true }, // 收集直接映射关系 - 分步执行版本 collectDirectMappings() { try { // 设置生成中标志 this._generationInProgress = true // 检查文件是否需要重新生成 if (!this._shouldRegenerateFile()) { return } // ========== 第一步:收集route和api列表 ========== const routes = this._routeAnalyzer.analyzeRoutes() const moduleDirs = this._routeAnalyzer.getModuleDirs() const apiMappings = this._apiCollector.collectApiMappings(moduleDirs) // 生成包含路由和API信息的文件(不包含triggerSources) this._fileGenerator.generateRouteApiMappingFile(routes, apiMappings) // ========== 第二步:Trigger追溯 ========== const enhancedApiMappings = this._triggerAnalyzer.findTriggerSourcesForApiMappings(apiMappings, routes) // ========== 第二步半:调用链追溯 ========== // 清理已处理文件的记录,开始新的处理周期 this._callChainTracer.clearProcessedFiles() const tracedApiMappings = this._callChainTracer.traceMethodTriggersToVisualComponents(enhancedApiMappings) // 生成包含triggerSources的文件 this._fileGenerator.generateRouteApiMappingFile(routes, tracedApiMappings) // ========== 第三步:删除triggerSources为空的apiMapping ========== const DataCleaner = require('./modules/data-cleaner.js') const dataCleaner = new DataCleaner() const cleanedMappings = dataCleaner.cleanData() // ========== 第四步:分析组件关系 ========== const componentRelationships = this._componentRelationshipAnalyzer.analyzeComponentRelationships(routes, cleanedMappings.apiMappings) // 生成包含组件关系的最终文件 this._fileGenerator.generateRouteApiMappingFileWithRelationships(routes, cleanedMappings.apiMappings, componentRelationships) // 重置生成中标志并更新时间戳 this._generationInProgress = false this._lastGenerationTime = Date.now() this._generationCount++ if (this._generationCount === 1) { this._generationWindowStart = this._lastGenerationTime } } catch (error) { this._generationInProgress = false console.error('❌ 生成direct-route-mappings.js时出错:', error) throw error } } } } module.exports = routeMappingPlugin