@eggjs/core 6.4.0 → 6.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -22
- package/dist/commonjs/egg.d.ts +17 -18
- package/dist/commonjs/egg.js +11 -11
- package/dist/commonjs/lifecycle.d.ts +2 -2
- package/dist/commonjs/lifecycle.js +16 -13
- package/dist/commonjs/loader/context_loader.js +2 -2
- package/dist/commonjs/loader/egg_loader.d.ts +13 -13
- package/dist/commonjs/loader/egg_loader.js +77 -62
- package/dist/commonjs/loader/file_loader.d.ts +3 -3
- package/dist/commonjs/loader/file_loader.js +22 -24
- package/dist/commonjs/singleton.d.ts +2 -2
- package/dist/commonjs/singleton.js +6 -7
- package/dist/commonjs/utils/index.d.ts +2 -2
- package/dist/commonjs/utils/index.js +4 -4
- package/dist/commonjs/utils/sequencify.d.ts +1 -1
- package/dist/commonjs/utils/sequencify.js +18 -13
- package/dist/commonjs/utils/timing.js +14 -8
- package/dist/esm/egg.d.ts +17 -18
- package/dist/esm/egg.js +13 -13
- package/dist/esm/lifecycle.d.ts +2 -2
- package/dist/esm/lifecycle.js +16 -13
- package/dist/esm/loader/context_loader.js +2 -2
- package/dist/esm/loader/egg_loader.d.ts +13 -13
- package/dist/esm/loader/egg_loader.js +80 -65
- package/dist/esm/loader/file_loader.d.ts +3 -3
- package/dist/esm/loader/file_loader.js +23 -25
- package/dist/esm/singleton.d.ts +2 -2
- package/dist/esm/singleton.js +6 -7
- package/dist/esm/utils/index.d.ts +2 -2
- package/dist/esm/utils/index.js +4 -4
- package/dist/esm/utils/sequencify.d.ts +1 -1
- package/dist/esm/utils/sequencify.js +18 -13
- package/dist/esm/utils/timing.js +14 -8
- package/dist/package.json +1 -1
- package/package.json +16 -6
- package/src/egg.ts +161 -61
- package/src/lifecycle.ts +72 -33
- package/src/loader/context_loader.ts +9 -7
- package/src/loader/egg_loader.ts +445 -183
- package/src/loader/file_loader.ts +78 -37
- package/src/singleton.ts +64 -26
- package/src/utils/index.ts +20 -13
- package/src/utils/sequencify.ts +50 -15
- package/src/utils/timing.ts +27 -13
package/src/egg.ts
CHANGED
|
@@ -1,26 +1,33 @@
|
|
|
1
1
|
/* eslint-disable prefer-spread */
|
|
2
2
|
import assert from 'node:assert';
|
|
3
3
|
import { debuglog } from 'node:util';
|
|
4
|
+
|
|
4
5
|
import {
|
|
5
|
-
Application as KoaApplication,
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
MiddlewareFunc as KoaMiddlewareFunc,
|
|
10
|
-
Next,
|
|
6
|
+
Application as KoaApplication,
|
|
7
|
+
Context as KoaContext,
|
|
8
|
+
Request as KoaRequest,
|
|
9
|
+
Response as KoaResponse,
|
|
10
|
+
type MiddlewareFunc as KoaMiddlewareFunc,
|
|
11
|
+
type Next,
|
|
11
12
|
} from '@eggjs/koa';
|
|
12
|
-
import { EggConsoleLogger, Logger } from 'egg-logger';
|
|
13
|
-
import {
|
|
13
|
+
import { EggConsoleLogger, type Logger } from 'egg-logger';
|
|
14
|
+
import {
|
|
15
|
+
EggRouter as Router,
|
|
16
|
+
type RegisterOptions,
|
|
17
|
+
type ResourcesController,
|
|
18
|
+
} from '@eggjs/router';
|
|
14
19
|
import type { ReadyFunctionArg } from 'get-ready';
|
|
20
|
+
|
|
15
21
|
import { BaseContextClass } from './base_context_class.js';
|
|
16
22
|
import { Timing } from './utils/timing.js';
|
|
17
|
-
import type { Fun } from './utils/index.js';
|
|
18
23
|
import { Lifecycle } from './lifecycle.js';
|
|
19
24
|
import { EggLoader } from './loader/egg_loader.js';
|
|
20
|
-
import utils from './utils/index.js';
|
|
21
|
-
import { EggAppConfig } from './types.js';
|
|
25
|
+
import utils, { type Fun } from './utils/index.js';
|
|
26
|
+
import type { EggAppConfig } from './types.js';
|
|
22
27
|
import {
|
|
23
|
-
Singleton,
|
|
28
|
+
Singleton,
|
|
29
|
+
type SingletonCreateMethod,
|
|
30
|
+
type SingletonOptions,
|
|
24
31
|
} from './singleton.js';
|
|
25
32
|
|
|
26
33
|
const debug = debuglog('@eggjs/core/egg');
|
|
@@ -38,15 +45,10 @@ export interface EggCoreOptions {
|
|
|
38
45
|
export type EggCoreInitOptions = Partial<EggCoreOptions>;
|
|
39
46
|
|
|
40
47
|
// export @eggjs/koa classes
|
|
41
|
-
export {
|
|
42
|
-
KoaRequest, KoaResponse, KoaContext, KoaApplication,
|
|
43
|
-
Router,
|
|
44
|
-
};
|
|
48
|
+
export { KoaRequest, KoaResponse, KoaContext, KoaApplication, Router };
|
|
45
49
|
|
|
46
50
|
// export @eggjs/koa types
|
|
47
|
-
export type {
|
|
48
|
-
Next, KoaMiddlewareFunc,
|
|
49
|
-
};
|
|
51
|
+
export type { Next, KoaMiddlewareFunc };
|
|
50
52
|
|
|
51
53
|
// export @eggjs/core classes
|
|
52
54
|
export class Request extends KoaRequest {
|
|
@@ -96,7 +98,8 @@ export class Context extends KoaContext {
|
|
|
96
98
|
}
|
|
97
99
|
|
|
98
100
|
// export @eggjs/core types
|
|
99
|
-
export type MiddlewareFunc<T = Context> =
|
|
101
|
+
export type MiddlewareFunc<T extends KoaContext = Context> =
|
|
102
|
+
KoaMiddlewareFunc<T>;
|
|
100
103
|
|
|
101
104
|
export class EggCore extends KoaApplication {
|
|
102
105
|
options: EggCoreOptions;
|
|
@@ -112,27 +115,38 @@ export class EggCore extends KoaApplication {
|
|
|
112
115
|
#router?: Router;
|
|
113
116
|
|
|
114
117
|
/** auto inject on loadService() */
|
|
118
|
+
|
|
115
119
|
readonly serviceClasses: Record<string, any> = {};
|
|
116
120
|
/** auto inject on loadController() */
|
|
121
|
+
|
|
117
122
|
readonly controller: Record<string, any> = {};
|
|
118
123
|
/** auto inject on loadMiddleware() */
|
|
119
|
-
readonly middlewares: Record<
|
|
124
|
+
readonly middlewares: Record<
|
|
125
|
+
string,
|
|
126
|
+
(opt: unknown, app: EggCore) => MiddlewareFunc
|
|
127
|
+
> = {};
|
|
120
128
|
|
|
121
129
|
/**
|
|
122
130
|
* @class
|
|
123
131
|
* @param {Object} options - options
|
|
124
|
-
* @param {String} [options.baseDir
|
|
125
|
-
* @param {String} [options.type
|
|
132
|
+
* @param {String} [options.baseDir] - the directory of application
|
|
133
|
+
* @param {String} [options.type] - whether it's running in app worker or agent worker
|
|
126
134
|
* @param {Object} [options.plugins] - custom plugins
|
|
127
135
|
* @since 1.0.0
|
|
128
136
|
*/
|
|
129
137
|
constructor(options: EggCoreInitOptions = {}) {
|
|
130
138
|
options.baseDir = options.baseDir ?? process.cwd();
|
|
131
139
|
options.type = options.type ?? 'application';
|
|
132
|
-
assert(
|
|
140
|
+
assert(
|
|
141
|
+
typeof options.baseDir === 'string',
|
|
142
|
+
'options.baseDir required, and must be a string'
|
|
143
|
+
);
|
|
133
144
|
// assert(fs.existsSync(options.baseDir), `Directory ${options.baseDir} not exists`);
|
|
134
145
|
// assert(fs.statSync(options.baseDir).isDirectory(), `Directory ${options.baseDir} is not a directory`);
|
|
135
|
-
assert(
|
|
146
|
+
assert(
|
|
147
|
+
options.type === 'application' || options.type === 'agent',
|
|
148
|
+
'options.type should be application or agent'
|
|
149
|
+
);
|
|
136
150
|
super();
|
|
137
151
|
|
|
138
152
|
this.timing = new Timing();
|
|
@@ -205,7 +219,7 @@ export class EggCore extends KoaApplication {
|
|
|
205
219
|
* @since 1.0.0
|
|
206
220
|
*/
|
|
207
221
|
const Loader = this[EGG_LOADER];
|
|
208
|
-
assert(Loader,
|
|
222
|
+
assert(Loader, "Symbol.for('egg#loader') is required");
|
|
209
223
|
this.loader = new Loader({
|
|
210
224
|
baseDir: options.baseDir,
|
|
211
225
|
app: this,
|
|
@@ -239,9 +253,9 @@ export class EggCore extends KoaApplication {
|
|
|
239
253
|
const singleton = new Singleton(options);
|
|
240
254
|
const initPromise = singleton.init();
|
|
241
255
|
if (initPromise) {
|
|
242
|
-
this.
|
|
256
|
+
this.lifecycle.registerBeforeStart(async () => {
|
|
243
257
|
await initPromise;
|
|
244
|
-
});
|
|
258
|
+
}, `${name}-singleton-init`);
|
|
245
259
|
}
|
|
246
260
|
}
|
|
247
261
|
|
|
@@ -249,7 +263,7 @@ export class EggCore extends KoaApplication {
|
|
|
249
263
|
* override koa's app.use, support generator function
|
|
250
264
|
* @since 1.0.0
|
|
251
265
|
*/
|
|
252
|
-
use(fn: MiddlewareFunc) {
|
|
266
|
+
use<T extends KoaContext = Context>(fn: MiddlewareFunc<T>) {
|
|
253
267
|
assert(typeof fn === 'function', 'app.use() requires a function');
|
|
254
268
|
debug('[use] add middleware: %o', fn._name || fn.name || '-');
|
|
255
269
|
this.middleware.push(fn as unknown as KoaMiddlewareFunc);
|
|
@@ -309,7 +323,7 @@ export class EggCore extends KoaApplication {
|
|
|
309
323
|
* @since 1.0.0
|
|
310
324
|
*/
|
|
311
325
|
get config(): EggAppConfig {
|
|
312
|
-
return this.loader ? this.loader.config : {} as EggAppConfig;
|
|
326
|
+
return this.loader ? this.loader.config : ({} as EggAppConfig);
|
|
313
327
|
}
|
|
314
328
|
|
|
315
329
|
/**
|
|
@@ -326,7 +340,9 @@ export class EggCore extends KoaApplication {
|
|
|
326
340
|
* @param {string} [name] scope name, default is empty string
|
|
327
341
|
*/
|
|
328
342
|
beforeStart(scope: Fun, name?: string) {
|
|
329
|
-
this.deprecate(
|
|
343
|
+
this.deprecate(
|
|
344
|
+
'`beforeStart` was deprecated, please use "Life Cycles" instead, see https://www.eggjs.org/advanced/loader#life-cycles'
|
|
345
|
+
);
|
|
330
346
|
this.lifecycle.registerBeforeStart(scope, name ?? '');
|
|
331
347
|
}
|
|
332
348
|
|
|
@@ -363,13 +379,15 @@ export class EggCore extends KoaApplication {
|
|
|
363
379
|
* @param {object} opts -
|
|
364
380
|
* - {Number} [timeout=10000] - emit `ready_timeout` when it doesn't finish but reach the timeout
|
|
365
381
|
* - {Boolean} [isWeakDep=false] - whether it's a weak dependency
|
|
366
|
-
* @
|
|
382
|
+
* @returns {Function} - a callback
|
|
367
383
|
* @example
|
|
368
384
|
* const done = app.readyCallback('mysql');
|
|
369
385
|
* mysql.ready(done);
|
|
370
386
|
*/
|
|
371
387
|
readyCallback(name: string, opts: object) {
|
|
372
|
-
this.deprecate(
|
|
388
|
+
this.deprecate(
|
|
389
|
+
'`readyCallback` was deprecated, please use "Life Cycles" instead, see https://www.eggjs.org/advanced/loader#life-cycles'
|
|
390
|
+
);
|
|
373
391
|
return this.lifecycle.legacyReadyCallback(name, opts);
|
|
374
392
|
}
|
|
375
393
|
|
|
@@ -386,7 +404,9 @@ export class EggCore extends KoaApplication {
|
|
|
386
404
|
* @param {Function} fn - the function that can be generator function or async function.
|
|
387
405
|
*/
|
|
388
406
|
beforeClose(fn: Fun, name?: string) {
|
|
389
|
-
this.deprecate(
|
|
407
|
+
this.deprecate(
|
|
408
|
+
'`beforeClose` was deprecated, please use "Life Cycles" instead, see https://www.eggjs.org/advanced/loader#life-cycles'
|
|
409
|
+
);
|
|
390
410
|
this.lifecycle.registerBeforeClose(fn, name);
|
|
391
411
|
}
|
|
392
412
|
|
|
@@ -398,7 +418,7 @@ export class EggCore extends KoaApplication {
|
|
|
398
418
|
*
|
|
399
419
|
* If error is thrown when it's closing, the promise will reject.
|
|
400
420
|
* It will also reject after following call.
|
|
401
|
-
* @
|
|
421
|
+
* @returns {Promise} promise
|
|
402
422
|
* @since 1.0.0
|
|
403
423
|
*/
|
|
404
424
|
async close(): Promise<void> {
|
|
@@ -416,25 +436,33 @@ export class EggCore extends KoaApplication {
|
|
|
416
436
|
if (this.#router) {
|
|
417
437
|
return this.#router;
|
|
418
438
|
}
|
|
419
|
-
|
|
420
|
-
return router;
|
|
439
|
+
this.#router = new Router({ sensitive: true }, this);
|
|
440
|
+
return this.#router;
|
|
421
441
|
}
|
|
422
442
|
|
|
423
443
|
/**
|
|
424
444
|
* Alias to {@link Router#url}
|
|
425
445
|
* @param {String} name - Router name
|
|
426
446
|
* @param {Object} params - more parameters
|
|
427
|
-
* @
|
|
447
|
+
* @returns {String} url
|
|
428
448
|
*/
|
|
429
|
-
url(name: string, params?:
|
|
449
|
+
url(name: string, params?: Parameters<Router['url']>[1]): string {
|
|
430
450
|
return this.router.url(name, params);
|
|
431
451
|
}
|
|
432
452
|
|
|
433
453
|
// delegate all router method to application
|
|
434
454
|
// 'head', 'options', 'get', 'put', 'patch', 'post', 'delete'
|
|
435
455
|
// 'all', 'resources', 'register', 'redirect'
|
|
436
|
-
head(
|
|
437
|
-
|
|
456
|
+
head(
|
|
457
|
+
path: string | RegExp | (string | RegExp)[],
|
|
458
|
+
...middlewares: (MiddlewareFunc | string)[]
|
|
459
|
+
): EggCore;
|
|
460
|
+
head(
|
|
461
|
+
name: string,
|
|
462
|
+
path: string | RegExp | (string | RegExp)[],
|
|
463
|
+
...middlewares: (MiddlewareFunc | string)[]
|
|
464
|
+
): EggCore;
|
|
465
|
+
|
|
438
466
|
head(...args: any): EggCore {
|
|
439
467
|
this.router.head.apply(this.router, args);
|
|
440
468
|
return this;
|
|
@@ -445,68 +473,140 @@ export class EggCore extends KoaApplication {
|
|
|
445
473
|
// this.router.options.apply(this.router, args);
|
|
446
474
|
// return this;
|
|
447
475
|
// }
|
|
448
|
-
get(
|
|
449
|
-
|
|
476
|
+
get(
|
|
477
|
+
path: string | RegExp | (string | RegExp)[],
|
|
478
|
+
...middlewares: (MiddlewareFunc | string)[]
|
|
479
|
+
): EggCore;
|
|
480
|
+
get(
|
|
481
|
+
name: string,
|
|
482
|
+
path: string | RegExp | (string | RegExp)[],
|
|
483
|
+
...middlewares: (MiddlewareFunc | string)[]
|
|
484
|
+
): EggCore;
|
|
485
|
+
|
|
450
486
|
get(...args: any): EggCore {
|
|
451
487
|
this.router.get.apply(this.router, args);
|
|
452
488
|
return this;
|
|
453
489
|
}
|
|
454
|
-
put(
|
|
455
|
-
|
|
490
|
+
put(
|
|
491
|
+
path: string | RegExp | (string | RegExp)[],
|
|
492
|
+
...middlewares: (MiddlewareFunc | string)[]
|
|
493
|
+
): EggCore;
|
|
494
|
+
put(
|
|
495
|
+
name: string,
|
|
496
|
+
path: string | RegExp | (string | RegExp)[],
|
|
497
|
+
...middlewares: (MiddlewareFunc | string)[]
|
|
498
|
+
): EggCore;
|
|
499
|
+
|
|
456
500
|
put(...args: any): EggCore {
|
|
457
501
|
this.router.put.apply(this.router, args);
|
|
458
502
|
return this;
|
|
459
503
|
}
|
|
460
|
-
patch(
|
|
461
|
-
|
|
504
|
+
patch(
|
|
505
|
+
path: string | RegExp | (string | RegExp)[],
|
|
506
|
+
...middlewares: (MiddlewareFunc | string)[]
|
|
507
|
+
): EggCore;
|
|
508
|
+
patch(
|
|
509
|
+
name: string,
|
|
510
|
+
path: string | RegExp | (string | RegExp)[],
|
|
511
|
+
...middlewares: (MiddlewareFunc | string)[]
|
|
512
|
+
): EggCore;
|
|
513
|
+
|
|
462
514
|
patch(...args: any): EggCore {
|
|
463
515
|
this.router.patch.apply(this.router, args);
|
|
464
516
|
return this;
|
|
465
517
|
}
|
|
466
|
-
post(
|
|
467
|
-
|
|
518
|
+
post(
|
|
519
|
+
path: string | RegExp | (string | RegExp)[],
|
|
520
|
+
...middlewares: (MiddlewareFunc | string)[]
|
|
521
|
+
): EggCore;
|
|
522
|
+
post(
|
|
523
|
+
name: string,
|
|
524
|
+
path: string | RegExp | (string | RegExp)[],
|
|
525
|
+
...middlewares: (MiddlewareFunc | string)[]
|
|
526
|
+
): EggCore;
|
|
527
|
+
|
|
468
528
|
post(...args: any): EggCore {
|
|
469
529
|
this.router.post.apply(this.router, args);
|
|
470
530
|
return this;
|
|
471
531
|
}
|
|
472
|
-
delete(
|
|
473
|
-
|
|
532
|
+
delete(
|
|
533
|
+
path: string | RegExp | (string | RegExp)[],
|
|
534
|
+
...middlewares: (MiddlewareFunc | string)[]
|
|
535
|
+
): EggCore;
|
|
536
|
+
delete(
|
|
537
|
+
name: string,
|
|
538
|
+
path: string | RegExp | (string | RegExp)[],
|
|
539
|
+
...middlewares: (MiddlewareFunc | string)[]
|
|
540
|
+
): EggCore;
|
|
541
|
+
|
|
474
542
|
delete(...args: any): EggCore {
|
|
475
543
|
this.router.delete.apply(this.router, args);
|
|
476
544
|
return this;
|
|
477
545
|
}
|
|
478
|
-
del(
|
|
479
|
-
|
|
546
|
+
del(
|
|
547
|
+
path: string | RegExp | (string | RegExp)[],
|
|
548
|
+
...middlewares: (MiddlewareFunc | string)[]
|
|
549
|
+
): EggCore;
|
|
550
|
+
del(
|
|
551
|
+
name: string,
|
|
552
|
+
path: string | RegExp | (string | RegExp)[],
|
|
553
|
+
...middlewares: (MiddlewareFunc | string)[]
|
|
554
|
+
): EggCore;
|
|
555
|
+
|
|
480
556
|
del(...args: any): EggCore {
|
|
481
557
|
this.router.del.apply(this.router, args);
|
|
482
558
|
return this;
|
|
483
559
|
}
|
|
484
560
|
|
|
485
|
-
all(
|
|
486
|
-
|
|
561
|
+
all(
|
|
562
|
+
path: string | RegExp | (string | RegExp)[],
|
|
563
|
+
...middlewares: (MiddlewareFunc | string)[]
|
|
564
|
+
): EggCore;
|
|
565
|
+
all(
|
|
566
|
+
name: string,
|
|
567
|
+
path: string | RegExp | (string | RegExp)[],
|
|
568
|
+
...middlewares: (MiddlewareFunc | string)[]
|
|
569
|
+
): EggCore;
|
|
570
|
+
|
|
487
571
|
all(...args: any): EggCore {
|
|
488
572
|
this.router.all.apply(this.router, args);
|
|
489
573
|
return this;
|
|
490
574
|
}
|
|
491
575
|
|
|
492
576
|
resources(prefix: string, controller: string | ResourcesController): EggCore;
|
|
493
|
-
resources(
|
|
494
|
-
|
|
495
|
-
|
|
577
|
+
resources(
|
|
578
|
+
prefix: string,
|
|
579
|
+
middleware: MiddlewareFunc,
|
|
580
|
+
controller: string | ResourcesController
|
|
581
|
+
): EggCore;
|
|
582
|
+
resources(
|
|
583
|
+
name: string,
|
|
584
|
+
prefix: string,
|
|
585
|
+
controller: string | ResourcesController
|
|
586
|
+
): EggCore;
|
|
587
|
+
resources(
|
|
588
|
+
name: string,
|
|
589
|
+
prefix: string,
|
|
590
|
+
middleware: MiddlewareFunc,
|
|
591
|
+
controller: string | ResourcesController
|
|
592
|
+
): EggCore;
|
|
593
|
+
|
|
496
594
|
resources(...args: any): EggCore {
|
|
497
595
|
this.router.resources.apply(this.router, args);
|
|
498
596
|
return this;
|
|
499
597
|
}
|
|
500
598
|
|
|
501
|
-
redirect(source: string, destination: string, status
|
|
599
|
+
redirect(source: string, destination: string, status = 301) {
|
|
502
600
|
this.router.redirect(source, destination, status);
|
|
503
601
|
return this;
|
|
504
602
|
}
|
|
505
603
|
|
|
506
|
-
register(
|
|
604
|
+
register(
|
|
605
|
+
path: string | RegExp | (string | RegExp)[],
|
|
507
606
|
methods: string[],
|
|
508
607
|
middleware: MiddlewareFunc | MiddlewareFunc[],
|
|
509
|
-
opts?: RegisterOptions
|
|
608
|
+
opts?: RegisterOptions
|
|
609
|
+
) {
|
|
510
610
|
this.router.register(path, methods, middleware, opts);
|
|
511
611
|
return this;
|
|
512
612
|
}
|
package/src/lifecycle.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import assert from 'node:assert';
|
|
2
2
|
import { EventEmitter } from 'node:events';
|
|
3
3
|
import { debuglog, format } from 'node:util';
|
|
4
|
+
|
|
4
5
|
import { isClass } from 'is-type-of';
|
|
5
|
-
import { Ready as ReadyObject } from 'get-ready';
|
|
6
|
-
import type { ReadyFunctionArg } from 'get-ready';
|
|
6
|
+
import { Ready as ReadyObject, type ReadyFunctionArg } from 'get-ready';
|
|
7
7
|
import { Ready } from 'ready-callback';
|
|
8
8
|
import { EggConsoleLogger } from 'egg-logger';
|
|
9
|
+
|
|
9
10
|
import utils from './utils/index.js';
|
|
10
11
|
import type { Fun } from './utils/index.js';
|
|
11
12
|
import type { EggCore } from './egg.js';
|
|
@@ -54,7 +55,7 @@ export interface ILifecycleBoot {
|
|
|
54
55
|
beforeClose?(): Promise<void>;
|
|
55
56
|
}
|
|
56
57
|
|
|
57
|
-
export type BootImplClass<T = ILifecycleBoot> = new(...args: any[]) => T;
|
|
58
|
+
export type BootImplClass<T = ILifecycleBoot> = new (...args: any[]) => T;
|
|
58
59
|
|
|
59
60
|
export interface LifecycleOptions {
|
|
60
61
|
baseDir: string;
|
|
@@ -89,20 +90,29 @@ export class Lifecycle extends EventEmitter {
|
|
|
89
90
|
|
|
90
91
|
this.timing.start(`${this.options.app.type} Start`);
|
|
91
92
|
// get app timeout from env or use default timeout 10 second
|
|
92
|
-
const eggReadyTimeoutEnv = parseInt(
|
|
93
|
+
const eggReadyTimeoutEnv = Number.parseInt(
|
|
94
|
+
process.env.EGG_READY_TIMEOUT_ENV || '10000'
|
|
95
|
+
);
|
|
93
96
|
assert(
|
|
94
97
|
Number.isInteger(eggReadyTimeoutEnv),
|
|
95
|
-
`process.env.EGG_READY_TIMEOUT_ENV ${process.env.EGG_READY_TIMEOUT_ENV} should be able to parseInt.`
|
|
98
|
+
`process.env.EGG_READY_TIMEOUT_ENV ${process.env.EGG_READY_TIMEOUT_ENV} should be able to parseInt.`
|
|
99
|
+
);
|
|
96
100
|
this.readyTimeout = eggReadyTimeoutEnv;
|
|
97
101
|
|
|
98
102
|
this.#initReady();
|
|
99
|
-
this
|
|
100
|
-
.
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
103
|
+
this.on('ready_stat', data => {
|
|
104
|
+
this.logger.info(
|
|
105
|
+
'[@eggjs/core/lifecycle:ready_stat] end ready task %s, remain %j',
|
|
106
|
+
data.id,
|
|
107
|
+
data.remain
|
|
108
|
+
);
|
|
109
|
+
}).on('ready_timeout', id => {
|
|
110
|
+
this.logger.warn(
|
|
111
|
+
'[@eggjs/core/lifecycle:ready_timeout] %s seconds later %s was still unable to finish.',
|
|
112
|
+
this.readyTimeout / 1000,
|
|
113
|
+
id
|
|
114
|
+
);
|
|
115
|
+
});
|
|
106
116
|
|
|
107
117
|
this.ready(err => {
|
|
108
118
|
this.triggerDidReady(err);
|
|
@@ -136,10 +146,12 @@ export class Lifecycle extends EventEmitter {
|
|
|
136
146
|
const timingKeyPrefix = 'readyCallback';
|
|
137
147
|
const timing = this.timing;
|
|
138
148
|
const cb = this.loadReady.readyCallback(name, opt);
|
|
139
|
-
const timingKey =
|
|
149
|
+
const timingKey =
|
|
150
|
+
`${timingKeyPrefix} in ` +
|
|
151
|
+
utils.getResolvedFilename(name, this.app.baseDir);
|
|
140
152
|
this.timing.start(timingKey);
|
|
141
153
|
debug('register legacyReadyCallback');
|
|
142
|
-
return function legacyReadyCallback(...args:
|
|
154
|
+
return function legacyReadyCallback(...args: unknown[]) {
|
|
143
155
|
timing.end(timingKey);
|
|
144
156
|
debug('end legacyReadyCallback');
|
|
145
157
|
cb(...args);
|
|
@@ -147,12 +159,21 @@ export class Lifecycle extends EventEmitter {
|
|
|
147
159
|
}
|
|
148
160
|
|
|
149
161
|
addBootHook(bootHootOrBootClass: BootImplClass | ILifecycleBoot) {
|
|
150
|
-
assert(
|
|
162
|
+
assert(
|
|
163
|
+
this.#init === false,
|
|
164
|
+
'do not add hook when lifecycle has been initialized'
|
|
165
|
+
);
|
|
151
166
|
this.#bootHooks.push(bootHootOrBootClass);
|
|
152
167
|
}
|
|
153
168
|
|
|
154
|
-
addFunctionAsBootHook<T = EggCore>(
|
|
155
|
-
|
|
169
|
+
addFunctionAsBootHook<T = EggCore>(
|
|
170
|
+
hook: (app: T) => void,
|
|
171
|
+
fullPath?: string
|
|
172
|
+
) {
|
|
173
|
+
assert(
|
|
174
|
+
this.#init === false,
|
|
175
|
+
'do not add hook when lifecycle has been initialized'
|
|
176
|
+
);
|
|
156
177
|
// app.js is exported as a function
|
|
157
178
|
// call this function in configDidLoad
|
|
158
179
|
class Boot implements ILifecycleBoot {
|
|
@@ -190,8 +211,7 @@ export class Lifecycle extends EventEmitter {
|
|
|
190
211
|
}
|
|
191
212
|
|
|
192
213
|
registerBeforeStart(scope: Fun, name: string) {
|
|
193
|
-
debug('%s add registerBeforeStart, name: %o',
|
|
194
|
-
this.options.app.type, name);
|
|
214
|
+
debug('%s add registerBeforeStart, name: %o', this.options.app.type, name);
|
|
195
215
|
this.#registerReadyCallback({
|
|
196
216
|
scope,
|
|
197
217
|
ready: this.loadReady,
|
|
@@ -207,15 +227,22 @@ export class Lifecycle extends EventEmitter {
|
|
|
207
227
|
fn.fullPath = fullPath;
|
|
208
228
|
}
|
|
209
229
|
this.#closeFunctionSet.add(fn);
|
|
210
|
-
debug(
|
|
211
|
-
|
|
230
|
+
debug(
|
|
231
|
+
'%s register beforeClose at %o, count: %d',
|
|
232
|
+
this.app.type,
|
|
233
|
+
fullPath,
|
|
234
|
+
this.#closeFunctionSet.size
|
|
235
|
+
);
|
|
212
236
|
}
|
|
213
237
|
|
|
214
238
|
async close() {
|
|
215
239
|
// close in reverse order: first created, last closed
|
|
216
240
|
const closeFns = Array.from(this.#closeFunctionSet);
|
|
217
|
-
debug(
|
|
218
|
-
|
|
241
|
+
debug(
|
|
242
|
+
'%s start trigger %d beforeClose functions',
|
|
243
|
+
this.app.type,
|
|
244
|
+
closeFns.length
|
|
245
|
+
);
|
|
219
246
|
for (const fn of closeFns.reverse()) {
|
|
220
247
|
debug('%s trigger beforeClose at %o', this.app.type, fn.fullPath);
|
|
221
248
|
await utils.callFn(fn);
|
|
@@ -301,7 +328,11 @@ export class Lifecycle extends EventEmitter {
|
|
|
301
328
|
try {
|
|
302
329
|
await boot.didReady(err);
|
|
303
330
|
} catch (err) {
|
|
304
|
-
debug(
|
|
331
|
+
debug(
|
|
332
|
+
'trigger didReady error at %o, error: %s',
|
|
333
|
+
boot.fullPath,
|
|
334
|
+
err
|
|
335
|
+
);
|
|
305
336
|
this.emit('error', err);
|
|
306
337
|
}
|
|
307
338
|
}
|
|
@@ -321,7 +352,11 @@ export class Lifecycle extends EventEmitter {
|
|
|
321
352
|
try {
|
|
322
353
|
await boot.serverDidReady();
|
|
323
354
|
} catch (err) {
|
|
324
|
-
debug(
|
|
355
|
+
debug(
|
|
356
|
+
'trigger serverDidReady error at %o, error: %s',
|
|
357
|
+
boot.fullPath,
|
|
358
|
+
err
|
|
359
|
+
);
|
|
325
360
|
this.emit('error', err);
|
|
326
361
|
}
|
|
327
362
|
}
|
|
@@ -355,8 +390,8 @@ export class Lifecycle extends EventEmitter {
|
|
|
355
390
|
|
|
356
391
|
#delegateReadyEvent(ready: Ready) {
|
|
357
392
|
ready.once('error', (err?: Error) => ready.ready(err));
|
|
358
|
-
ready.on('ready_timeout', (id:
|
|
359
|
-
ready.on('ready_stat', (data:
|
|
393
|
+
ready.on('ready_timeout', (id: unknown) => this.emit('ready_timeout', id));
|
|
394
|
+
ready.on('ready_stat', (data: unknown) => this.emit('ready_stat', data));
|
|
360
395
|
ready.on('error', (err?: Error) => this.emit('error', err));
|
|
361
396
|
}
|
|
362
397
|
|
|
@@ -368,12 +403,14 @@ export class Lifecycle extends EventEmitter {
|
|
|
368
403
|
}) {
|
|
369
404
|
const { scope, ready, timingKeyPrefix, scopeFullName } = args;
|
|
370
405
|
if (typeof scope !== 'function') {
|
|
371
|
-
throw new
|
|
406
|
+
throw new TypeError('boot only support function');
|
|
372
407
|
}
|
|
373
408
|
|
|
374
409
|
// get filename from stack if scopeFullName is undefined
|
|
375
410
|
const name = scopeFullName || utils.getCalleeFromStack(true, 4);
|
|
376
|
-
const timingKey =
|
|
411
|
+
const timingKey =
|
|
412
|
+
`${timingKeyPrefix} in ` +
|
|
413
|
+
utils.getResolvedFilename(name, this.app.baseDir);
|
|
377
414
|
|
|
378
415
|
this.timing.start(timingKey);
|
|
379
416
|
|
|
@@ -381,19 +418,21 @@ export class Lifecycle extends EventEmitter {
|
|
|
381
418
|
const done = ready.readyCallback(name);
|
|
382
419
|
|
|
383
420
|
// ensure scope executes after load completed
|
|
384
|
-
process.nextTick(() => {
|
|
385
|
-
|
|
421
|
+
process.nextTick(async () => {
|
|
422
|
+
try {
|
|
423
|
+
await utils.callFn(scope);
|
|
386
424
|
debug('[registerReadyCallback] end name: %o', name);
|
|
387
425
|
done();
|
|
388
426
|
this.timing.end(timingKey);
|
|
389
|
-
}
|
|
427
|
+
} catch (e) {
|
|
428
|
+
let err = e as Error;
|
|
390
429
|
// avoid non-stringify error: TypeError: Cannot convert object to primitive value
|
|
391
430
|
if (!(err instanceof Error)) {
|
|
392
431
|
err = new Error(format('%s', err));
|
|
393
432
|
}
|
|
394
433
|
done(err);
|
|
395
434
|
this.timing.end(timingKey);
|
|
396
|
-
}
|
|
435
|
+
}
|
|
397
436
|
});
|
|
398
437
|
}
|
|
399
438
|
}
|
|
@@ -38,7 +38,8 @@ export class ClassLoader {
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
export interface ContextLoaderOptions
|
|
41
|
+
export interface ContextLoaderOptions
|
|
42
|
+
extends Omit<FileLoaderOptions, 'target'> {
|
|
42
43
|
/** required inject */
|
|
43
44
|
inject: Record<string, any>;
|
|
44
45
|
/** property name defined to target */
|
|
@@ -71,14 +72,14 @@ export class ContextLoader extends FileLoader {
|
|
|
71
72
|
...options,
|
|
72
73
|
target,
|
|
73
74
|
});
|
|
74
|
-
this.#inject = this.options.inject
|
|
75
|
+
this.#inject = this.options.inject as Record<string, any>;
|
|
75
76
|
|
|
76
77
|
const app = this.#inject;
|
|
77
78
|
const property = options.property;
|
|
78
79
|
// define ctx.service
|
|
79
80
|
Object.defineProperty(app.context, property, {
|
|
80
81
|
get() {
|
|
81
|
-
//
|
|
82
|
+
// oxlint-disable-next-line unicorn/no-this-assignment, typescript/no-this-alias
|
|
82
83
|
const ctx = this;
|
|
83
84
|
// distinguish property cache,
|
|
84
85
|
// cache's lifecycle is the same with this context instance
|
|
@@ -86,11 +87,12 @@ export class ContextLoader extends FileLoader {
|
|
|
86
87
|
if (!ctx[CLASS_LOADER]) {
|
|
87
88
|
ctx[CLASS_LOADER] = new Map();
|
|
88
89
|
}
|
|
89
|
-
const classLoader: Map<string | symbol, ClassLoader> =
|
|
90
|
+
const classLoader: Map<string | symbol, ClassLoader> =
|
|
91
|
+
ctx[CLASS_LOADER];
|
|
90
92
|
let instance = classLoader.get(property);
|
|
91
93
|
if (!instance) {
|
|
92
94
|
instance = getInstance(target, ctx);
|
|
93
|
-
classLoader.set(property, instance
|
|
95
|
+
classLoader.set(property, instance as ClassLoader);
|
|
94
96
|
}
|
|
95
97
|
return instance;
|
|
96
98
|
},
|
|
@@ -110,8 +112,8 @@ function getInstance(values: any, ctx: Context) {
|
|
|
110
112
|
// it's just an object
|
|
111
113
|
instance = Class;
|
|
112
114
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
+
// Can't set property to primitive, so check again
|
|
116
|
+
// e.x. module.exports = 1;
|
|
115
117
|
} else if (isPrimitive(values)) {
|
|
116
118
|
instance = values;
|
|
117
119
|
} else {
|