引言
课程学习来自于"哲玄前端",哲玄大佬的讲解深入浅出,令我收益匪浅。实在是良心的课程,在实践中学到了很多编程思想和设计思路。恩师!!
项目架构概述
elpis-core遵循特定的目录结构和命名规范,就能获得框架的自动加载能力。这种设计减少了配置文件的复杂性,提高了开发效率。核心设计原则包括:
- 分层架构:严格区分控制器(Controller)、服务(Service)和路由(Router)
- 中间件机制:灵活的中间件系统处理横切关注点
- 环境隔离:支持开发、测试和生产环境的配置隔离
- 参数校验:基于JSON Schema的请求参数自动校验
- 服务端渲染:内置支持SSR,提升首屏加载速度和SEO友好性
目录结构详解
heart-elpis/
├── app/ # 业务代码目录
│ ├── controller/ # 控制器层:处理HTTP请求
│ ├── service/ # 服务层:封装业务逻辑
│ ├── middleware/ # 中间件:请求处理管道
│ ├── router/ # 路由定义:URL映射
│ ├── router-schema/ # API参数验证规则
│ ├── extend/ # 框架扩展点
│ └── public/ # 静态资源文件
├── config/ # 配置文件目录
│ ├── config.default.js # 默认配置
│ ├── config.local.js # 本地开发环境配置
│ ├── config.beta.js # 测试环境配置
│ └── config.prod.js # 生产环境配置
├── elpis-core/ # 框架核心代码
│ ├── index.js # 框架启动入口
│ ├── env.js # 环境变量处理
│ └── loader/ # 模块加载器
└── logs/ # 日志目录(被Git忽略)
核心功能实现
1. 洋葱模型中间件系统
基于Koa的洋葱模型,设计了一套灵活的中间件系统。每个请求都会经过一系列中间件处理,形成一个完整的处理管道。这种设计使得横切关注点(如日志、错误处理、参数校验)能够优雅地实现。
module.exports
return async (ctx, next) => {
try {
await next()
} catch (err) {
// 异常处理逻辑
app.logger.error('[-- exception --]:', err)
// 统一错误响应
ctx.status = 200
ctx.body = {
success: false,
code: 50000,
message: '网络异常 请稍后重试',
}
}
}
}
2. 参数校验
基于AJV的强大参数校验系统,自动验证API请求的各部分(headers、query、body、params):
//
if (valid && body && schema.body) {
schema.body.$schema = $schema
validate = ajv.compile(schema.body)
valid = validate(body)
}
// 校验失败处理
if (!valid) {
ctx.body = {
success: false,
message: `request validate fail: ${ajv.errorsText(validate.errors)}`,
code: 442,
}
return
}
shell
### 3. 服务端渲染
内置Nunjucks模板引擎支持,实现高效的服务端渲染:
async
await ctx.render(`output/entry.${ctx.params.page}`, {
name: app.options?.name,
env: app.env.get(),
options: JSON.stringify(app.options),
})
}
4. 模块自动加载
框架通过精心设计的加载器系统,自动加载各类业务模块:
配置加载的优化
其中配置加载顺序的优化是一个重要的改进:
- 最初:配置在服务加载后才加载
- 改进:配置最先加载,确保其他模块能够正确获取配置信息
scss
// 按顺序加载各模块
configLoader(app)
middlewareLoader(app)
extendLoader(app)
serviceLoader(app)
controllerLoader(app)
routerSchemaLoader(app)
routerLoader(app)
实践中的思考
1. 错误处理的演进
最初,错误处理是简单的try-catch:
try
// 业务逻辑
} catch (error) {
console.error('[exception] there is no env.config file')
}
后来发现这种处理方式过于简单,无法提供足够的错误信息。改进后:
try
// 业务逻辑
} catch (error) {
console.error(`[exception] 加载环境配置文件失败: ${error.message}`)
}
结语
任何学习都不可能一蹴而就,编程里面没有什么黑魔法,许多现在无法弄懂的,以后总有一天我要弄懂。任何工具都是服务于开发者,开发者不应局限于任何一种工具,而是需要掌握底层的设计思路,运用市面上琳琅满目的工具完成自己项目的开发。