加载器
Egg 在 Koa 的基础上进行增强最重要的就是基于一定的约定,根据功能差异将代码放到不同的目录下管理,对整体团队的开发成本提升有着明显的效果。Loader 实现了这套约定,并抽象了很多底层 API 可以进一步扩展
框架、插件和应用的关系
1. 框架继承
1 2 3 4 5 6 7 8 9 10 11
| +-----------------------------------+--------+ | app1, app2, app3, app4 | | +-----+--------------+--------------+ | | | | framework3 | | + | framework1 +--------------+ plugin | | | | framework2 | | + +--------------+--------------+ | | Egg | | +-----------------------------------+--------| | Koa | +-----------------------------------+--------+
|
2. 加载单元执行顺序
文件按表格内的顺序自上而下加载
- 按插件 => 框架 => 应用依次加载
- 插件之间的顺序由依赖关系决定,被依赖方先加载,无依赖按 object key 配置顺序加载,具体可以查看插件章节
- 框架按继承顺序加载,越底层越先加载。
3. 加载单元生命周期
- 配置文件即将加载,这是最后动态修改配置的时机(configWillLoad)
- 配置文件加载完成(configDidLoad)
- 文件加载完成(didLoad)
- 插件启动完毕(willReady)
- worker 准备就绪(didReady)
- 应用启动完成(serverDidReady)
- 应用即将关闭(beforeClose)
加载器函数
1. loadFile
1 2 3 4 5 6 7 8 9 10 11 12
| // 用于加载一个文件,比如加载 app/xx.js 就是使用这个方法 // app/xx.js module.exports = app => { console.log(app.config); };
// app.js // 以 app/xx.js 为例,我们可以在 app.js 加载这个文件 const path = require('path'); module.exports = app => { app.loader.loadFile(path.join(app.config.baseDir, 'app/xx.js')); };
|
2. loadToApp
1 2 3 4 5 6 7
| // 用于加载一个目录下的文件到 app,比如 app/controller/home.js 会加载到 app.controller.home。 // app.js // 以下只是示例,加载 controller 请用 loadController module.exports = app => { const directory = path.join(app.config.baseDir, 'app/controller'); app.loader.loadToApp(directory, 'controller'); };
|
3. loadToContext
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| // 与 loadToApp 有一点差异,loadToContext 是加载到 ctx 上而非 app,而且是懒加载。加载时会将文件都放到一个临时对象上,在调用 ctx API 时才实例化对象。 // 以下为示例,请使用 loadService // app/service/user.js const Service = require('egg').Service; class UserService extends Service {
} module.exports = UserService;
// app.js // 获取所有的 loadUnit const servicePaths = app.loader.getLoadUnits().map(unit => path.join(unit.path, 'app/service'));
app.loader.loadToContext(servicePaths, 'service', { // service 需要继承 app.Service,所以要拿到 app 参数 // 设置 call 在加载时会调用函数返回 UserService call: true, // 将文件加载到 app.serviceClasses fieldClass: 'serviceClasses', });
|
CustomLoader
loadToContext 和 loadToApp 可被 customLoader 配置替代。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| // app.js module.exports = app => { const directory = path.join(app.config.baseDir, 'app/adapter'); app.loader.loadToApp(directory, 'adapter'); };;
===== 变成: =====
// config/config.default.js module.exports = { customLoader: { // 定义在 app 上的属性名 app.adapter adapter: { // 相对于 app.config.baseDir directory: 'app/adapter', // 如果是 ctx 则使用 loadToContext inject: 'app', // 是否加载框架和插件的目录 loadunit: false, // 还可以定义其他 LoaderOptions } }, };
|