Egg 学习笔记-源码分析1

本文探讨了Egg.js框架中模块的加载机制,重点介绍了controller和服务模块的自动加载过程。通过对Egg-core源码的解析,揭示了如何在不使用require的情况下调用这些模块。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. Egg在调用controller/service文件夹下的模块时,不需要require,如何实现的?

在原生Node/Koa中,当我们需要调用其他模块时,需要require, 非常繁琐。(java体系都是auto import)

但在Egg中,我们可以通过app.controller.文件名的形式直接调用。

猜想,是不是在app文件夹下任意写一个文件夹xxx,再在xxx下写一个yyy.js, 就可以实现app.xxx.yyy直接调用?实践结果是No。

先说结论,app/加文件夹的方式是实现不了上述的目的的,但在controller/service文件夹里嵌套文件夹,可以实现。这个在官方文档里没有直接写明。

原理:

Egg在启动worker进程时,会执行loadController, loadService等方法,遍历解析app/controller, app/service文件夹下的所有js文件,把导出的模块进行挂载, 对应实现模块是egg-core。

egg-core/lib/loader/mixin/下面有如下的文件:
controller.js,service,js,extend.js,middleware.js, 他们分别对应负责加载controller,service, extend等

controller.js,

opt = Object.assign({
  caseStyle: 'lower',
  directory: path.join(this.options.baseDir, 'app/controller'),
  initializer: (obj, opt) => {
  ...忽略其他代码...
  const controllerBase = opt.directory;

  this.loadToApp(controllerBase, 'controller', opt);
  this.options.logger.info('[egg:loader] Controller loaded: %s', controllerBase);
},

看到loadToApp的调用,传参指定了app/controller文件夹

loadToApp最后会调用file_loader.js里的load,关键几行代码如下:

let files = this.options.match || [ '**/*.js' ];
const filepaths = globby.sync(files, { cwd: directory });
const properties = filepath.substring(0, filepath.lastIndexOf('.')).split('/');

上述代码实现了把嵌套的js文件全部解析和挂载。注释也很清晰:

文件路径app/service/foo/bar.js 会转换为 service.foo.bar

需要注意的是,controller是loadToApp,也就是加载到应用级别, service是loadToContext, 也就是加载到请求级别的对象。所以在router里是通过app.controller方式引用,而在controler里使用service是this.ctx.service。这在Egg文档Loader一节里也有说明,service是请求中首次访问时才进行实例化,并缓存下来。这里是通过定义getter来实现

 Object.defineProperty(app.context, property, {
  get() {
    // distinguish property cache,
    // cache's lifecycle is the same with this context instance
    // e.x. ctx.service1 and ctx.service2 have different cache
    if (!this[CLASSLOADER]) {
      this[CLASSLOADER] = new Map();
    }
    const classLoader = this[CLASSLOADER];

    let instance = classLoader.get(property);
    if (!instance) {
      instance = getInstance(target, this);
      classLoader.set(property, instance);
    }
    return instance;
  },
});

另外,Egg-loader里还学到使用mixin实现多继承。

当使用egg-Sequelize实现ORM时,app/model下的js也可以被自动读取.

查阅源码知道,这些其实是通过在插件里调用Egg提供的low-level API实现的

Sequelize也是类似的

function loadModel(app) {
    const modelDir = path.join(app.baseDir, 'app/model');
     app.loader.loadToApp(modelDir, MODELS, {
     inject: app,
     caseStyle: 'upper',
    ignore: 'index.js',
});
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值