You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

115 lines
5.3 KiB

// 自动扫描 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<string>} [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}`)
}
}