Egg

150 阅读1分钟

npm run dev

创建 egg 实例

  • 继承链 Application extends EggApplication extends EggCore extends KoaApplication
// 1.super KoaApplication
拥有koa的属性方法:
1. middleWare
2. use
3. listen
/*
    1. baseDir 项目路径
    2. BaseContextClass(基类)
    3. 实例化生命周期
    4. 实例化loader
*/


constructor(options = {}) {
    options.baseDir = options.baseDir || process.cwd();
    this.BaseContextClass = BaseContextClass;


    this.lifecycle = new Lifecycle({
      baseDir: options.baseDir,
      app: this
    })
   
    this.loader = new Loader({
      baseDir: options.baseDir,
      app: this,
      env: options.env,
    })
}
// 生命周期实例
this[BOOT_HOOKS] = []
this[BOOTS] = []

ready this.triggerWillReady()
ready this.triggerDidReady()
// loader实例记录了很多信息
// package.json对象   环境变量   项目信息(name baseDir env)
constructor(options) {
    this.pkg = utility.readJSONSync(path.join(this.options.baseDir, 'package.json'));
    this.serverEnv = this.getServerEnv();
    this.eggPaths = this.getEggPaths() // 继承
    this.appInfo = this.getAppInfo();
}
// super EggCore
constructor(options = {}) {
    super(options);

    this.ContextCookies = ContextCookies;
    this.ContextLogger = ContextLogger;
    this.ContextHttpClient = ContextHttpClient;
    this.HttpClient = HttpClient;

    this.loader.loadConfig();
}
// 加载插件 loadPlugin
// this.orderPlugins 依赖的所有的插件
{
    p1: { enable: true, path, dependencies },
    p2: { enable: true, path, dependencies },
}
this.getLoadUnits() // 根据orderPlugins返回的插件数组,最后一个是 app
{
    path: plugin.path,
    type: 'plugin',
}
{
    path: baseDir,
    type: 'app'
}
loadConfig() {
    this.configMeta = {};
    const target = {};
 
    // 根据环境变量 加载项目的  config.default config.dev
    const appConfig = this._preloadAppConfig();



    // 按照所有插件  -> app
    for (const filename of this.getTypeFiles('config')) { 
      for (const unit of this.getLoadUnits()) {
        const isApp = unit.type === 'app';
        // 插件的config文件的函数的参数 appInfo appconfig
        const config = this._loadConfig(unit.path, filename, isApp ? undefined : appConfig, unit.type);

        extend(true, target, config);
      }
    }

    // 配置定义的中间件
    target.coreMiddleware = target.coreMiddlewares = target.coreMiddleware || [];
    target.appMiddleware = target.appMiddlewares = target.middleware || [];

    // 得到最终的配置
    this.config = target;
}
loadExtend(name, proto) {
    //    app/extend/application
    const filepaths = this.getExtendFilePaths(name);

    for (let filepath of filepaths) {
      // 抛出对象
      const ext = this.requireFile(filepath);
      const properties = Object.getOwnPropertyNames(ext)
      Object.defineProperty(proto/* app */, property, descriptor)
    }
}
loadApplicationExtend  this.app
loadRequestExtend      this.app.request
loadResponseExtend

this.loadContextExtend()   this.app.context
this.loadHelperExtend() 
if (this.app && this.app.Helper) {
    this.loadExtend('helper', this.app.Helper.prototype);
}   
this.loadCustomLoader()


  
this.loadCustomApp()
1. 执行所有插件的 app 文件,项目app文件 将类存进 lifecycle 的 hooks中,这里注意如果导出的是一个函数:
class Hook {
    constructor(app) {
        this.app = app;
    }
    configDidLoad() {
        hook(this.app) // 函数
    }
}
2. 同步执行所有插件的 configWillLoad  configDidLoad (config其实已经在上面设置了)
triggerConfigWillLoad() {
    for (const boot of this[BOOTS]) {
        boot.configWillLoad();
    }
    this.triggerConfigDidLoad();
}
triggerConfigDidLoad() {
    for (const boot of this[BOOTS]) {
        boot.configDidLoad() 
    }
    this.triggerDidLoad();
}

3. process.nextTick 执行 didload(异步async) 
then -> willReady(异步)-> 盲猜这里进行了listen(也就是项目启动了)-> then -> didReady


4. this.loadService() // 解析service下的文件丰富ctx,BaseContextClass在这体现
5. this.loadMiddleware(); // (this.config[name]/* config里面配置的中间件的信息 */) => (ctx, next) => {}
   执行 use
   先是插件中间件,然后是项目的中间件;

6. this.loadController()
7. this.loadRouter(); // router.js