Skip to content

Commit 1f858c0

Browse files
committed
feat: add LifecyclePreLoad
1 parent 27fd9ff commit 1f858c0

File tree

11 files changed

+173
-13
lines changed

11 files changed

+173
-13
lines changed

core/lifecycle/src/LifycycleUtil.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,4 +98,9 @@ export class LifecycleUtil<T extends LifecycleContext, R extends LifecycleObject
9898
const LIFECYCLE_HOOK = Symbol.for(`EggPrototype#Lifecycle${hookName}`);
9999
return proto.getMetaData<string>(LIFECYCLE_HOOK);
100100
}
101+
102+
static getStaticLifecycleHook(hookName: LifecycleHookName, clazz: EggProtoImplClass) {
103+
const LIFECYCLE_HOOK = Symbol.for(`EggPrototype#Lifecycle${hookName}`);
104+
return MetadataUtil.getMetaData<string>(LIFECYCLE_HOOK, clazz);
105+
}
101106
}

core/lifecycle/src/decorator/index.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,22 @@ function createLifecycle(hookName: LifecycleHookName) {
1010
};
1111
}
1212

13+
function createStaticLifecycle(hookName: LifecycleHookName) {
14+
return () => {
15+
return function(target: EggProtoImplClass, methodName: string) {
16+
if (typeof target !== 'function') {
17+
throw new Error(`${hookName} must be a static function`);
18+
}
19+
LifecycleUtil.setLifecycleHook(methodName, hookName, target);
20+
};
21+
};
22+
}
23+
24+
1325
export const LifecyclePostConstruct = createLifecycle('postConstruct');
1426
export const LifecyclePreInject = createLifecycle('preInject');
1527
export const LifecyclePostInject = createLifecycle('postInject');
1628
export const LifecycleInit = createLifecycle('init');
1729
export const LifecyclePreDestroy = createLifecycle('preDestroy');
1830
export const LifecycleDestroy = createLifecycle('destroy');
31+
export const LifecyclePreLoad = createStaticLifecycle('preLoad');

core/metadata/src/impl/ModuleLoadUnit.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import type {
1919
import { Graph, GraphNode, MapUtil } from '@eggjs/tegg-common-util';
2020
import { PrototypeUtil, QualifierUtil } from '@eggjs/core-decorator';
2121
import { FrameworkErrorFormater } from 'egg-errors';
22-
import { IdenticalUtil } from '@eggjs/tegg-lifecycle';
22+
import { IdenticalUtil, LifecycleUtil } from '@eggjs/tegg-lifecycle';
2323
import { EggPrototypeFactory } from '../factory/EggPrototypeFactory';
2424
import { LoadUnitFactory } from '../factory/LoadUnitFactory';
2525
import { EggPrototypeCreatorFactory } from '../factory/EggPrototypeCreatorFactory';
@@ -182,6 +182,16 @@ export class ModuleLoadUnit implements LoadUnit {
182182
return clazzList;
183183
}
184184

185+
async preLoad() {
186+
const clazzList = this.loader.load();
187+
for (const protoClass of clazzList) {
188+
const fnName = LifecycleUtil.getStaticLifecycleHook('preLoad', protoClass);
189+
if (fnName) {
190+
await protoClass[fnName]?.();
191+
}
192+
}
193+
}
194+
185195
async init() {
186196
const clazzList = this.loadClazz();
187197
const protoGraph = new ModuleGraph(clazzList, this.unitPath, this.name);

core/types/lifecycle/EggObjectLifecycle.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ import type { EggObject, EggObjectLifeCycleContext } from '@eggjs/tegg-runtime';
44
* lifecycle hook interface for egg object
55
*/
66
export interface EggObjectLifecycle {
7+
/**
8+
* call before project load
9+
*/
10+
preLoad?(ctx: EggObjectLifeCycleContext): Promise<void>;
711
/**
812
* call after construct
913
*/

core/types/lifecycle/LifecycleHook.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export interface LifecycleContext {
44
}
55

66
export interface LifecycleObject<T extends LifecycleContext> extends IdenticalObject {
7+
preLoad?(): Promise<void>;
78
init?(ctx: T): Promise<void>;
89
destroy?(ctx: T): Promise<void>;
910
}

standalone/standalone/src/EggModuleLoader.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ export class EggModuleLoader {
1010
this.moduleReferences = moduleReferences;
1111
}
1212

13-
private buildAppGraph(loaderCache: Map<string, Loader>) {
13+
private static buildAppGraph(loaderCache: Map<string, Loader>, moduleReferences: readonly ModuleReference[]) {
1414
const appGraph = new AppGraph();
15-
for (const moduleConfig of this.moduleReferences) {
15+
for (const moduleConfig of moduleReferences) {
1616
const modulePath = moduleConfig.path;
1717
const moduleNode = new ModuleNode(moduleConfig);
1818
const loader = LoaderFactory.createLoader(modulePath, EggLoadUnitType.MODULE);
@@ -27,10 +27,10 @@ export class EggModuleLoader {
2727
return appGraph;
2828
}
2929

30-
async load(): Promise<LoadUnit[]> {
30+
private static async load(moduleReferences: readonly ModuleReference[]): Promise<LoadUnit[]> {
3131
const loadUnits: LoadUnit[] = [];
3232
const loaderCache = new Map<string, Loader>();
33-
const appGraph = this.buildAppGraph(loaderCache);
33+
const appGraph = EggModuleLoader.buildAppGraph(loaderCache, moduleReferences);
3434
appGraph.sort();
3535
const moduleConfigList = appGraph.moduleConfigList;
3636
for (const moduleConfig of moduleConfigList) {
@@ -40,6 +40,16 @@ export class EggModuleLoader {
4040
loadUnits.push(loadUnit);
4141
}
4242
return loadUnits;
43-
// return loadUnits;
43+
}
44+
45+
async load(): Promise<LoadUnit[]> {
46+
return await EggModuleLoader.load(this.moduleReferences);
47+
}
48+
49+
static async preLoad(moduleReferences: readonly ModuleReference[]): Promise<void> {
50+
const loads = await EggModuleLoader.load(moduleReferences);
51+
for (const load of loads) {
52+
await load.preLoad?.();
53+
}
4454
}
4555
}

standalone/standalone/src/Runner.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,7 @@ export class Runner {
8585
this.cwd = cwd;
8686
this.env = options?.env;
8787
this.name = options?.name;
88-
const moduleDirs = (options?.dependencies || []).concat(this.cwd);
89-
this.moduleReferences = moduleDirs.reduce((list, baseDir) => {
90-
const module = typeof baseDir === 'string' ? { baseDir } : baseDir;
91-
return list.concat(...ModuleConfigUtil.readModuleReference(module.baseDir, module));
92-
}, [] as readonly ModuleReference[]);
88+
this.moduleReferences = Runner.getModuleReferences(this.cwd, options?.dependencies);
9389
this.moduleConfigs = {};
9490
this.innerObjects = {
9591
moduleConfigs: [{
@@ -189,6 +185,19 @@ export class Runner {
189185
return [ standaloneLoadUnit, ...loadUnits ];
190186
}
191187

188+
static getModuleReferences(cwd: string, dependencies?: RunnerOptions['dependencies']) {
189+
const moduleDirs = (dependencies || []).concat(cwd);
190+
return moduleDirs.reduce((list, baseDir) => {
191+
const module = typeof baseDir === 'string' ? { baseDir } : baseDir;
192+
return list.concat(...ModuleConfigUtil.readModuleReference(module.baseDir, module));
193+
}, [] as readonly ModuleReference[]);
194+
}
195+
196+
static async preLoad(cwd: string, dependencies?: RunnerOptions['dependencies']) {
197+
const moduleReferences = Runner.getModuleReferences(cwd, dependencies);
198+
await EggModuleLoader.preLoad(moduleReferences);
199+
}
200+
192201
async init() {
193202
this.loadUnits = await this.load();
194203
const instances: LoadUnitInstance[] = [];

standalone/standalone/src/main.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
import { Runner, RunnerOptions } from './Runner';
22

3+
export async function preLoad(cwd: string, dependencies?: RunnerOptions['dependencies']) {
4+
try {
5+
await Runner.preLoad(cwd, dependencies);
6+
} catch (e) {
7+
e.message = `[tegg/standalone] bootstrap standalone preLoad failed: ${e.message}`;
8+
throw e;
9+
}
10+
}
11+
312
export async function main<T = void>(cwd: string, options?: RunnerOptions): Promise<T> {
413
const runner = new Runner(cwd, options);
514
try {
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import {
2+
SingletonProto,
3+
LifecyclePreLoad,
4+
LifecyclePostConstruct,
5+
LifecyclePreInject,
6+
LifecyclePostInject,
7+
LifecycleInit,
8+
LifecyclePreDestroy,
9+
LifecycleDestroy,
10+
} from '@eggjs/tegg';
11+
import { Runner, MainRunner } from '@eggjs/tegg/standalone';
12+
13+
@Runner()
14+
@SingletonProto()
15+
export class Foo implements MainRunner<string[]> {
16+
17+
static staticCalled: string[] = [];
18+
19+
getLifecycleCalled() {
20+
return Foo.staticCalled;
21+
}
22+
23+
@LifecyclePreLoad()
24+
static async _preLoad() {
25+
Foo.staticCalled.push('preLoad');
26+
}
27+
28+
constructor() {
29+
Foo.staticCalled.push('construct');
30+
}
31+
32+
@LifecyclePostConstruct()
33+
protected async _postConstruct() {
34+
Foo.staticCalled.push('postConstruct');
35+
}
36+
37+
@LifecyclePreInject()
38+
protected async _preInject() {
39+
Foo.staticCalled.push('preInject');
40+
}
41+
42+
@LifecyclePostInject()
43+
protected async _postInject() {
44+
Foo.staticCalled.push('postInject');
45+
}
46+
47+
protected async init() {
48+
Foo.staticCalled.push('init should not called');
49+
}
50+
51+
@LifecycleInit()
52+
protected async _init() {
53+
Foo.staticCalled.push('init');
54+
}
55+
56+
@LifecyclePreDestroy()
57+
protected async _preDestroy() {
58+
Foo.staticCalled.push('preDestroy');
59+
}
60+
61+
@LifecycleDestroy()
62+
protected async _destroy() {
63+
Foo.staticCalled.push('destroy');
64+
}
65+
66+
async main(): Promise<string[]> {
67+
return Foo.staticCalled;
68+
}
69+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"name": "lifecycle",
3+
"eggModule": {
4+
"name": "lifecycle"
5+
}
6+
}

0 commit comments

Comments
 (0)