// 自动扫描 controllers 目录并注册路由 // 兼容传统 routes 方式和自动注册 controller 方式 import fs from "fs" import path from "path" import { logger } from "@/logger.js" // 保证不会被摇树(tree-shaking),即使在生产环境也会被打包 if (import.meta.env.PROD) { // 通过引用返回值,防止被摇树优化 let controllers = import.meta.glob("../controllers/**/*Controller.js", { eager: true }) controllers = null console.log(controllers); } /** * 自动扫描 controllers 目录,注册所有导出的路由 * 自动检测 routes 目录下已手动注册的 controller,避免重复注册 * @param {Koa} app - Koa 实例 * @param {string} controllersDir - controllers 目录路径 * @param {string} prefix - 路由前缀 * @param {Set} [manualControllers] - 可选,手动传入已注册 controller 文件名集合,优先于自动扫描 */ export function autoRegisterControllers(app, controllersDir) { let allRouter = [] function scan(dir, routePrefix = "") { try { for (const file of fs.readdirSync(dir)) { const fullPath = path.join(dir, file) const stat = fs.statSync(fullPath) if (stat.isDirectory()) { scan(fullPath, routePrefix + "/" + file) } else if (file.endsWith("Controller.js")) { try { // 使用同步的import方式,确保ES模块兼容性 const controllerModule = require(fullPath) const controller = controllerModule.default || controllerModule if (!controller) { logger.warn(`[控制器注册] ${file} - 缺少默认导出,跳过注册`) continue } const routes = controller.createRoutes || controller.default?.createRoutes || controller.default || controller if (typeof routes === "function") { try { const router = routes() if (router && typeof router.middleware === "function") { allRouter.push(router) logger.info(`[控制器注册] ✅ ${file} - 路由创建成功`) } else { logger.warn(`[控制器注册] ⚠️ ${file} - createRoutes() 返回的不是有效的路由器对象`) } } catch (error) { logger.error(`[控制器注册] ❌ ${file} - createRoutes() 执行失败: ${error.message}`) } } else { logger.warn(`[控制器注册] ⚠️ ${file} - 未找到 createRoutes 方法或导出对象`) } } catch (importError) { logger.error(`[控制器注册] ❌ ${file} - 模块导入失败: ${importError.message}`) } } } } catch (error) { logger.error(`[控制器注册] ❌ 扫描目录失败 ${dir}: ${error.message}`) } } try { scan(controllersDir) if (allRouter.length === 0) { logger.warn("[路由注册] ⚠️ 未发现任何可注册的控制器") return } logger.info(`[路由注册] 📋 发现 ${allRouter.length} 个控制器,开始注册到应用`) // 按顺序注册路由,确保中间件执行顺序 for (let i = 0; i < allRouter.length; i++) { const router = allRouter[i] try { app.use(router.middleware()) logger.debug(`[路由注册] 🔗 路由 ${i + 1}/${allRouter.length} 注册成功`) // 枚举并紧凑输出该路由器下的所有路由方法与路径(单行聚合) const methodEntries = Object.entries(router.routes || {}) const items = [] for (const [method, list] of methodEntries) { if (!Array.isArray(list) || list.length === 0) continue for (const r of list) { if (!r || !r.path) continue items.push(`${method.toUpperCase()} ${r.path}`) } } if (items.length > 0) { const prefix = router.options && router.options.prefix ? router.options.prefix : "" logger.info(`[路由注册] ✅ ${prefix || "/"} 共 ${items.length} 条 -> ${items.join("; ")}`) } else { logger.warn(`[路由注册] ⚠️ 该控制器未包含任何可用路由`) } } catch (error) { logger.error(`[路由注册] ❌ 路由 ${i + 1}/${allRouter.length} 注册失败: ${error.message}`) } } logger.info(`[路由注册] ✅ 完成!成功注册 ${allRouter.length} 个控制器路由`) } catch (error) { logger.error(`[路由注册] ❌ 自动注册过程中发生严重错误: ${error.message}`) } }