@eggjs/core 7.0.2-beta.2 → 7.0.2-beta.22
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/dist/egg.d.ts +25 -0
- package/dist/egg.js +21 -2
- package/dist/index.d.ts +5 -1
- package/dist/index.js +6 -1
- package/dist/lifecycle.d.ts +62 -1
- package/dist/lifecycle.js +131 -8
- package/dist/loader/egg_loader.d.ts +15 -0
- package/dist/loader/egg_loader.js +195 -17
- package/dist/loader/file_loader.d.ts +10 -3
- package/dist/loader/file_loader.js +18 -10
- package/dist/loader/loader_fs.d.ts +17 -0
- package/dist/loader/loader_fs.js +271 -0
- package/dist/loader/manifest.d.ts +98 -0
- package/dist/loader/manifest.js +341 -0
- package/package.json +23 -16
package/dist/egg.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { Timing } from "./utils/timing.js";
|
|
|
4
4
|
import { Lifecycle } from "./lifecycle.js";
|
|
5
5
|
import { EggAppConfig } from "./types.js";
|
|
6
6
|
import { EggLoader } from "./loader/egg_loader.js";
|
|
7
|
+
import { LoaderFS } from "./loader/loader_fs.js";
|
|
7
8
|
import { SingletonCreateMethod } from "./singleton.js";
|
|
8
9
|
import { Application as KoaApplication, Context as KoaContext, MiddlewareFunc as KoaMiddlewareFunc, Next, Request as KoaRequest, Response as KoaResponse } from "@eggjs/koa";
|
|
9
10
|
import { EggRouter as Router, RegisterOptions, ResourcesController } from "@eggjs/router";
|
|
@@ -18,6 +19,18 @@ interface EggCoreOptions {
|
|
|
18
19
|
plugins?: any;
|
|
19
20
|
serverScope?: string;
|
|
20
21
|
env?: string;
|
|
22
|
+
/** Skip lifecycle hooks, only trigger loadMetadata for manifest generation */
|
|
23
|
+
metadataOnly?: boolean;
|
|
24
|
+
/** Loader-facing filesystem abstraction */
|
|
25
|
+
loaderFS?: LoaderFS;
|
|
26
|
+
/**
|
|
27
|
+
* When true, lifecycle stops after the `configWillLoad` phase.
|
|
28
|
+
* `configDidLoad`, `didLoad`, `willReady`, `didReady`, and `serverDidReady`
|
|
29
|
+
* are skipped. Used for V8 startup snapshot construction — SDKs typically
|
|
30
|
+
* execute during `configDidLoad`, opening connections and starting timers
|
|
31
|
+
* which are not serializable. Analogous to `metadataOnly` mode.
|
|
32
|
+
*/
|
|
33
|
+
snapshot?: boolean;
|
|
21
34
|
}
|
|
22
35
|
type EggCoreInitOptions = Partial<EggCoreOptions>;
|
|
23
36
|
declare class Request$1 extends KoaRequest {
|
|
@@ -197,6 +210,18 @@ declare class EggCore extends KoaApplication {
|
|
|
197
210
|
*/
|
|
198
211
|
beforeClose(fn: Fun, name?: string): void;
|
|
199
212
|
/**
|
|
213
|
+
* Trigger snapshotWillSerialize lifecycle hooks on all boots in reverse order.
|
|
214
|
+
* Called by the build script before V8 serializes the heap.
|
|
215
|
+
* Cleans up non-serializable resources: file handles, timers, listeners, connections.
|
|
216
|
+
*/
|
|
217
|
+
triggerSnapshotWillSerialize(): Promise<void>;
|
|
218
|
+
/**
|
|
219
|
+
* Trigger snapshotDidDeserialize lifecycle hooks on all boots in forward order.
|
|
220
|
+
* Called by the restore entry after V8 deserializes the heap.
|
|
221
|
+
* Restores non-serializable resources and resumes the lifecycle from configDidLoad.
|
|
222
|
+
*/
|
|
223
|
+
triggerSnapshotDidDeserialize(): Promise<void>;
|
|
224
|
+
/**
|
|
200
225
|
* Close all, it will close
|
|
201
226
|
* - callbacks registered by beforeClose
|
|
202
227
|
* - emit `close` event
|
package/dist/egg.js
CHANGED
|
@@ -107,7 +107,8 @@ var EggCore = class EggCore extends KoaApplication {
|
|
|
107
107
|
this.lifecycle = new Lifecycle({
|
|
108
108
|
baseDir: options.baseDir,
|
|
109
109
|
app: this,
|
|
110
|
-
logger: this.console
|
|
110
|
+
logger: this.console,
|
|
111
|
+
snapshot: options.snapshot
|
|
111
112
|
});
|
|
112
113
|
this.lifecycle.on("error", (err) => this.emit("error", err));
|
|
113
114
|
this.lifecycle.on("ready_timeout", (id) => this.emit("ready_timeout", id));
|
|
@@ -130,7 +131,9 @@ var EggCore = class EggCore extends KoaApplication {
|
|
|
130
131
|
logger: this.console,
|
|
131
132
|
serverScope: options.serverScope,
|
|
132
133
|
env: options.env ?? "",
|
|
133
|
-
EggCoreClass: EggCore
|
|
134
|
+
EggCoreClass: EggCore,
|
|
135
|
+
metadataOnly: options.metadataOnly,
|
|
136
|
+
loaderFS: options.loaderFS
|
|
134
137
|
});
|
|
135
138
|
}
|
|
136
139
|
get logger() {
|
|
@@ -274,6 +277,22 @@ var EggCore = class EggCore extends KoaApplication {
|
|
|
274
277
|
this.lifecycle.registerBeforeClose(fn, name);
|
|
275
278
|
}
|
|
276
279
|
/**
|
|
280
|
+
* Trigger snapshotWillSerialize lifecycle hooks on all boots in reverse order.
|
|
281
|
+
* Called by the build script before V8 serializes the heap.
|
|
282
|
+
* Cleans up non-serializable resources: file handles, timers, listeners, connections.
|
|
283
|
+
*/
|
|
284
|
+
async triggerSnapshotWillSerialize() {
|
|
285
|
+
return this.lifecycle.triggerSnapshotWillSerialize();
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Trigger snapshotDidDeserialize lifecycle hooks on all boots in forward order.
|
|
289
|
+
* Called by the restore entry after V8 deserializes the heap.
|
|
290
|
+
* Restores non-serializable resources and resumes the lifecycle from configDidLoad.
|
|
291
|
+
*/
|
|
292
|
+
async triggerSnapshotDidDeserialize() {
|
|
293
|
+
return this.lifecycle.triggerSnapshotDidDeserialize();
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
277
296
|
* Close all, it will close
|
|
278
297
|
* - callbacks registered by beforeClose
|
|
279
298
|
* - emit `close` event
|
package/dist/index.d.ts
CHANGED
|
@@ -3,10 +3,14 @@ import { BaseContextClass } from "./base_context_class.js";
|
|
|
3
3
|
import { Timing, TimingItem } from "./utils/timing.js";
|
|
4
4
|
import { BootImplClass, FunWithFullPath, ILifecycleBoot, Lifecycle, LifecycleOptions } from "./lifecycle.js";
|
|
5
5
|
import { CustomLoaderConfigItem, EggAppConfig, EggAppInfo, EggPluginInfo } from "./types.js";
|
|
6
|
+
import { ManifestGenerateOptions, ManifestInvalidation, ManifestStore, StartupManifest } from "./loader/manifest.js";
|
|
6
7
|
import { CaseStyle, CaseStyleFunction, EXPORTS, FULLPATH, FileLoader, FileLoaderFilter, FileLoaderInitializer, FileLoaderOptions, FileLoaderParseItem } from "./loader/file_loader.js";
|
|
7
8
|
import { ClassLoader, ClassLoaderOptions, ContextLoader, ContextLoaderOptions } from "./loader/context_loader.js";
|
|
8
9
|
import { EggDirInfo, EggDirInfoType, EggLoader, EggLoaderOptions } from "./loader/egg_loader.js";
|
|
10
|
+
import { ManifestLoaderFS } from "./loader/loader_fs.js";
|
|
9
11
|
import { Singleton, SingletonCreateMethod, SingletonOptions } from "./singleton.js";
|
|
10
12
|
import { Context, EGG_LOADER, EggCore, EggCoreInitOptions, EggCoreOptions, KoaApplication, KoaContext, KoaMiddlewareFunc, KoaRequest, KoaResponse, MiddlewareFunc, Next, Request, Response, Router } from "./egg.js";
|
|
11
13
|
import { SequencifyResult, SequencifyTask, sequencify } from "./utils/sequencify.js";
|
|
12
|
-
|
|
14
|
+
import "@eggjs/typings/global";
|
|
15
|
+
export * from "@eggjs/loader-fs";
|
|
16
|
+
export { BaseContextClass, BootImplClass, CaseStyle, CaseStyleFunction, ClassLoader, ClassLoaderOptions, Context, ContextLoader, ContextLoaderOptions, CustomLoaderConfigItem, EGG_LOADER, EXPORTS, EggAppConfig, EggAppInfo, EggCore, EggCoreInitOptions, EggCoreOptions, EggDirInfo, EggDirInfoType, EggLoader, EggLoaderOptions, EggPluginInfo, FULLPATH, FileLoader, FileLoaderFilter, FileLoaderInitializer, FileLoaderOptions, FileLoaderParseItem, FunWithFullPath, ILifecycleBoot, KoaApplication, KoaContext, KoaMiddlewareFunc, KoaRequest, KoaResponse, Lifecycle, LifecycleOptions, ManifestGenerateOptions, ManifestInvalidation, ManifestLoaderFS, ManifestStore, MiddlewareFunc, Next, Request, Response, Router, SequencifyResult, SequencifyTask, Singleton, SingletonCreateMethod, SingletonOptions, StartupManifest, Timing, TimingItem, sequencify, utils };
|
package/dist/index.js
CHANGED
|
@@ -5,8 +5,13 @@ import { sequencify } from "./utils/sequencify.js";
|
|
|
5
5
|
import { Timing } from "./utils/timing.js";
|
|
6
6
|
import { CaseStyle, EXPORTS, FULLPATH, FileLoader } from "./loader/file_loader.js";
|
|
7
7
|
import { ClassLoader, ContextLoader } from "./loader/context_loader.js";
|
|
8
|
+
import { ManifestStore } from "./loader/manifest.js";
|
|
8
9
|
import { EggLoader } from "./loader/egg_loader.js";
|
|
9
10
|
import { Singleton } from "./singleton.js";
|
|
10
11
|
import { Context, EGG_LOADER, EggCore, KoaApplication, KoaContext, KoaRequest, KoaResponse, Request, Response, Router } from "./egg.js";
|
|
12
|
+
import { ManifestLoaderFS } from "./loader/loader_fs.js";
|
|
13
|
+
import "@eggjs/typings/global";
|
|
11
14
|
|
|
12
|
-
export
|
|
15
|
+
export * from "@eggjs/loader-fs"
|
|
16
|
+
|
|
17
|
+
export { BaseContextClass, CaseStyle, ClassLoader, Context, ContextLoader, EGG_LOADER, EXPORTS, EggCore, EggLoader, FULLPATH, FileLoader, KoaApplication, KoaContext, KoaRequest, KoaResponse, Lifecycle, ManifestLoaderFS, ManifestStore, Request, Response, Router, Singleton, Timing, sequencify, utils_default as utils };
|
package/dist/lifecycle.d.ts
CHANGED
|
@@ -40,12 +40,42 @@ interface ILifecycleBoot {
|
|
|
40
40
|
* Do some thing before app close
|
|
41
41
|
*/
|
|
42
42
|
beforeClose?(): Promise<void>;
|
|
43
|
+
/**
|
|
44
|
+
* Collect metadata for manifest generation (metadataOnly mode).
|
|
45
|
+
* Called instead of configWillLoad/configDidLoad/didLoad/willReady
|
|
46
|
+
* when the application is started with metadataOnly: true.
|
|
47
|
+
*/
|
|
48
|
+
loadMetadata?(): Promise<void> | void;
|
|
49
|
+
/**
|
|
50
|
+
* Called before V8 serializes the heap for startup snapshot.
|
|
51
|
+
* Clean up non-serializable resources: close file handles, clear timers,
|
|
52
|
+
* remove process listeners, close network connections.
|
|
53
|
+
* Executed in REVERSE registration order (like beforeClose).
|
|
54
|
+
*/
|
|
55
|
+
snapshotWillSerialize?(): Promise<void> | void;
|
|
56
|
+
/**
|
|
57
|
+
* Called after V8 deserializes the heap from a startup snapshot.
|
|
58
|
+
* Restore non-serializable resources: reopen file handles, recreate timers,
|
|
59
|
+
* re-register process listeners, reinitialize connections.
|
|
60
|
+
* Executed in FORWARD registration order (like configWillLoad).
|
|
61
|
+
* After all hooks complete, the normal lifecycle resumes from configDidLoad.
|
|
62
|
+
*/
|
|
63
|
+
snapshotDidDeserialize?(): Promise<void> | void;
|
|
43
64
|
}
|
|
44
65
|
type BootImplClass<T = ILifecycleBoot> = new (...args: any[]) => T;
|
|
45
66
|
interface LifecycleOptions {
|
|
46
67
|
baseDir: string;
|
|
47
68
|
app: EggCore;
|
|
48
69
|
logger: EggConsoleLogger;
|
|
70
|
+
/**
|
|
71
|
+
* When true, the lifecycle stops after configWillLoad phase completes.
|
|
72
|
+
* configDidLoad, didLoad, willReady, didReady, and serverDidReady hooks
|
|
73
|
+
* are NOT called. Used for V8 startup snapshot construction — SDKs
|
|
74
|
+
* typically execute during configDidLoad, opening connections and starting
|
|
75
|
+
* timers which are not serializable. The handling is analogous to
|
|
76
|
+
* metadataOnly mode: both short-circuit the lifecycle chain early.
|
|
77
|
+
*/
|
|
78
|
+
snapshot?: boolean;
|
|
49
79
|
}
|
|
50
80
|
type FunWithFullPath = Fun & {
|
|
51
81
|
fullPath?: string;
|
|
@@ -60,6 +90,18 @@ declare class Lifecycle extends EventEmitter {
|
|
|
60
90
|
ready(): Promise<void>;
|
|
61
91
|
ready(flagOrFunction: ReadyFunctionArg): void;
|
|
62
92
|
get app(): EggCore;
|
|
93
|
+
/**
|
|
94
|
+
* Whether `close()` has finished. Useful to guard lazy work (logger creation,
|
|
95
|
+
* close-hook registration) that may run after the app/agent was torn down.
|
|
96
|
+
*/
|
|
97
|
+
get isClosed(): boolean;
|
|
98
|
+
/**
|
|
99
|
+
* Whether `close()` is currently running (started but not yet finished). A
|
|
100
|
+
* close hook registered during this window would be added after the close
|
|
101
|
+
* callback snapshot is taken and would never run, so `registerBeforeClose()`
|
|
102
|
+
* also refuses registration while closing.
|
|
103
|
+
*/
|
|
104
|
+
get isClosing(): boolean;
|
|
63
105
|
get logger(): EggConsoleLogger;
|
|
64
106
|
get timing(): Timing;
|
|
65
107
|
legacyReadyCallback(name: string, opt?: object): (...args: unknown[]) => void;
|
|
@@ -70,7 +112,12 @@ declare class Lifecycle extends EventEmitter {
|
|
|
70
112
|
*/
|
|
71
113
|
init(): void;
|
|
72
114
|
registerBeforeStart(scope: Fun, name: string): void;
|
|
73
|
-
|
|
115
|
+
/**
|
|
116
|
+
* Register a function to run during `close()`. Returns `false` when the
|
|
117
|
+
* registration is refused because the app/agent is already closing or closed
|
|
118
|
+
* (the hook would never run); `true` otherwise.
|
|
119
|
+
*/
|
|
120
|
+
registerBeforeClose(fn: FunWithFullPath, fullPath?: string): boolean;
|
|
74
121
|
close(): Promise<void>;
|
|
75
122
|
triggerConfigWillLoad(): void;
|
|
76
123
|
triggerConfigDidLoad(): void;
|
|
@@ -78,6 +125,20 @@ declare class Lifecycle extends EventEmitter {
|
|
|
78
125
|
triggerWillReady(): void;
|
|
79
126
|
triggerDidReady(err?: Error): Promise<void>;
|
|
80
127
|
triggerServerDidReady(): Promise<void>;
|
|
128
|
+
triggerLoadMetadata(): Promise<void>;
|
|
129
|
+
/**
|
|
130
|
+
* Trigger snapshotWillSerialize on all boots in REVERSE order.
|
|
131
|
+
* Called by the build script before V8 serializes the heap.
|
|
132
|
+
*/
|
|
133
|
+
triggerSnapshotWillSerialize(): Promise<void>;
|
|
134
|
+
/**
|
|
135
|
+
* Trigger snapshotDidDeserialize on all boots in FORWARD order.
|
|
136
|
+
* Called by the restore entry after V8 deserializes the heap.
|
|
137
|
+
* After all hooks complete, resets the ready state and resumes the normal
|
|
138
|
+
* lifecycle from configDidLoad. The returned promise resolves when the
|
|
139
|
+
* full lifecycle (configDidLoad → didLoad → willReady) has completed.
|
|
140
|
+
*/
|
|
141
|
+
triggerSnapshotDidDeserialize(): Promise<void>;
|
|
81
142
|
}
|
|
82
143
|
//#endregion
|
|
83
144
|
export { BootImplClass, FunWithFullPath, ILifecycleBoot, Lifecycle, LifecycleOptions };
|
package/dist/lifecycle.js
CHANGED
|
@@ -15,6 +15,9 @@ var Lifecycle = class extends EventEmitter {
|
|
|
15
15
|
#bootHooks;
|
|
16
16
|
#boots;
|
|
17
17
|
#isClosed;
|
|
18
|
+
#isClosing;
|
|
19
|
+
#metadataOnly;
|
|
20
|
+
#snapshotBuilding;
|
|
18
21
|
#closeFunctionSet;
|
|
19
22
|
loadReady;
|
|
20
23
|
bootReady;
|
|
@@ -29,6 +32,9 @@ var Lifecycle = class extends EventEmitter {
|
|
|
29
32
|
this.#boots = [];
|
|
30
33
|
this.#closeFunctionSet = /* @__PURE__ */ new Set();
|
|
31
34
|
this.#isClosed = false;
|
|
35
|
+
this.#isClosing = false;
|
|
36
|
+
this.#metadataOnly = false;
|
|
37
|
+
this.#snapshotBuilding = false;
|
|
32
38
|
this.#init = false;
|
|
33
39
|
this.timing.start(`${this.options.app.type} Start`);
|
|
34
40
|
const eggReadyTimeoutEnv = Number.parseInt(process.env.EGG_READY_TIMEOUT_ENV || "10000");
|
|
@@ -41,7 +47,7 @@ var Lifecycle = class extends EventEmitter {
|
|
|
41
47
|
this.logger.warn("[egg/core/lifecycle:ready_timeout] %s seconds later %s was still unable to finish.", this.readyTimeout / 1e3, id);
|
|
42
48
|
});
|
|
43
49
|
this.ready((err) => {
|
|
44
|
-
this.triggerDidReady(err);
|
|
50
|
+
if (!this.#metadataOnly && !this.options.snapshot) this.triggerDidReady(err);
|
|
45
51
|
debug("app ready");
|
|
46
52
|
this.timing.end(`${this.options.app.type} Start`);
|
|
47
53
|
});
|
|
@@ -53,6 +59,22 @@ var Lifecycle = class extends EventEmitter {
|
|
|
53
59
|
get app() {
|
|
54
60
|
return this.options.app;
|
|
55
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Whether `close()` has finished. Useful to guard lazy work (logger creation,
|
|
64
|
+
* close-hook registration) that may run after the app/agent was torn down.
|
|
65
|
+
*/
|
|
66
|
+
get isClosed() {
|
|
67
|
+
return this.#isClosed;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Whether `close()` is currently running (started but not yet finished). A
|
|
71
|
+
* close hook registered during this window would be added after the close
|
|
72
|
+
* callback snapshot is taken and would never run, so `registerBeforeClose()`
|
|
73
|
+
* also refuses registration while closing.
|
|
74
|
+
*/
|
|
75
|
+
get isClosing() {
|
|
76
|
+
return this.#isClosing;
|
|
77
|
+
}
|
|
56
78
|
get logger() {
|
|
57
79
|
return this.options.logger;
|
|
58
80
|
}
|
|
@@ -117,20 +139,35 @@ var Lifecycle = class extends EventEmitter {
|
|
|
117
139
|
scopeFullName: name
|
|
118
140
|
});
|
|
119
141
|
}
|
|
142
|
+
/**
|
|
143
|
+
* Register a function to run during `close()`. Returns `false` when the
|
|
144
|
+
* registration is refused because the app/agent is already closing or closed
|
|
145
|
+
* (the hook would never run); `true` otherwise.
|
|
146
|
+
*/
|
|
120
147
|
registerBeforeClose(fn, fullPath) {
|
|
121
148
|
assert(typeof fn === "function", "argument should be function");
|
|
122
|
-
|
|
149
|
+
if (this.#isClosing || this.#isClosed) {
|
|
150
|
+
debug("%s skip registerBeforeClose at %o, app is closing or has been closed", this.app.type, fullPath);
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
123
153
|
if (fullPath) fn.fullPath = fullPath;
|
|
124
154
|
this.#closeFunctionSet.add(fn);
|
|
125
155
|
debug("%s register beforeClose at %o, count: %d", this.app.type, fullPath, this.#closeFunctionSet.size);
|
|
156
|
+
return true;
|
|
126
157
|
}
|
|
127
158
|
async close() {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
this.#closeFunctionSet
|
|
159
|
+
this.#isClosing = true;
|
|
160
|
+
if (this.#metadataOnly || this.#snapshotBuilding) {
|
|
161
|
+
debug("%s skip beforeClose functions in early-exit lifecycle mode", this.app.type);
|
|
162
|
+
this.#closeFunctionSet.clear();
|
|
163
|
+
} else {
|
|
164
|
+
const closeFns = Array.from(this.#closeFunctionSet);
|
|
165
|
+
debug("%s start trigger %d beforeClose functions", this.app.type, closeFns.length);
|
|
166
|
+
for (const fn of closeFns.reverse()) {
|
|
167
|
+
debug("%s trigger beforeClose at %o", this.app.type, fn.fullPath);
|
|
168
|
+
await utils_default.callFn(fn);
|
|
169
|
+
this.#closeFunctionSet.delete(fn);
|
|
170
|
+
}
|
|
134
171
|
}
|
|
135
172
|
this.app.emit("close");
|
|
136
173
|
this.removeAllListeners();
|
|
@@ -145,6 +182,12 @@ var Lifecycle = class extends EventEmitter {
|
|
|
145
182
|
boot.configWillLoad();
|
|
146
183
|
}
|
|
147
184
|
debug("trigger configWillLoad end");
|
|
185
|
+
if (this.options.snapshot) {
|
|
186
|
+
debug("snapshot mode: stopping after configWillLoad, skipping configDidLoad and later phases");
|
|
187
|
+
this.#snapshotBuilding = true;
|
|
188
|
+
this.loadReady.start();
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
148
191
|
this.triggerConfigDidLoad();
|
|
149
192
|
}
|
|
150
193
|
triggerConfigDidLoad() {
|
|
@@ -221,6 +264,85 @@ var Lifecycle = class extends EventEmitter {
|
|
|
221
264
|
debug("trigger serverDidReady end");
|
|
222
265
|
})();
|
|
223
266
|
}
|
|
267
|
+
async triggerLoadMetadata() {
|
|
268
|
+
this.#metadataOnly = true;
|
|
269
|
+
debug("trigger loadMetadata start");
|
|
270
|
+
let firstError;
|
|
271
|
+
for (const boot of this.#boots) if (typeof boot.loadMetadata === "function") {
|
|
272
|
+
debug("trigger loadMetadata at %o", boot.fullPath);
|
|
273
|
+
try {
|
|
274
|
+
await boot.loadMetadata();
|
|
275
|
+
} catch (err) {
|
|
276
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
277
|
+
if (!firstError) firstError = error;
|
|
278
|
+
debug("trigger loadMetadata error at %o, error: %s", boot.fullPath, error);
|
|
279
|
+
this.emit("error", error);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
debug("trigger loadMetadata end");
|
|
283
|
+
this.ready(firstError ?? true);
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Trigger snapshotWillSerialize on all boots in REVERSE order.
|
|
287
|
+
* Called by the build script before V8 serializes the heap.
|
|
288
|
+
*/
|
|
289
|
+
async triggerSnapshotWillSerialize() {
|
|
290
|
+
if (!this.options.snapshot) throw new Error("triggerSnapshotWillSerialize() can only be called on a snapshot-mode lifecycle");
|
|
291
|
+
debug("trigger snapshotWillSerialize start");
|
|
292
|
+
const boots = [...this.#boots].reverse();
|
|
293
|
+
for (const boot of boots) {
|
|
294
|
+
if (typeof boot.snapshotWillSerialize !== "function") continue;
|
|
295
|
+
const fullPath = boot.fullPath ?? "unknown";
|
|
296
|
+
debug("trigger snapshotWillSerialize at %o", fullPath);
|
|
297
|
+
const timingKey = `Snapshot Will Serialize in ${utils_default.getResolvedFilename(fullPath, this.app.baseDir)}`;
|
|
298
|
+
this.timing.start(timingKey);
|
|
299
|
+
try {
|
|
300
|
+
await utils_default.callFn(boot.snapshotWillSerialize.bind(boot));
|
|
301
|
+
} catch (err) {
|
|
302
|
+
debug("trigger snapshotWillSerialize error at %o, error: %s", fullPath, err);
|
|
303
|
+
this.timing.end(timingKey);
|
|
304
|
+
throw err;
|
|
305
|
+
}
|
|
306
|
+
this.timing.end(timingKey);
|
|
307
|
+
}
|
|
308
|
+
debug("trigger snapshotWillSerialize end");
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Trigger snapshotDidDeserialize on all boots in FORWARD order.
|
|
312
|
+
* Called by the restore entry after V8 deserializes the heap.
|
|
313
|
+
* After all hooks complete, resets the ready state and resumes the normal
|
|
314
|
+
* lifecycle from configDidLoad. The returned promise resolves when the
|
|
315
|
+
* full lifecycle (configDidLoad → didLoad → willReady) has completed.
|
|
316
|
+
*/
|
|
317
|
+
async triggerSnapshotDidDeserialize() {
|
|
318
|
+
if (!this.options.snapshot) throw new Error("triggerSnapshotDidDeserialize() can only be called on a snapshot-mode lifecycle");
|
|
319
|
+
debug("trigger snapshotDidDeserialize start");
|
|
320
|
+
for (const boot of this.#boots) {
|
|
321
|
+
if (typeof boot.snapshotDidDeserialize !== "function") continue;
|
|
322
|
+
const fullPath = boot.fullPath ?? "unknown";
|
|
323
|
+
debug("trigger snapshotDidDeserialize at %o", fullPath);
|
|
324
|
+
const timingKey = `Snapshot Did Deserialize in ${utils_default.getResolvedFilename(fullPath, this.app.baseDir)}`;
|
|
325
|
+
this.timing.start(timingKey);
|
|
326
|
+
try {
|
|
327
|
+
await utils_default.callFn(boot.snapshotDidDeserialize.bind(boot));
|
|
328
|
+
} catch (err) {
|
|
329
|
+
debug("trigger snapshotDidDeserialize error at %o, error: %s", fullPath, err);
|
|
330
|
+
this.timing.end(timingKey);
|
|
331
|
+
throw err;
|
|
332
|
+
}
|
|
333
|
+
this.timing.end(timingKey);
|
|
334
|
+
}
|
|
335
|
+
debug("trigger snapshotDidDeserialize end");
|
|
336
|
+
this.#snapshotBuilding = false;
|
|
337
|
+
this.#readyObject = new Ready();
|
|
338
|
+
this.#initReady();
|
|
339
|
+
this.ready((err) => {
|
|
340
|
+
this.triggerDidReady(err);
|
|
341
|
+
debug("app ready after snapshot deserialize");
|
|
342
|
+
});
|
|
343
|
+
this.triggerConfigDidLoad();
|
|
344
|
+
await this.ready();
|
|
345
|
+
}
|
|
224
346
|
#initReady() {
|
|
225
347
|
debug("loadReady init");
|
|
226
348
|
this.loadReady = new Ready$1({
|
|
@@ -232,6 +354,7 @@ var Lifecycle = class extends EventEmitter {
|
|
|
232
354
|
debug("loadReady end, err: %o", err);
|
|
233
355
|
debug("trigger didLoad end");
|
|
234
356
|
if (err) this.ready(err);
|
|
357
|
+
else if (this.#snapshotBuilding) this.ready(true);
|
|
235
358
|
else this.triggerWillReady();
|
|
236
359
|
});
|
|
237
360
|
debug("bootReady init");
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { Timing } from "../utils/timing.js";
|
|
2
2
|
import { Lifecycle } from "../lifecycle.js";
|
|
3
3
|
import { EggAppConfig, EggAppInfo, EggPluginInfo } from "../types.js";
|
|
4
|
+
import { ManifestStore, StartupManifest } from "./manifest.js";
|
|
4
5
|
import { FileLoader, FileLoaderOptions } from "./file_loader.js";
|
|
5
6
|
import { ContextLoader, ContextLoaderOptions } from "./context_loader.js";
|
|
6
7
|
import { EggCore } from "../egg.js";
|
|
7
8
|
import { Logger } from "egg-logger";
|
|
9
|
+
import { LoaderFS } from "@eggjs/loader-fs";
|
|
8
10
|
|
|
9
11
|
//#region src/loader/egg_loader.d.ts
|
|
10
12
|
interface EggLoaderOptions {
|
|
@@ -21,6 +23,10 @@ interface EggLoaderOptions {
|
|
|
21
23
|
serverScope?: string;
|
|
22
24
|
/** custom plugins */
|
|
23
25
|
plugins?: Record<string, EggPluginInfo>;
|
|
26
|
+
/** Skip lifecycle hooks, only trigger loadMetadata for manifest generation */
|
|
27
|
+
metadataOnly?: boolean;
|
|
28
|
+
/** Loader-facing filesystem abstraction */
|
|
29
|
+
loaderFS?: LoaderFS;
|
|
24
30
|
}
|
|
25
31
|
type EggDirInfoType = "app" | "plugin" | "framework";
|
|
26
32
|
interface EggDirInfo {
|
|
@@ -36,7 +42,11 @@ declare class EggLoader {
|
|
|
36
42
|
readonly serverEnv: string;
|
|
37
43
|
readonly serverScope: string;
|
|
38
44
|
readonly appInfo: EggAppInfo;
|
|
45
|
+
readonly outDir?: string;
|
|
39
46
|
dirs?: EggDirInfo[];
|
|
47
|
+
/** Startup manifest — loaded from cache or collecting for generation */
|
|
48
|
+
readonly manifest: ManifestStore;
|
|
49
|
+
readonly loaderFS: LoaderFS;
|
|
40
50
|
/**
|
|
41
51
|
* @class
|
|
42
52
|
* @param {Object} options - options
|
|
@@ -368,6 +378,11 @@ declare class EggLoader {
|
|
|
368
378
|
get ContextLoader(): typeof ContextLoader;
|
|
369
379
|
getTypeFiles(filename: string): string[];
|
|
370
380
|
resolveModule(filepath: string): string | undefined;
|
|
381
|
+
/**
|
|
382
|
+
* Generate startup manifest from collected data.
|
|
383
|
+
* Should be called after all loading phases complete.
|
|
384
|
+
*/
|
|
385
|
+
generateManifest(): StartupManifest;
|
|
371
386
|
}
|
|
372
387
|
//#endregion
|
|
373
388
|
export { EggDirInfo, EggDirInfoType, EggLoader, EggLoaderOptions };
|