@@ -7,24 +7,25 @@ const isFunction = require('is-type-of').function;
7
7
const interopRequire = require ( 'interop-require' ) ;
8
8
const debug = require ( 'debug' ) ( 'egg:loader' ) ;
9
9
const Loader = require ( './loader' ) ;
10
+ const Emitter = require ( 'events' ) . EventEmitter ;
10
11
11
12
class EggLoader {
12
13
13
14
/**
14
15
* @constructor
15
16
* @param {Object } options
16
17
* - {String} [baseDir] - 应用根目录
17
- * - {String} [eggPath] - 使用 egg-loader 的框架的路径,如 egg
18
- * - {String} [customEgg] - 自定义入口框架的路径,每个异构技术 bu 都可以自定义自己的插件集合
19
- * - {Object} [plugins] - 自定义插件配置,测试用
20
18
* - {Object} [app] - app 实例,如果是 Agent Worker 则传入 agent 实例,可为空
19
+ * - {Object} [plugins] - 自定义插件配置,测试用
21
20
* - {Logger} [logger] - logger 实例,默认是 console
22
21
*/
23
22
constructor ( options ) {
24
- this . options = options || { } ;
23
+ options = options || { } ;
24
+ assert ( fs . existsSync ( options . baseDir ) , `${ options . baseDir } not exists` ) ;
25
+
26
+ this . options = options ;
25
27
this . options . logger = this . options . logger || console ;
26
28
this . app = this . options . app || { } ; // master 没有 app
27
- assert ( fs . existsSync ( this . options . baseDir ) , `${ this . options . baseDir } not exists` ) ;
28
29
29
30
/**
30
31
* 读取 package.json
@@ -33,48 +34,22 @@ class EggLoader {
33
34
this . pkg = require ( path . join ( this . options . baseDir , 'package.json' ) ) ;
34
35
35
36
/**
36
- * 初始化时传入,见 {@link EggLoader}
37
- * @member {String} EggLoader#eggPath
38
- */
39
- this . eggPath = fs . realpathSync ( this . options . eggPath ) ;
40
- debug ( 'Loaded eggPath %j' , this . eggPath ) ;
41
-
42
- /**
43
- * 框架可以继承,从入口框架(CustomEgg)找到所有的框架的根目录
44
- *
45
- * 需要通过配置 getter 来指定 eggPath 才能被加载到
46
- *
47
- * ```
48
- * // lib/xx.js
49
- * const egg = require('egg');
50
- * class XxApplication extends egg.Application {
51
- * constructor(options) {
52
- * super(options);
53
- * }
54
- *
55
- * get [Symbol.for('egg#eggPath')]() {
56
- * return path.join(__dirname, '..');
57
- * }
58
- * }
59
- * ```
60
- * @member {Array} EggLoader#frameworkPaths
61
- */
62
- this . frameworkPaths = this . loadFrameworkPaths ( ) ;
63
- debug ( 'Loaded frameworkPaths %j' , this . frameworkPaths ) ;
64
-
65
- /**
66
- * = this.eggPath + this.frameworkPaths
67
37
* @member {Array} EggLoader#eggPaths
38
+ * @see EggLoader#getEggPaths
68
39
*/
69
- this . eggPaths = [ this . eggPath ] . concat ( this . frameworkPaths ) ;
40
+ this . eggPaths = this . getEggPaths ( ) ;
70
41
debug ( 'Loaded eggPaths %j' , this . eggPaths ) ;
71
42
43
+ /**
44
+ * @member {String} EggLoader#serverEnv
45
+ * @see EggLoader#getServerEnv
46
+ */
72
47
this . serverEnv = this . getServerEnv ( ) ;
73
48
debug ( 'Loaded serverEnv %j' , this . serverEnv ) ;
74
49
}
75
50
76
51
/**
77
- * Get environment of Egg, it's not NODE_ENV
52
+ * Get environment of Egg, ** it's not NODE_ENV**
78
53
*
79
54
* 1. from `$baseDir/config/serverEnv`
80
55
* 2. from EGG_SERVER_ENV
@@ -115,6 +90,53 @@ class EggLoader {
115
90
return serverEnv ;
116
91
}
117
92
93
+ /**
94
+ * Get all framework directories.
95
+ *
96
+ * You can extend Application of egg, the extrypoint is options.app,
97
+ *
98
+ * loader will find all directories from the prototype of Application,
99
+ * you should define `Symbol.for('egg#eggPath')` property.
100
+ *
101
+ * ```
102
+ * // lib/xx.js
103
+ * const egg = require('egg');
104
+ * class XxApplication extends egg.Application {
105
+ * constructor(options) {
106
+ * super(options);
107
+ * }
108
+ *
109
+ * get [Symbol.for('egg#eggPath')]() {
110
+ * return path.join(__dirname, '..');
111
+ * }
112
+ * }
113
+ * ```
114
+ *
115
+ * @return {Array } framework directories
116
+ */
117
+ getEggPaths ( ) {
118
+ const eggPaths = [ ] ;
119
+
120
+ let proto = this . app ;
121
+ while ( proto ) {
122
+ proto = Object . getPrototypeOf ( proto ) ;
123
+ if ( proto ) {
124
+ if ( isKoa ( proto ) ) {
125
+ break ;
126
+ }
127
+ const eggPath = proto [ Symbol . for ( 'egg#eggPath' ) ] ;
128
+ assert ( eggPath , 'Symbol.for(\'egg#eggPath\') is required on Application' ) ;
129
+ // 使用 fs.realpathSync 来找到最终路径
130
+ const realpath = fs . realpathSync ( eggPath ) ;
131
+ if ( eggPaths . indexOf ( realpath ) === - 1 ) {
132
+ eggPaths . unshift ( realpath ) ;
133
+ }
134
+ }
135
+ }
136
+
137
+ return eggPaths ;
138
+ }
139
+
118
140
/**
119
141
* 加载自定义的 app.js,**在 app.js 可做任何操作,但建议尽量减少此操作,做该做的事**。
120
142
*
@@ -209,9 +231,6 @@ class EggLoader {
209
231
210
232
const dirs = this . dirs = [ ] ;
211
233
212
- // egg 本身路径,在 lib/core 目录下
213
- dirs . push ( path . join ( this . eggPath , 'lib/core' ) ) ;
214
-
215
234
// 插件目录,master 没有 plugin
216
235
if ( this . orderPlugins ) {
217
236
for ( const plugin of this . orderPlugins ) {
@@ -220,8 +239,8 @@ class EggLoader {
220
239
}
221
240
222
241
// egg 框架路径,在 lib/core 目录下
223
- for ( const frameworkPath of this . frameworkPaths ) {
224
- dirs . push ( path . join ( frameworkPath , 'lib/core' ) ) ;
242
+ for ( const eggPath of this . eggPaths ) {
243
+ dirs . push ( path . join ( eggPath , 'lib/core' ) ) ;
225
244
}
226
245
227
246
// 应用目录
@@ -231,42 +250,6 @@ class EggLoader {
231
250
return dirs ;
232
251
}
233
252
234
-
235
- /**
236
- * 获取 {@link EggLoader#frameworkPaths}
237
- * @return {Array } 框架目录
238
- * @private
239
- */
240
- loadFrameworkPaths ( ) {
241
- const eggPath = this . eggPath ;
242
- const frameworkPaths = [ ] ;
243
-
244
- addEggPath ( this . options . customEgg ) ;
245
-
246
- // 遍历整个原型链,获取原型链上所有的 eggPath
247
- // 越核心的优先级越高
248
- let proto = this . app ;
249
- while ( proto ) {
250
- proto = Object . getPrototypeOf ( proto ) ;
251
- if ( proto ) {
252
- const eggPath = proto [ Symbol . for ( 'egg#eggPath' ) ] ;
253
- addEggPath ( eggPath ) ;
254
- }
255
- }
256
-
257
- return frameworkPaths ;
258
-
259
- function addEggPath ( dirpath ) {
260
- if ( dirpath ) {
261
- // 使用 fs.realpathSync 来找到最终路径
262
- const realpath = fs . realpathSync ( dirpath ) ;
263
- if ( frameworkPaths . indexOf ( realpath ) === - 1 && realpath !== eggPath ) {
264
- frameworkPaths . unshift ( realpath ) ;
265
- }
266
- }
267
- }
268
- }
269
-
270
253
/**
271
254
* 返回应用 appname,默认获取 pkg.name
272
255
*
@@ -316,3 +299,9 @@ for (const loader of loaders) {
316
299
}
317
300
318
301
module . exports = EggLoader ;
302
+
303
+ function isKoa ( app ) {
304
+ return app . hasOwnProperty ( 'use' ) &&
305
+ app . hasOwnProperty ( 'listen' ) &&
306
+ Object . getPrototypeOf ( app ) === Emitter . prototype ;
307
+ }
0 commit comments