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.
168 lines
8.0 KiB
168 lines
8.0 KiB
// 自动扫描 controllers 目录并注册路由
|
|
// 兼容传统 routes 方式和自动注册 controller 方式
|
|
import fs from "fs"
|
|
import path from "path"
|
|
import { logger } from "@/logger.js"
|
|
import routeCache from "./cache/RouteCache.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()) {
|
|
if (!file.startsWith("_")) {
|
|
scan(fullPath, routePrefix + "/" + file)
|
|
}
|
|
} else if (file.endsWith("Controller.js") && !file.startsWith("_")) {
|
|
try {
|
|
const stat = fs.statSync(fullPath)
|
|
const mtime = stat.mtime.getTime()
|
|
|
|
// 尝试从缓存获取路由注册结果
|
|
let cachedRoutes = routeCache.getRegistration(fullPath, mtime)
|
|
|
|
if (cachedRoutes) {
|
|
// 缓存命中,直接使用缓存结果
|
|
allRouter.push(...cachedRoutes)
|
|
logger.info(`[控制器注册] ✨ ${file} - 从缓存加载路由成功`)
|
|
continue
|
|
}
|
|
|
|
// 使用动态导入ES模块
|
|
const controllerModule = require(fullPath)
|
|
const controller = controllerModule.default || controllerModule
|
|
|
|
if (!controller) {
|
|
logger.warn(`[控制器注册] ${file} - 缺少默认导出,跳过注册`)
|
|
continue
|
|
}
|
|
|
|
// 尝试从缓存获取控制器实例
|
|
const className = controller.name || file.replace('.js', '')
|
|
let cachedController = routeCache.getController(className)
|
|
|
|
const routes = controller.createRoutes || controller.default?.createRoutes || controller.default || controller
|
|
|
|
if (typeof routes === "function") {
|
|
try {
|
|
const routerResult = routes()
|
|
const routersToProcess = Array.isArray(routerResult) ? routerResult : [routerResult]
|
|
const validRouters = []
|
|
|
|
for (const router of routersToProcess) {
|
|
if (router && typeof router.middleware === "function") {
|
|
validRouters.push(router)
|
|
} else {
|
|
logger.warn(`[控制器注册] ⚠️ ${file} - createRoutes() 返回的部分路由器对象无效`)
|
|
}
|
|
}
|
|
|
|
if (validRouters.length > 0) {
|
|
allRouter.push(...validRouters)
|
|
|
|
// 将路由注册结果存入缓存(如果缓存启用)
|
|
routeCache.setRegistration(fullPath, mtime, validRouters)
|
|
|
|
// 将控制器类存入缓存以便复用(如果缓存启用)
|
|
if (!cachedController) {
|
|
routeCache.setController(className, controller)
|
|
}
|
|
|
|
// 根据缓存状态显示不同的日志信息
|
|
const cacheEnabled = routeCache.config.enabled
|
|
if (cacheEnabled) {
|
|
logger.info(`[控制器注册] ✅ ${file} - 路由创建成功,已缓存`)
|
|
} else {
|
|
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} 个控制器路由`)
|
|
|
|
// 输出缓存统计信息
|
|
const cacheStats = routeCache.getStats()
|
|
logger.info(`[路由缓存] 缓存状态: ${cacheStats.enabled ? '启用' : '禁用'}, 总命中率: ${cacheStats.hitRate}`)
|
|
if (cacheStats.enabled) {
|
|
logger.debug(`[路由缓存] 详细统计:`, cacheStats.caches)
|
|
}
|
|
|
|
} catch (error) {
|
|
logger.error(`[路由注册] ❌ 自动注册过程中发生严重错误: ${error.message}`)
|
|
}
|
|
}
|
|
|