@ecopages/core 0.2.0-beta.13 → 0.2.0-beta.14
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 +1 -1
- package/package.json +26 -2
- package/src/adapters/abstract/application-adapter.d.ts +27 -3
- package/src/adapters/abstract/application-adapter.js +28 -0
- package/src/adapters/abstract/server-adapter.d.ts +3 -2
- package/src/adapters/bun/create-app.d.ts +1 -1
- package/src/adapters/bun/create-app.js +23 -6
- package/src/adapters/bun/server-adapter.d.ts +9 -2
- package/src/adapters/bun/server-adapter.js +28 -4
- package/src/adapters/create-app.d.ts +1 -12
- package/src/adapters/create-app.js +0 -58
- package/src/adapters/index.d.ts +1 -1
- package/src/adapters/index.js +1 -2
- package/src/adapters/node/create-app.d.ts +1 -1
- package/src/adapters/node/create-app.js +14 -4
- package/src/adapters/node/server-adapter.d.ts +7 -1
- package/src/adapters/node/server-adapter.js +25 -3
- package/src/adapters/shared/fs-server-response-matcher.d.ts +2 -0
- package/src/adapters/shared/fs-server-response-matcher.js +39 -17
- package/src/dev/server-ready-message.d.ts +6 -0
- package/src/dev/server-ready-message.js +8 -0
- package/src/eco/README.md +11 -0
- package/src/eco/eco-declared-component.d.ts +14 -0
- package/src/eco/eco-declared-component.js +16 -0
- package/src/eco/eco.browser.js +5 -6
- package/src/eco/eco.js +5 -6
- package/src/eco/eco.types.d.ts +2 -2
- package/src/eco/page-layout-normalization.d.ts +21 -0
- package/src/eco/page-layout-normalization.js +59 -0
- package/src/errors/index.d.ts +1 -0
- package/src/errors/index.js +7 -1
- package/src/errors/undeclared-component-dependency-error.d.ts +11 -0
- package/src/errors/undeclared-component-dependency-error.js +17 -0
- package/src/route-renderer/orchestration/component-graph.js +12 -4
- package/src/route-renderer/orchestration/document-shell-render.service.d.ts +37 -1
- package/src/route-renderer/orchestration/document-shell-render.service.js +79 -13
- package/src/route-renderer/orchestration/integration-renderer.js +5 -1
- package/src/route-renderer/orchestration/layout-shell-props.service.d.ts +20 -0
- package/src/route-renderer/orchestration/layout-shell-props.service.js +31 -0
- package/src/route-renderer/orchestration/ownership-validation.service.d.ts +1 -0
- package/src/route-renderer/orchestration/ownership-validation.service.js +18 -0
- package/src/route-renderer/orchestration/route-prepared-options.builder.d.ts +3 -1
- package/src/route-renderer/orchestration/route-prepared-options.builder.js +3 -1
- package/src/route-renderer/orchestration/route-render-orchestrator.d.ts +3 -1
- package/src/route-renderer/orchestration/route-render-orchestrator.js +3 -3
- package/src/route-renderer/orchestration/string-markup-renderer.js +2 -1
- package/src/route-renderer/page-loading/component-dependency-collection.js +5 -2
- package/src/types/public-types.d.ts +51 -4
- package/src/utils/parse-cli-args.d.ts +1 -0
- package/src/utils/parse-cli-args.js +3 -0
- package/src/utils/server-utils.module.js +1 -0
- package/src/watchers/project-watcher-ignore.d.ts +11 -0
- package/src/watchers/project-watcher-ignore.js +16 -0
- package/src/watchers/project-watcher.js +2 -6
package/README.md
CHANGED
|
@@ -227,7 +227,7 @@ import { defineApiHandler, defineGroupHandler, eco } from '@ecopages/core';
|
|
|
227
227
|
```
|
|
228
228
|
|
|
229
229
|
> [!NOTE]
|
|
230
|
-
> `createApp`
|
|
230
|
+
> Use `createApp()` from `@ecopages/core/create-app` as the application entrypoint.
|
|
231
231
|
|
|
232
232
|
### Runtime Escape Hatches
|
|
233
233
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ecopages/core",
|
|
3
|
-
"version": "0.2.0-beta.
|
|
3
|
+
"version": "0.2.0-beta.14",
|
|
4
4
|
"description": "Core package for Ecopages",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ecopages",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"directory": "packages/core"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@ecopages/file-system": "0.2.0-beta.
|
|
20
|
+
"@ecopages/file-system": "0.2.0-beta.14",
|
|
21
21
|
"@ecopages/logger": "^0.2.3",
|
|
22
22
|
"@ecopages/scripts-injector": "^0.1.5",
|
|
23
23
|
"@oxc-project/runtime": "0.134.0",
|
|
@@ -62,6 +62,10 @@
|
|
|
62
62
|
"types": "./src/route-renderer/orchestration/foreign-subtree-execution.service.d.ts",
|
|
63
63
|
"default": "./src/route-renderer/orchestration/foreign-subtree-execution.service.js"
|
|
64
64
|
},
|
|
65
|
+
"./route-renderer/orchestration/document-shell-render.service": {
|
|
66
|
+
"types": "./src/route-renderer/orchestration/document-shell-render.service.d.ts",
|
|
67
|
+
"default": "./src/route-renderer/orchestration/document-shell-render.service.js"
|
|
68
|
+
},
|
|
65
69
|
"./router/navigation-coordinator": {
|
|
66
70
|
"types": "./src/router/client/navigation-coordinator.d.ts",
|
|
67
71
|
"default": "./src/router/client/navigation-coordinator.js"
|
|
@@ -75,6 +79,10 @@
|
|
|
75
79
|
"types": "./src/eco/eco.d.ts",
|
|
76
80
|
"default": "./src/eco/eco.js"
|
|
77
81
|
},
|
|
82
|
+
"./eco/page-layout-normalization": {
|
|
83
|
+
"types": "./src/eco/page-layout-normalization.d.ts",
|
|
84
|
+
"default": "./src/eco/page-layout-normalization.js"
|
|
85
|
+
},
|
|
78
86
|
"./declarations": {
|
|
79
87
|
"types": "./src/declarations.d.ts"
|
|
80
88
|
},
|
|
@@ -113,6 +121,10 @@
|
|
|
113
121
|
"types": "./src/dev/dev-client-ownership.d.ts",
|
|
114
122
|
"default": "./src/dev/dev-client-ownership.js"
|
|
115
123
|
},
|
|
124
|
+
"./dev/server-ready-message": {
|
|
125
|
+
"types": "./src/dev/server-ready-message.d.ts",
|
|
126
|
+
"default": "./src/dev/server-ready-message.js"
|
|
127
|
+
},
|
|
116
128
|
"./services/asset-processing-service": {
|
|
117
129
|
"types": "./src/services/assets/asset-processing-service/index.d.ts",
|
|
118
130
|
"default": "./src/services/assets/asset-processing-service/index.js"
|
|
@@ -243,6 +255,10 @@
|
|
|
243
255
|
"types": "./src/route-renderer/orchestration/foreign-subtree-execution.service.d.ts",
|
|
244
256
|
"default": "./src/route-renderer/orchestration/foreign-subtree-execution.service.js"
|
|
245
257
|
},
|
|
258
|
+
"./route-renderer/orchestration/document-shell-render.service.ts": {
|
|
259
|
+
"types": "./src/route-renderer/orchestration/document-shell-render.service.d.ts",
|
|
260
|
+
"default": "./src/route-renderer/orchestration/document-shell-render.service.js"
|
|
261
|
+
},
|
|
246
262
|
"./router/navigation-coordinator.ts": {
|
|
247
263
|
"types": "./src/router/client/navigation-coordinator.d.ts",
|
|
248
264
|
"default": "./src/router/client/navigation-coordinator.js"
|
|
@@ -256,6 +272,10 @@
|
|
|
256
272
|
"types": "./src/eco/eco.d.ts",
|
|
257
273
|
"default": "./src/eco/eco.js"
|
|
258
274
|
},
|
|
275
|
+
"./eco/page-layout-normalization.ts": {
|
|
276
|
+
"types": "./src/eco/page-layout-normalization.d.ts",
|
|
277
|
+
"default": "./src/eco/page-layout-normalization.js"
|
|
278
|
+
},
|
|
259
279
|
"./declarations.ts": {
|
|
260
280
|
"types": "./src/declarations.d.ts"
|
|
261
281
|
},
|
|
@@ -294,6 +314,10 @@
|
|
|
294
314
|
"types": "./src/dev/dev-client-ownership.d.ts",
|
|
295
315
|
"default": "./src/dev/dev-client-ownership.js"
|
|
296
316
|
},
|
|
317
|
+
"./dev/server-ready-message.ts": {
|
|
318
|
+
"types": "./src/dev/server-ready-message.d.ts",
|
|
319
|
+
"default": "./src/dev/server-ready-message.js"
|
|
320
|
+
},
|
|
297
321
|
"./services/asset-processing-service.ts": {
|
|
298
322
|
"types": "./src/services/assets/asset-processing-service/index.d.ts",
|
|
299
323
|
"default": "./src/services/assets/asset-processing-service/index.js"
|
|
@@ -49,6 +49,18 @@ export interface ApplicationRuntimeOptions {
|
|
|
49
49
|
*/
|
|
50
50
|
hostModuleLoader?: SourceModuleLoader;
|
|
51
51
|
}
|
|
52
|
+
export interface AppStartInfo {
|
|
53
|
+
origin: string;
|
|
54
|
+
}
|
|
55
|
+
export type OnAppStartCallback = (info: AppStartInfo) => void;
|
|
56
|
+
/** @deprecated Use {@link AppStartInfo}. */
|
|
57
|
+
export type ApplicationListeningInfo = AppStartInfo;
|
|
58
|
+
/** @deprecated Use {@link OnAppStartCallback}. */
|
|
59
|
+
export type StartCallback = OnAppStartCallback;
|
|
60
|
+
/** @deprecated Use {@link OnAppStartCallback}. */
|
|
61
|
+
export type ListenCallback = OnAppStartCallback;
|
|
62
|
+
/** @deprecated Use {@link OnAppStartCallback}. */
|
|
63
|
+
export type ApplicationListeningCallback = OnAppStartCallback;
|
|
52
64
|
/**
|
|
53
65
|
* Configuration options for application adapters
|
|
54
66
|
*/
|
|
@@ -66,7 +78,10 @@ export interface ApplicationAdapterOptions {
|
|
|
66
78
|
* Common interface for application adapters
|
|
67
79
|
*/
|
|
68
80
|
export interface ApplicationAdapter<T = any> extends AsyncDisposable {
|
|
69
|
-
|
|
81
|
+
/** Boot the server. Pass a callback to run when the runtime is ready (optional). */
|
|
82
|
+
start(onAppStart?: OnAppStartCallback): Promise<T | void>;
|
|
83
|
+
/** Invoked by embedded hosts once the app can take traffic. */
|
|
84
|
+
handleListening(origin: string): void;
|
|
70
85
|
stop(force?: boolean): Promise<void>;
|
|
71
86
|
}
|
|
72
87
|
/**
|
|
@@ -94,6 +109,7 @@ export declare abstract class AbstractApplicationAdapter<TOptions extends Applic
|
|
|
94
109
|
* Both Bun and Node adapters read this map to register upgrade routes.
|
|
95
110
|
*/
|
|
96
111
|
protected websocketHandlers: Map<string, EcopagesWebSocketHandler<any, any>>;
|
|
112
|
+
private onAppStartCallback?;
|
|
97
113
|
constructor(options: TOptions);
|
|
98
114
|
private clearDistFolder;
|
|
99
115
|
/**
|
|
@@ -244,9 +260,17 @@ export declare abstract class AbstractApplicationAdapter<TOptions extends Applic
|
|
|
244
260
|
*/
|
|
245
261
|
protected abstract initializeServerAdapter(): Promise<any>;
|
|
246
262
|
/**
|
|
247
|
-
*
|
|
263
|
+
* Boot the server. When `onAppStart` is passed, it runs once the runtime can take traffic.
|
|
264
|
+
* Embedded apps only register the callback — the host (for example Vite) boots the port.
|
|
265
|
+
*/
|
|
266
|
+
start(onAppStart?: OnAppStartCallback): Promise<TServer | void>;
|
|
267
|
+
/** Runtime-specific server boot (dev, preview, build). */
|
|
268
|
+
protected abstract bootServer(): Promise<TServer | void>;
|
|
269
|
+
/**
|
|
270
|
+
* Invoked by embedded hosts (for example Vite) once the app can take traffic.
|
|
248
271
|
*/
|
|
249
|
-
|
|
272
|
+
handleListening(origin: string): void;
|
|
273
|
+
protected notifyListening(origin: string): void;
|
|
250
274
|
/**
|
|
251
275
|
* Stops the application server and releases runtime resources.
|
|
252
276
|
*
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
import { getHostModuleLoader } from "../../services/module-loading/host-module-loader-registry.js";
|
|
7
7
|
import { invariant } from "../../utils/invariant.js";
|
|
8
8
|
import { fileSystem } from "@ecopages/file-system";
|
|
9
|
+
import { formatServerReadyMessage } from "../../dev/server-ready-message.js";
|
|
9
10
|
import { parseCliArgs } from "../../utils/parse-cli-args.js";
|
|
10
11
|
class AbstractApplicationAdapter {
|
|
11
12
|
appConfig;
|
|
@@ -20,6 +21,7 @@ class AbstractApplicationAdapter {
|
|
|
20
21
|
* Both Bun and Node adapters read this map to register upgrade routes.
|
|
21
22
|
*/
|
|
22
23
|
websocketHandlers = /* @__PURE__ */ new Map();
|
|
24
|
+
onAppStartCallback;
|
|
23
25
|
constructor(options) {
|
|
24
26
|
this.appConfig = options.appConfig;
|
|
25
27
|
this.serverOptions = options.serverOptions || {};
|
|
@@ -191,6 +193,32 @@ class AbstractApplicationAdapter {
|
|
|
191
193
|
getErrorHandler() {
|
|
192
194
|
return this.errorHandler;
|
|
193
195
|
}
|
|
196
|
+
/**
|
|
197
|
+
* Boot the server. When `onAppStart` is passed, it runs once the runtime can take traffic.
|
|
198
|
+
* Embedded apps only register the callback — the host (for example Vite) boots the port.
|
|
199
|
+
*/
|
|
200
|
+
async start(onAppStart) {
|
|
201
|
+
if (onAppStart) {
|
|
202
|
+
this.onAppStartCallback = onAppStart;
|
|
203
|
+
}
|
|
204
|
+
if (this.runtimeOptions.embedded) {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
return this.bootServer();
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Invoked by embedded hosts (for example Vite) once the app can take traffic.
|
|
211
|
+
*/
|
|
212
|
+
handleListening(origin) {
|
|
213
|
+
this.notifyListening(origin);
|
|
214
|
+
}
|
|
215
|
+
notifyListening(origin) {
|
|
216
|
+
const normalizedOrigin = origin.replace(/\/$/, "");
|
|
217
|
+
if (!this.onAppStartCallback) {
|
|
218
|
+
console.log(formatServerReadyMessage(normalizedOrigin));
|
|
219
|
+
}
|
|
220
|
+
this.onAppStartCallback?.({ origin: normalizedOrigin });
|
|
221
|
+
}
|
|
194
222
|
/**
|
|
195
223
|
* Stops the application server and releases runtime resources.
|
|
196
224
|
*
|
|
@@ -32,7 +32,8 @@ export interface ServerAdapterResult {
|
|
|
32
32
|
buildStatic: (options?: {
|
|
33
33
|
preview?: boolean;
|
|
34
34
|
force?: boolean;
|
|
35
|
-
}) => Promise<
|
|
35
|
+
}) => Promise<string | undefined>;
|
|
36
|
+
servePreviewOnly: () => Promise<string | undefined>;
|
|
36
37
|
dispose(): Promise<void>;
|
|
37
38
|
}
|
|
38
39
|
/**
|
|
@@ -60,7 +61,7 @@ export declare abstract class AbstractServerAdapter<TOptions extends ServerAdapt
|
|
|
60
61
|
abstract buildStatic(options?: {
|
|
61
62
|
preview?: boolean;
|
|
62
63
|
force?: boolean;
|
|
63
|
-
}): Promise<
|
|
64
|
+
}): Promise<string | undefined>;
|
|
64
65
|
/**
|
|
65
66
|
* Factory method to create a server adapter with runtime-specific functionality
|
|
66
67
|
*/
|
|
@@ -53,7 +53,7 @@ export declare class BunEcopagesApp<WebSocketData = undefined> extends SharedApp
|
|
|
53
53
|
* @param options Optional settings
|
|
54
54
|
* @param options.autoCompleteInitialization Whether to automatically complete initialization with dynamic routes after server start (defaults to true)
|
|
55
55
|
*/
|
|
56
|
-
|
|
56
|
+
protected bootServer(): Promise<Server<WebSocketData> | void>;
|
|
57
57
|
stop(force?: boolean): Promise<void>;
|
|
58
58
|
}
|
|
59
59
|
/**
|
|
@@ -66,7 +66,7 @@ class BunEcopagesApp extends SharedApplicationAdapter {
|
|
|
66
66
|
* @param options Optional settings
|
|
67
67
|
* @param options.autoCompleteInitialization Whether to automatically complete initialization with dynamic routes after server start (defaults to true)
|
|
68
68
|
*/
|
|
69
|
-
async
|
|
69
|
+
async bootServer() {
|
|
70
70
|
if (this.stopped) {
|
|
71
71
|
this.serverAdapter = void 0;
|
|
72
72
|
this.stopped = false;
|
|
@@ -74,15 +74,25 @@ class BunEcopagesApp extends SharedApplicationAdapter {
|
|
|
74
74
|
if (!this.serverAdapter) {
|
|
75
75
|
this.serverAdapter = await this.initializeServerAdapter();
|
|
76
76
|
}
|
|
77
|
-
const { dev, preview, build, force } = this.cliArgs;
|
|
77
|
+
const { dev, preview, build, force, serveOnly } = this.cliArgs;
|
|
78
78
|
const staticRuntimeMode = resolveStaticRuntimeMode({
|
|
79
79
|
appConfig: this.appConfig,
|
|
80
80
|
cliArgs: this.cliArgs
|
|
81
81
|
});
|
|
82
|
+
if (preview && serveOnly) {
|
|
83
|
+
const previewOrigin2 = await this.serverAdapter.servePreviewOnly();
|
|
84
|
+
if (previewOrigin2) {
|
|
85
|
+
this.notifyListening(previewOrigin2);
|
|
86
|
+
}
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
82
89
|
if (staticRuntimeMode.canBuildWithoutRuntimeServer) {
|
|
83
90
|
appLogger.debugTime("Building static pages");
|
|
84
|
-
await this.serverAdapter.buildStatic({ preview, force });
|
|
91
|
+
const previewOrigin2 = await this.serverAdapter.buildStatic({ preview, force });
|
|
85
92
|
appLogger.debugTimeEnd("Building static pages");
|
|
93
|
+
if (preview && previewOrigin2) {
|
|
94
|
+
this.notifyListening(previewOrigin2);
|
|
95
|
+
}
|
|
86
96
|
if (build) {
|
|
87
97
|
process.exit(0);
|
|
88
98
|
}
|
|
@@ -103,12 +113,14 @@ class BunEcopagesApp extends SharedApplicationAdapter {
|
|
|
103
113
|
if (!this.server) {
|
|
104
114
|
throw new Error("Server failed to start");
|
|
105
115
|
}
|
|
106
|
-
|
|
107
|
-
|
|
116
|
+
const runtimeOrigin = this.runtimeHost.getOrigin(
|
|
117
|
+
this.server,
|
|
118
|
+
runtimeServerOptions
|
|
108
119
|
);
|
|
120
|
+
let previewOrigin;
|
|
109
121
|
if (build || preview) {
|
|
110
122
|
appLogger.debugTime("Building static pages");
|
|
111
|
-
await this.serverAdapter.buildStatic({ preview, force });
|
|
123
|
+
previewOrigin = await this.serverAdapter.buildStatic({ preview, force });
|
|
112
124
|
const buildRuntimeServer = this.server;
|
|
113
125
|
this.server = null;
|
|
114
126
|
await this.runtimeHost.stop(buildRuntimeServer, { force: true });
|
|
@@ -116,6 +128,11 @@ class BunEcopagesApp extends SharedApplicationAdapter {
|
|
|
116
128
|
if (build) {
|
|
117
129
|
process.exit(0);
|
|
118
130
|
}
|
|
131
|
+
} else {
|
|
132
|
+
this.notifyListening(runtimeOrigin);
|
|
133
|
+
}
|
|
134
|
+
if (preview && previewOrigin) {
|
|
135
|
+
this.notifyListening(previewOrigin);
|
|
119
136
|
}
|
|
120
137
|
return this.server ?? void 0;
|
|
121
138
|
}
|
|
@@ -52,7 +52,8 @@ export interface BunServerAdapterResult extends ServerAdapterResult {
|
|
|
52
52
|
buildStatic: (options?: {
|
|
53
53
|
preview?: boolean;
|
|
54
54
|
force?: boolean;
|
|
55
|
-
}) => Promise<
|
|
55
|
+
}) => Promise<string | undefined>;
|
|
56
|
+
servePreviewOnly: () => Promise<string | undefined>;
|
|
56
57
|
completeInitialization: (server?: BunServerInstance | null) => Promise<void>;
|
|
57
58
|
handleRequest: (request: Request) => Promise<Response>;
|
|
58
59
|
attachUserWebSocketUpgrades: (server: NodeHttpServer, options?: {
|
|
@@ -216,7 +217,13 @@ export declare class BunServerAdapter extends SharedServerAdapter<BunServerAdapt
|
|
|
216
217
|
buildStatic(options?: {
|
|
217
218
|
preview?: boolean;
|
|
218
219
|
force?: boolean;
|
|
219
|
-
}): Promise<
|
|
220
|
+
}): Promise<string | undefined>;
|
|
221
|
+
/**
|
|
222
|
+
* Serves an existing static export without running SSG. Used by e2e preview
|
|
223
|
+
* launchers after a shared prewarm build.
|
|
224
|
+
*/
|
|
225
|
+
servePreviewOnly(): Promise<string | undefined>;
|
|
226
|
+
private startPreviewServer;
|
|
220
227
|
/**
|
|
221
228
|
* Initializes the server with dynamic routes after server creation.
|
|
222
229
|
* Must be called before handling any requests.
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import path from "node:path";
|
|
1
2
|
import { DEFAULT_ECOPAGES_HOSTNAME, DEFAULT_ECOPAGES_PORT } from "../../config/constants.js";
|
|
2
3
|
import { appLogger } from "../../global/app-logger.js";
|
|
3
4
|
import { HttpError } from "../../errors/http-error.js";
|
|
@@ -433,8 +434,30 @@ class BunServerAdapter extends SharedServerAdapter {
|
|
|
433
434
|
}
|
|
434
435
|
);
|
|
435
436
|
if (!options?.preview) {
|
|
436
|
-
return;
|
|
437
|
+
return void 0;
|
|
437
438
|
}
|
|
439
|
+
return this.startPreviewServer();
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* Serves an existing static export without running SSG. Used by e2e preview
|
|
443
|
+
* launchers after a shared prewarm build.
|
|
444
|
+
*/
|
|
445
|
+
async servePreviewOnly() {
|
|
446
|
+
if (!this.fullyInitialized) {
|
|
447
|
+
await this.initializeSharedRouteHandling({
|
|
448
|
+
staticRoutes: this.staticRoutes,
|
|
449
|
+
hmrManager: this.hmrManager
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
const distPath = path.join(this.appConfig.rootDir, this.appConfig.distDir);
|
|
453
|
+
if (!fileSystem.exists(distPath)) {
|
|
454
|
+
throw new Error(
|
|
455
|
+
`Cannot serve preview without building first: dist directory "${this.appConfig.distDir}" not found in "${this.appConfig.rootDir}".`
|
|
456
|
+
);
|
|
457
|
+
}
|
|
458
|
+
return this.startPreviewServer();
|
|
459
|
+
}
|
|
460
|
+
async startPreviewServer() {
|
|
438
461
|
const previewHostname = this.serveOptions.hostname || DEFAULT_ECOPAGES_HOSTNAME;
|
|
439
462
|
const previewPort = Number(this.serveOptions.port || DEFAULT_ECOPAGES_PORT);
|
|
440
463
|
const activePreviewPort = await this.previewHost.start({
|
|
@@ -443,10 +466,10 @@ class BunServerAdapter extends SharedServerAdapter {
|
|
|
443
466
|
port: previewPort,
|
|
444
467
|
allowPortFallback: this.allowPortFallback
|
|
445
468
|
});
|
|
446
|
-
if (activePreviewPort) {
|
|
447
|
-
|
|
448
|
-
return;
|
|
469
|
+
if (!activePreviewPort) {
|
|
470
|
+
return void 0;
|
|
449
471
|
}
|
|
472
|
+
return `http://${previewHostname}:${activePreviewPort}`;
|
|
450
473
|
}
|
|
451
474
|
/**
|
|
452
475
|
* Initializes the server with dynamic routes after server creation.
|
|
@@ -497,6 +520,7 @@ class BunServerAdapter extends SharedServerAdapter {
|
|
|
497
520
|
return {
|
|
498
521
|
getServerOptions: this.getServerOptions.bind(this),
|
|
499
522
|
buildStatic: this.buildStatic.bind(this),
|
|
523
|
+
servePreviewOnly: this.servePreviewOnly.bind(this),
|
|
500
524
|
completeInitialization: this.completeInitialization.bind(this),
|
|
501
525
|
handleRequest: this.handleRequest.bind(this),
|
|
502
526
|
attachUserWebSocketUpgrades: this.attachUserWebSocketUpgrades.bind(this),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { EcoPagesAppConfig } from '../types/internal-types.js';
|
|
2
2
|
import { AbstractApplicationAdapter } from './abstract/application-adapter.js';
|
|
3
3
|
import type { ApplicationAdapterOptions } from './abstract/application-adapter.js';
|
|
4
|
-
|
|
4
|
+
export type { OnAppStartCallback, AppStartInfo, StartCallback, ListenCallback, ApplicationListeningCallback, ApplicationListeningInfo, } from './abstract/application-adapter.js';
|
|
5
5
|
export type EcopagesRuntimeAdapter = 'auto' | 'node' | 'bun';
|
|
6
6
|
export interface EcopagesAppOptions extends ApplicationAdapterOptions {
|
|
7
7
|
appConfig: EcoPagesAppConfig;
|
|
@@ -20,14 +20,3 @@ export interface EcopagesAppOptions extends ApplicationAdapterOptions {
|
|
|
20
20
|
}
|
|
21
21
|
export type UniversalEcopagesApp = AbstractApplicationAdapter<EcopagesAppOptions, unknown, Request>;
|
|
22
22
|
export declare function createApp<WebSocketData = undefined>(options: EcopagesAppOptions): Promise<UniversalEcopagesApp>;
|
|
23
|
-
export declare class EcopagesApp extends SharedApplicationAdapter<EcopagesAppOptions, unknown, Request> {
|
|
24
|
-
private readonly appOptions;
|
|
25
|
-
private runtimeApp;
|
|
26
|
-
private runtimeAppPromise;
|
|
27
|
-
constructor(options: EcopagesAppOptions);
|
|
28
|
-
private getRuntimeApp;
|
|
29
|
-
protected initializeServerAdapter(): Promise<UniversalEcopagesApp>;
|
|
30
|
-
start(): Promise<unknown>;
|
|
31
|
-
fetch(request: Request): Promise<Response>;
|
|
32
|
-
stop(force?: boolean): Promise<void>;
|
|
33
|
-
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { AbstractApplicationAdapter } from "./abstract/application-adapter.js";
|
|
2
|
-
import { SharedApplicationAdapter } from "./shared/application-adapter.js";
|
|
3
2
|
import { createApp as createBunApp } from "./bun/create-app.js";
|
|
4
3
|
import { createNodeApp } from "./node/create-app.js";
|
|
5
4
|
async function createRuntimeApp(options) {
|
|
@@ -13,63 +12,6 @@ async function createRuntimeApp(options) {
|
|
|
13
12
|
async function createApp(options) {
|
|
14
13
|
return createRuntimeApp(options);
|
|
15
14
|
}
|
|
16
|
-
class EcopagesApp extends SharedApplicationAdapter {
|
|
17
|
-
appOptions;
|
|
18
|
-
runtimeApp = null;
|
|
19
|
-
runtimeAppPromise = null;
|
|
20
|
-
constructor(options) {
|
|
21
|
-
super(options);
|
|
22
|
-
this.appOptions = options;
|
|
23
|
-
}
|
|
24
|
-
async getRuntimeApp() {
|
|
25
|
-
if (this.runtimeApp) {
|
|
26
|
-
return this.runtimeApp;
|
|
27
|
-
}
|
|
28
|
-
if (!this.runtimeAppPromise) {
|
|
29
|
-
this.runtimeAppPromise = createRuntimeApp({
|
|
30
|
-
...this.appOptions,
|
|
31
|
-
clearOutput: false
|
|
32
|
-
}).then((app) => {
|
|
33
|
-
for (const handler of this.apiHandlers) {
|
|
34
|
-
app.add(handler);
|
|
35
|
-
}
|
|
36
|
-
for (const route of this.staticRoutes) {
|
|
37
|
-
app.static(route.path, route.loader);
|
|
38
|
-
}
|
|
39
|
-
if (this.errorHandler) {
|
|
40
|
-
app.onError(this.errorHandler);
|
|
41
|
-
}
|
|
42
|
-
this.runtimeApp = app;
|
|
43
|
-
return app;
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
return this.runtimeAppPromise;
|
|
47
|
-
}
|
|
48
|
-
async initializeServerAdapter() {
|
|
49
|
-
return this.getRuntimeApp();
|
|
50
|
-
}
|
|
51
|
-
async start() {
|
|
52
|
-
const runtimeApp = await this.getRuntimeApp();
|
|
53
|
-
return runtimeApp.start();
|
|
54
|
-
}
|
|
55
|
-
async fetch(request) {
|
|
56
|
-
const runtimeApp = await this.getRuntimeApp();
|
|
57
|
-
const candidate = runtimeApp;
|
|
58
|
-
if (!candidate.fetch) {
|
|
59
|
-
throw new Error("The selected runtime adapter does not expose fetch()");
|
|
60
|
-
}
|
|
61
|
-
return candidate.fetch(request);
|
|
62
|
-
}
|
|
63
|
-
async stop(force = true) {
|
|
64
|
-
const runtimeApp = this.runtimeApp ?? (this.runtimeAppPromise ? await this.runtimeAppPromise : null);
|
|
65
|
-
if (runtimeApp) {
|
|
66
|
-
await runtimeApp.stop(force);
|
|
67
|
-
}
|
|
68
|
-
this.runtimeApp = null;
|
|
69
|
-
this.runtimeAppPromise = null;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
15
|
export {
|
|
73
|
-
EcopagesApp,
|
|
74
16
|
createApp
|
|
75
17
|
};
|
package/src/adapters/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { createApp } from './create-app.js';
|
|
2
2
|
export { defineApiHandler, defineGroupHandler, type GroupHandler } from './shared/define-api-handler.js';
|
package/src/adapters/index.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createApp } from "./create-app.js";
|
|
2
2
|
import { defineApiHandler, defineGroupHandler } from "./shared/define-api-handler.js";
|
|
3
3
|
export {
|
|
4
|
-
EcopagesApp,
|
|
5
4
|
createApp,
|
|
6
5
|
defineApiHandler,
|
|
7
6
|
defineGroupHandler
|
|
@@ -18,7 +18,7 @@ export declare class NodeEcopagesApp extends SharedApplicationAdapter<EcopagesAp
|
|
|
18
18
|
protected createServerAdapter(params: Parameters<typeof createNodeServerAdapter>[0]): Promise<NodeServerAdapterResult>;
|
|
19
19
|
stop(force?: boolean): Promise<void>;
|
|
20
20
|
protected initializeServerAdapter(): Promise<NodeServerAdapterResult>;
|
|
21
|
-
|
|
21
|
+
protected bootServer(): Promise<NodeServerInstance | void>;
|
|
22
22
|
fetch(request: Request): Promise<Response>;
|
|
23
23
|
attachWebSocketUpgrades(httpServer: import('node:http').Server, options?: {
|
|
24
24
|
passthroughUnmatched?: boolean;
|
|
@@ -55,7 +55,7 @@ class NodeEcopagesApp extends SharedApplicationAdapter {
|
|
|
55
55
|
allowPortFallback: binding.allowPortFallback
|
|
56
56
|
});
|
|
57
57
|
}
|
|
58
|
-
async
|
|
58
|
+
async bootServer() {
|
|
59
59
|
if (this.stopped) {
|
|
60
60
|
this.serverAdapter = void 0;
|
|
61
61
|
this.stopped = false;
|
|
@@ -66,11 +66,21 @@ class NodeEcopagesApp extends SharedApplicationAdapter {
|
|
|
66
66
|
if (this.server) {
|
|
67
67
|
return this.server;
|
|
68
68
|
}
|
|
69
|
-
const { build, preview, force } = this.cliArgs;
|
|
69
|
+
const { build, preview, force, serveOnly } = this.cliArgs;
|
|
70
|
+
if (preview && serveOnly) {
|
|
71
|
+
const previewOrigin = await this.serverAdapter.servePreviewOnly();
|
|
72
|
+
if (previewOrigin) {
|
|
73
|
+
this.notifyListening(previewOrigin);
|
|
74
|
+
}
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
70
77
|
if (build || preview) {
|
|
71
78
|
appLogger.debugTime("Building static pages");
|
|
72
|
-
await this.serverAdapter.buildStatic({ preview, force });
|
|
79
|
+
const previewOrigin = await this.serverAdapter.buildStatic({ preview, force });
|
|
73
80
|
appLogger.debugTimeEnd("Building static pages");
|
|
81
|
+
if (preview && previewOrigin) {
|
|
82
|
+
this.notifyListening(previewOrigin);
|
|
83
|
+
}
|
|
74
84
|
if (build) {
|
|
75
85
|
process.exit(0);
|
|
76
86
|
}
|
|
@@ -85,7 +95,7 @@ class NodeEcopagesApp extends SharedApplicationAdapter {
|
|
|
85
95
|
});
|
|
86
96
|
this.runtimeOrigin = this.runtimeHost.getOrigin(this.server, serveOptions);
|
|
87
97
|
await this.serverAdapter.completeInitialization(this.server);
|
|
88
|
-
|
|
98
|
+
this.notifyListening(this.runtimeOrigin);
|
|
89
99
|
return this.server;
|
|
90
100
|
}
|
|
91
101
|
async fetch(request) {
|
|
@@ -126,7 +126,13 @@ export declare class NodeServerAdapter extends SharedServerAdapter<NodeServerAda
|
|
|
126
126
|
buildStatic(options?: {
|
|
127
127
|
preview?: boolean;
|
|
128
128
|
force?: boolean;
|
|
129
|
-
}): Promise<
|
|
129
|
+
}): Promise<string | undefined>;
|
|
130
|
+
/**
|
|
131
|
+
* Serves an existing static export without running SSG. Used by e2e preview
|
|
132
|
+
* launchers after a shared prewarm build.
|
|
133
|
+
*/
|
|
134
|
+
servePreviewOnly(): Promise<string | undefined>;
|
|
135
|
+
private startPreviewServer;
|
|
130
136
|
createAdapter(): Promise<NodeServerAdapterResult>;
|
|
131
137
|
/**
|
|
132
138
|
* Releases dev-time resources owned by the adapter.
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import {} from "node:http";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { fileSystem } from "@ecopages/file-system";
|
|
2
4
|
import { setupAppRuntimePlugins } from "../../build/build-adapter.js";
|
|
3
5
|
import { installAppRuntimeBuildExecutor } from "../../build/runtime-build-executor.js";
|
|
4
6
|
import { appLogger } from "../../global/app-logger.js";
|
|
@@ -155,8 +157,27 @@ class NodeServerAdapter extends SharedServerAdapter {
|
|
|
155
157
|
}
|
|
156
158
|
);
|
|
157
159
|
if (!options?.preview) {
|
|
158
|
-
return;
|
|
160
|
+
return void 0;
|
|
161
|
+
}
|
|
162
|
+
return this.startPreviewServer();
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Serves an existing static export without running SSG. Used by e2e preview
|
|
166
|
+
* launchers after a shared prewarm build.
|
|
167
|
+
*/
|
|
168
|
+
async servePreviewOnly() {
|
|
169
|
+
if (!this.initialized) {
|
|
170
|
+
await this.initialize();
|
|
171
|
+
}
|
|
172
|
+
const distPath = path.join(this.appConfig.rootDir, this.appConfig.distDir);
|
|
173
|
+
if (!fileSystem.exists(distPath)) {
|
|
174
|
+
throw new Error(
|
|
175
|
+
`Cannot serve preview without building first: dist directory "${this.appConfig.distDir}" not found in "${this.appConfig.rootDir}".`
|
|
176
|
+
);
|
|
159
177
|
}
|
|
178
|
+
return this.startPreviewServer();
|
|
179
|
+
}
|
|
180
|
+
async startPreviewServer() {
|
|
160
181
|
const activePreviewPort = await this.previewHost.start({
|
|
161
182
|
appConfig: this.appConfig,
|
|
162
183
|
hostname: String(this.serveOptions.hostname || DEFAULT_ECOPAGES_HOSTNAME),
|
|
@@ -164,16 +185,17 @@ class NodeServerAdapter extends SharedServerAdapter {
|
|
|
164
185
|
allowPortFallback: this.allowPortFallback
|
|
165
186
|
});
|
|
166
187
|
if (!activePreviewPort) {
|
|
167
|
-
return;
|
|
188
|
+
return void 0;
|
|
168
189
|
}
|
|
169
190
|
const previewHostname = this.serveOptions.hostname || DEFAULT_ECOPAGES_HOSTNAME;
|
|
170
|
-
|
|
191
|
+
return `http://${previewHostname}:${activePreviewPort}`;
|
|
171
192
|
}
|
|
172
193
|
async createAdapter() {
|
|
173
194
|
await this.initialize();
|
|
174
195
|
return {
|
|
175
196
|
getServerOptions: this.getServerOptions.bind(this),
|
|
176
197
|
buildStatic: this.buildStatic.bind(this),
|
|
198
|
+
servePreviewOnly: this.servePreviewOnly.bind(this),
|
|
177
199
|
completeInitialization: this.completeInitialization.bind(this),
|
|
178
200
|
handleRequest: this.handleRequest.bind(this),
|
|
179
201
|
attachUserWebSocketUpgrades: this.attachUserWebSocketUpgrades.bind(this),
|
|
@@ -55,6 +55,8 @@ export declare class FileSystemResponseMatcher {
|
|
|
55
55
|
* when the page template cannot be resolved.
|
|
56
56
|
*/
|
|
57
57
|
private renderCustomNotFoundResponse;
|
|
58
|
+
private renderCustomNotFoundResponseOrServerError;
|
|
59
|
+
private createInternalServerErrorResponse;
|
|
58
60
|
private createExecutionPlan;
|
|
59
61
|
/**
|
|
60
62
|
* Loads the matched page module for request-time inspection.
|