@ecopages/core 0.2.0-beta.1 → 0.2.0-beta.11
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/package.json +107 -3
- package/src/adapters/abstract/application-adapter.d.ts +73 -1
- package/src/adapters/abstract/application-adapter.js +89 -0
- package/src/adapters/abstract/server-adapter.d.ts +3 -0
- package/src/adapters/abstract/ws-pattern-matcher.d.ts +60 -0
- package/src/adapters/abstract/ws-pattern-matcher.js +61 -0
- package/src/adapters/bun/client-bridge.d.ts +1 -0
- package/src/adapters/bun/client-bridge.js +3 -0
- package/src/adapters/bun/create-app.d.ts +5 -3
- package/src/adapters/bun/create-app.js +44 -39
- package/src/adapters/bun/hmr-manager.d.ts +2 -1
- package/src/adapters/bun/hmr-manager.js +2 -2
- package/src/adapters/bun/server-adapter.d.ts +81 -20
- package/src/adapters/bun/server-adapter.js +220 -78
- package/src/adapters/bun/static-preview-host.js +25 -20
- package/src/adapters/create-app.d.ts +13 -0
- package/src/adapters/create-app.js +10 -1
- package/src/adapters/node/create-app.d.ts +4 -0
- package/src/adapters/node/create-app.js +38 -9
- package/src/adapters/node/node-client-bridge.d.ts +1 -0
- package/src/adapters/node/node-client-bridge.js +3 -0
- package/src/adapters/node/node-hmr-manager.d.ts +2 -1
- package/src/adapters/node/node-hmr-manager.js +2 -2
- package/src/adapters/node/server-adapter-dependencies.js +2 -0
- package/src/adapters/node/server-adapter.d.ts +55 -19
- package/src/adapters/node/server-adapter.js +140 -132
- package/src/adapters/node/static-content-server.d.ts +1 -0
- package/src/adapters/node/static-content-server.js +10 -2
- package/src/adapters/node/static-preview-host.js +27 -12
- package/src/adapters/shared/bun-user-websocket-lifecycle.d.ts +22 -0
- package/src/adapters/shared/bun-user-websocket-lifecycle.js +96 -0
- package/src/adapters/shared/copy-runtime-public-dir.d.ts +6 -0
- package/src/adapters/shared/copy-runtime-public-dir.js +24 -0
- package/src/adapters/shared/hmr-html-response.d.ts +1 -1
- package/src/adapters/shared/hmr-html-response.js +4 -1
- package/src/adapters/shared/node-http-websocket-upgrades.d.ts +21 -0
- package/src/adapters/shared/node-http-websocket-upgrades.js +100 -0
- package/src/adapters/shared/port-manager.d.ts +116 -0
- package/src/adapters/shared/port-manager.js +196 -0
- package/src/adapters/shared/runtime-app-bootstrap.d.ts +2 -1
- package/src/adapters/shared/runtime-app-bootstrap.js +3 -6
- package/src/adapters/shared/runtime-server-lifecycle.d.ts +38 -0
- package/src/adapters/shared/runtime-server-lifecycle.js +39 -0
- package/src/adapters/shared/server-adapter.d.ts +2 -1
- package/src/adapters/shared/server-adapter.js +12 -4
- package/src/adapters/shared/server-route-handler.d.ts +4 -1
- package/src/adapters/shared/server-route-handler.js +5 -2
- package/src/adapters/shared/server-static-builder.d.ts +14 -29
- package/src/adapters/shared/server-static-builder.js +91 -70
- package/src/adapters/shared/shared-hmr-manager.d.ts +12 -0
- package/src/adapters/shared/shared-hmr-manager.js +64 -7
- package/src/adapters/shared/static-preview-host.d.ts +5 -0
- package/src/adapters/shared/websocket-lifecycle.d.ts +24 -0
- package/src/adapters/shared/websocket-lifecycle.js +55 -0
- package/src/build/README.md +77 -14
- package/src/build/app-build-manifest-runtime.d.ts +10 -0
- package/src/build/app-build-manifest-runtime.js +90 -0
- package/src/build/build-adapter.d.ts +17 -319
- package/src/build/build-adapter.js +28 -94
- package/src/build/build-contracts.d.ts +97 -0
- package/src/build/build-contracts.js +0 -0
- package/src/build/build-input-fingerprint.d.ts +28 -0
- package/src/build/build-input-fingerprint.js +31 -0
- package/src/build/build-profile-options.d.ts +7 -0
- package/src/build/build-profile-options.js +37 -0
- package/src/build/build-runtime.d.ts +24 -0
- package/src/build/build-runtime.js +65 -0
- package/src/build/deduping-build-executor.d.ts +28 -0
- package/src/build/deduping-build-executor.js +56 -0
- package/src/build/jsx-ownership-plugins.d.ts +24 -0
- package/src/build/jsx-ownership-plugins.js +41 -0
- package/src/build/pages-unified-graph-build.d.ts +31 -0
- package/src/build/pages-unified-graph-build.js +206 -0
- package/src/build/parallel-build-executor.d.ts +21 -0
- package/src/build/parallel-build-executor.js +52 -0
- package/src/build/production-build-cache.d.ts +20 -0
- package/src/build/production-build-cache.js +63 -0
- package/src/build/rolldown-adapter-helpers.d.ts +3 -6
- package/src/build/rolldown-adapter-helpers.js +71 -6
- package/src/build/rolldown-build-adapter.d.ts +2 -6
- package/src/build/rolldown-build-adapter.js +3 -3
- package/src/build/rolldown-build-invocation-metrics.d.ts +12 -0
- package/src/build/rolldown-build-invocation-metrics.js +43 -0
- package/src/build/rolldown-plugin-bridge.d.ts +15 -1
- package/src/build/rolldown-plugin-bridge.js +20 -5
- package/src/build/rolldown-source-transform-pass.d.ts +15 -0
- package/src/build/rolldown-source-transform-pass.js +58 -0
- package/src/build/runtime-build-executor.d.ts +8 -15
- package/src/build/runtime-build-executor.js +12 -15
- package/src/build/runtime-build-output-normalizer.d.ts +7 -0
- package/src/build/runtime-build-output-normalizer.js +94 -2
- package/src/build/server-entry-build-cache.d.ts +44 -0
- package/src/build/server-entry-build-cache.js +161 -0
- package/src/config/config-builder.d.ts +12 -7
- package/src/config/config-builder.js +12 -9
- package/src/dev/client-bridge-registry.d.ts +5 -0
- package/src/dev/client-bridge-registry.js +15 -0
- package/src/dev/dev-client-ownership.d.ts +7 -0
- package/src/dev/dev-client-ownership.js +6 -0
- package/src/dev/host-runtime.d.ts +3 -0
- package/src/dev/host-runtime.js +7 -0
- package/src/hmr/client/hmr-runtime.js +5 -2
- package/src/hmr/strategies/server-rendered-template-hmr-strategy.d.ts +17 -0
- package/src/hmr/strategies/server-rendered-template-hmr-strategy.js +29 -0
- package/src/integrations/ghtml/ghtml-renderer.d.ts +2 -6
- package/src/integrations/ghtml/ghtml-renderer.js +2 -51
- package/src/integrations/ghtml/ghtml.plugin.d.ts +3 -16
- package/src/integrations/ghtml/ghtml.plugin.js +7 -14
- package/src/plugins/define-integration.d.ts +26 -0
- package/src/plugins/define-integration.js +19 -0
- package/src/plugins/eco-component-meta-plugin.js +5 -8
- package/src/plugins/foreign-jsx-override-plugin.js +4 -6
- package/src/plugins/integration-plugin.d.ts +19 -9
- package/src/plugins/integration-plugin.js +7 -4
- package/src/plugins/jsx-import-source.utils.d.ts +8 -0
- package/src/plugins/jsx-import-source.utils.js +26 -0
- package/src/plugins/processor.d.ts +19 -4
- package/src/plugins/processor.js +22 -4
- package/src/plugins/source-transform.d.ts +31 -0
- package/src/plugins/source-transform.js +23 -1
- package/src/route-renderer/GRAPH.md +8 -8
- package/src/route-renderer/README.md +30 -28
- package/src/route-renderer/orchestration/component-graph-collectors.d.ts +10 -0
- package/src/route-renderer/orchestration/component-graph-collectors.js +143 -0
- package/src/route-renderer/orchestration/component-graph.d.ts +36 -0
- package/src/route-renderer/orchestration/component-graph.js +90 -0
- package/src/route-renderer/orchestration/component-render-context.d.ts +3 -10
- package/src/route-renderer/orchestration/component-render-context.js +3 -1
- package/src/route-renderer/orchestration/declared-ownership-graph.d.ts +1 -18
- package/src/route-renderer/orchestration/declared-ownership-graph.js +5 -31
- package/src/route-renderer/orchestration/document-shell-render.service.d.ts +54 -0
- package/src/route-renderer/orchestration/document-shell-render.service.js +54 -0
- package/src/route-renderer/orchestration/foreign-subtree-execution.service.d.ts +59 -29
- package/src/route-renderer/orchestration/foreign-subtree-execution.service.js +164 -35
- package/src/route-renderer/orchestration/global-injector-assets.service.d.ts +7 -0
- package/src/route-renderer/orchestration/global-injector-assets.service.js +32 -0
- package/src/route-renderer/orchestration/integration-renderer.d.ts +18 -54
- package/src/route-renderer/orchestration/integration-renderer.js +108 -194
- package/src/route-renderer/orchestration/integration-route-render-adapter.d.ts +38 -0
- package/src/route-renderer/orchestration/integration-route-render-adapter.js +27 -0
- package/src/route-renderer/orchestration/ownership-validation.service.d.ts +4 -0
- package/src/route-renderer/orchestration/ownership-validation.service.js +11 -1
- package/src/route-renderer/orchestration/page-browser-graph-contribution.loader.d.ts +9 -0
- package/src/route-renderer/orchestration/page-browser-graph-contribution.loader.js +7 -0
- package/src/route-renderer/orchestration/page-browser-graph.service.d.ts +25 -0
- package/src/route-renderer/orchestration/page-browser-graph.service.js +174 -0
- package/src/route-renderer/orchestration/render-output.utils.d.ts +2 -0
- package/src/route-renderer/orchestration/render-output.utils.js +4 -0
- package/src/route-renderer/orchestration/route-html-finalization.service.d.ts +17 -0
- package/src/route-renderer/orchestration/route-html-finalization.service.js +26 -0
- package/src/route-renderer/orchestration/route-prepared-options.builder.d.ts +24 -0
- package/src/route-renderer/orchestration/route-prepared-options.builder.js +52 -0
- package/src/route-renderer/orchestration/route-prepared-options.utils.d.ts +4 -0
- package/src/route-renderer/orchestration/route-prepared-options.utils.js +33 -0
- package/src/route-renderer/orchestration/route-render-orchestrator.d.ts +5 -38
- package/src/route-renderer/orchestration/route-render-orchestrator.js +51 -459
- package/src/route-renderer/orchestration/string-markup-renderer.d.ts +14 -0
- package/src/route-renderer/orchestration/string-markup-renderer.js +54 -0
- package/src/router/client/navigation-coordinator.d.ts +1 -1
- package/src/router/client/navigation-coordinator.js +12 -2
- package/src/services/assets/asset-processing-service/browser-runtime-asset.factory.d.ts +1 -0
- package/src/services/assets/asset-processing-service/browser-runtime-asset.factory.js +1 -0
- package/src/services/assets/asset-processing-service/browser-runtime-entry.factory.d.ts +4 -2
- package/src/services/assets/asset-processing-service/browser-runtime-entry.factory.js +27 -7
- package/src/services/assets/asset-processing-service/processors/script/file-script.processor.js +32 -14
- package/src/services/assets/asset-processing-service/processors/script/node-module-script.processor.js +17 -3
- package/src/services/assets/asset-processing-service/processors/stylesheet/content-stylesheet.processor.d.ts +0 -3
- package/src/services/assets/asset-processing-service/processors/stylesheet/content-stylesheet.processor.js +2 -31
- package/src/services/assets/asset-processing-service/processors/stylesheet/file-stylesheet.processor.d.ts +0 -3
- package/src/services/assets/asset-processing-service/processors/stylesheet/file-stylesheet.processor.js +2 -30
- package/src/services/assets/asset-processing-service/processors/stylesheet/stylesheet-processor-pipeline.d.ts +2 -0
- package/src/services/assets/asset-processing-service/processors/stylesheet/stylesheet-processor-pipeline.js +43 -0
- package/src/services/assets/browser-bundle.service.d.ts +3 -1
- package/src/services/assets/browser-bundle.service.js +17 -5
- package/src/services/html/html-transformer.service.d.ts +1 -1
- package/src/services/html/html-transformer.service.js +4 -4
- package/src/services/invalidation/development-invalidation.service.d.ts +10 -1
- package/src/services/invalidation/development-invalidation.service.js +31 -2
- package/src/services/module-loading/README.md +49 -0
- package/src/services/module-loading/app-server-module-transpiler.service.js +5 -17
- package/src/services/module-loading/page-module-import.service.d.ts +4 -1
- package/src/services/module-loading/page-module-import.service.js +61 -41
- package/src/services/module-loading/route-module-build-cache-registry.d.ts +24 -0
- package/src/services/module-loading/route-module-build-cache-registry.js +37 -0
- package/src/services/module-loading/route-module-build-cache.d.ts +4 -0
- package/src/services/module-loading/route-module-build-cache.js +38 -0
- package/src/services/module-loading/route-module-build-cache.store.d.ts +57 -0
- package/src/services/module-loading/route-module-build-cache.store.js +207 -0
- package/src/services/module-loading/route-module-build-manifest.d.ts +61 -0
- package/src/services/module-loading/route-module-build-manifest.js +116 -0
- package/src/services/module-loading/route-module-dependency-hasher.d.ts +81 -0
- package/src/services/module-loading/route-module-dependency-hasher.js +121 -0
- package/src/services/module-loading/server-module-transpiler.service.js +1 -1
- package/src/static-site-generator/README.md +33 -0
- package/src/static-site-generator/static-build-invalidation.d.ts +10 -0
- package/src/static-site-generator/static-build-invalidation.js +59 -0
- package/src/static-site-generator/static-export-context.d.ts +22 -0
- package/src/static-site-generator/static-export-context.js +0 -0
- package/src/static-site-generator/static-site-generator.d.ts +17 -20
- package/src/static-site-generator/static-site-generator.js +188 -85
- package/src/types/internal-types.d.ts +12 -9
- package/src/types/public-types.d.ts +87 -22
- package/src/utils/parse-cli-args.d.ts +1 -0
- package/src/utils/parse-cli-args.js +3 -0
- package/src/watchers/project-watcher.d.ts +14 -2
- package/src/watchers/project-watcher.js +50 -20
- package/src/build/rolldown-dev-build-adapter.d.ts +0 -82
- package/src/build/rolldown-dev-build-adapter.js +0 -166
- package/src/hmr/hmr.postcss.test.e2e.d.ts +0 -1
- package/src/hmr/hmr.postcss.test.e2e.js +0 -31
- package/src/hmr/hmr.test.e2e.d.ts +0 -1
- package/src/hmr/hmr.test.e2e.js +0 -43
- package/src/route-renderer/orchestration/ownership-planning.service.d.ts +0 -24
- package/src/route-renderer/orchestration/ownership-planning.service.js +0 -63
- package/src/route-renderer/orchestration/queued-foreign-subtree-resolution.service.d.ts +0 -91
- package/src/route-renderer/orchestration/queued-foreign-subtree-resolution.service.js +0 -170
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { fileSystem } from "@ecopages/file-system";
|
|
3
|
+
import { RESOLVED_ASSETS_DIR } from "../../config/constants.js";
|
|
4
|
+
import { disposeAppBuildRuntime } from "../../build/build-runtime.js";
|
|
5
|
+
import { getAppBrowserBuildPlugins } from "../../build/build-adapter.js";
|
|
6
|
+
import { copyRuntimePublicDirIfChanged } from "./copy-runtime-public-dir.js";
|
|
7
|
+
import { injectHmrRuntimeIntoHtmlResponse, isHtmlResponse, shouldInjectHmrHtmlResponse } from "./hmr-html-response.js";
|
|
8
|
+
function prepareRuntimePublicDir(appConfig) {
|
|
9
|
+
const srcPublicDir = path.join(appConfig.rootDir, appConfig.srcDir, appConfig.publicDir);
|
|
10
|
+
if (fileSystem.exists(srcPublicDir)) {
|
|
11
|
+
copyRuntimePublicDirIfChanged(srcPublicDir, path.join(appConfig.rootDir, appConfig.distDir));
|
|
12
|
+
}
|
|
13
|
+
fileSystem.ensureDir(path.join(appConfig.absolutePaths.distDir, RESOLVED_ASSETS_DIR));
|
|
14
|
+
}
|
|
15
|
+
function wireIntegrationHmrManagers(appConfig, hmrManager) {
|
|
16
|
+
hmrManager.setPlugins(getAppBrowserBuildPlugins(appConfig));
|
|
17
|
+
for (const integration of appConfig.integrations) {
|
|
18
|
+
integration.setHmrManager(hmrManager);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
async function maybeInjectAdapterHmrHtmlResponse(response, options) {
|
|
22
|
+
if (shouldInjectHmrHtmlResponse(options.watch, options.hmrManager, options.hostOwnsDevClient) && isHtmlResponse(response)) {
|
|
23
|
+
return injectHmrRuntimeIntoHtmlResponse(response);
|
|
24
|
+
}
|
|
25
|
+
return response;
|
|
26
|
+
}
|
|
27
|
+
async function disposeDevResources(options) {
|
|
28
|
+
await options.projectWatcher?.close();
|
|
29
|
+
await disposeAppBuildRuntime(options.appConfig);
|
|
30
|
+
options.hmrManager?.stop();
|
|
31
|
+
options.bridge?.destroy();
|
|
32
|
+
await options.previewHost.stop();
|
|
33
|
+
}
|
|
34
|
+
export {
|
|
35
|
+
disposeDevResources,
|
|
36
|
+
maybeInjectAdapterHmrHtmlResponse,
|
|
37
|
+
prepareRuntimePublicDir,
|
|
38
|
+
wireIntegrationHmrManagers
|
|
39
|
+
};
|
|
@@ -21,7 +21,8 @@ export declare abstract class SharedServerAdapter<TOptions extends ServerAdapter
|
|
|
21
21
|
protected routeHandler: ServerRouteHandler;
|
|
22
22
|
protected staticSiteGenerator: StaticSiteGenerator;
|
|
23
23
|
protected staticBuilder: ServerStaticBuilder;
|
|
24
|
-
protected
|
|
24
|
+
protected schemaValidator: SchemaValidationService;
|
|
25
|
+
protected hostOwnsDevClient: boolean;
|
|
25
26
|
protected initializeSharedRouteHandling(options: {
|
|
26
27
|
staticRoutes: StaticRoute[];
|
|
27
28
|
hmrManager?: any;
|
|
@@ -27,6 +27,7 @@ class SharedServerAdapter extends AbstractServerAdapter {
|
|
|
27
27
|
staticSiteGenerator;
|
|
28
28
|
staticBuilder;
|
|
29
29
|
schemaValidator = new SchemaValidationService();
|
|
30
|
+
hostOwnsDevClient = false;
|
|
30
31
|
async initializeSharedRouteHandling(options) {
|
|
31
32
|
await this.initSharedRouter();
|
|
32
33
|
this.configureSharedResponseHandlers(options.staticRoutes, options.hmrManager);
|
|
@@ -76,7 +77,7 @@ class SharedServerAdapter extends AbstractServerAdapter {
|
|
|
76
77
|
const module = await serverModuleTranspiler.importModule({
|
|
77
78
|
filePath,
|
|
78
79
|
outdir: path.join(resolveInternalExecutionDir(this.appConfig), ".server-route-modules"),
|
|
79
|
-
externalPackages:
|
|
80
|
+
externalPackages: true,
|
|
80
81
|
transpileErrorMessage: (details) => `Error transpiling route module: ${details}`,
|
|
81
82
|
noOutputMessage: (targetFilePath) => `No transpiled output generated for route module: ${targetFilePath}`
|
|
82
83
|
});
|
|
@@ -115,7 +116,8 @@ class SharedServerAdapter extends AbstractServerAdapter {
|
|
|
115
116
|
fileSystemResponseMatcher: this.fileSystemResponseMatcher,
|
|
116
117
|
explicitStaticRouteMatcher,
|
|
117
118
|
watch: !!this.options?.watch,
|
|
118
|
-
hmrManager
|
|
119
|
+
hmrManager,
|
|
120
|
+
hostOwnsDevClient: this.hostOwnsDevClient
|
|
119
121
|
});
|
|
120
122
|
}
|
|
121
123
|
createSharedResponseHandlerDependencies(staticRoutes) {
|
|
@@ -380,7 +382,10 @@ class SharedServerAdapter extends AbstractServerAdapter {
|
|
|
380
382
|
const runtimePath = context.hmrManager.getRuntimePath();
|
|
381
383
|
if (fileSystem.exists(runtimePath)) {
|
|
382
384
|
return new Response(fileSystem.readFileAsBuffer(runtimePath), {
|
|
383
|
-
headers: {
|
|
385
|
+
headers: {
|
|
386
|
+
"Content-Type": "application/javascript",
|
|
387
|
+
"Cache-Control": "no-store, must-revalidate"
|
|
388
|
+
}
|
|
384
389
|
});
|
|
385
390
|
}
|
|
386
391
|
}
|
|
@@ -389,7 +394,10 @@ class SharedServerAdapter extends AbstractServerAdapter {
|
|
|
389
394
|
const assetPath = path.join(context.hmrManager.getDistDir(), relativePath);
|
|
390
395
|
if (fileSystem.exists(assetPath)) {
|
|
391
396
|
return new Response(fileSystem.readFileAsBuffer(assetPath), {
|
|
392
|
-
headers: {
|
|
397
|
+
headers: {
|
|
398
|
+
"Content-Type": "application/javascript",
|
|
399
|
+
"Cache-Control": "no-store, must-revalidate"
|
|
400
|
+
}
|
|
393
401
|
});
|
|
394
402
|
}
|
|
395
403
|
}
|
|
@@ -16,6 +16,8 @@ export interface ServerRouteHandlerParams {
|
|
|
16
16
|
watch?: boolean;
|
|
17
17
|
/** HMR manager for broadcasting hot module reload events in development. */
|
|
18
18
|
hmrManager?: IHmrManager;
|
|
19
|
+
/** When true, the host dev server owns browser dev-client bootstrap. */
|
|
20
|
+
hostOwnsDevClient?: boolean;
|
|
19
21
|
}
|
|
20
22
|
/**
|
|
21
23
|
* Handles HTTP requests and routing for the server.
|
|
@@ -33,12 +35,13 @@ export declare class ServerRouteHandler {
|
|
|
33
35
|
private readonly explicitStaticRouteMatcher?;
|
|
34
36
|
private readonly watch;
|
|
35
37
|
private readonly hmrManager?;
|
|
38
|
+
private readonly hostOwnsDevClient;
|
|
36
39
|
/**
|
|
37
40
|
* Creates a new ServerRouteHandler instance.
|
|
38
41
|
*
|
|
39
42
|
* @param params - Configuration parameters
|
|
40
43
|
*/
|
|
41
|
-
constructor({ router, fileSystemResponseMatcher, explicitStaticRouteMatcher, watch, hmrManager, }: ServerRouteHandlerParams);
|
|
44
|
+
constructor({ router, fileSystemResponseMatcher, explicitStaticRouteMatcher, watch, hmrManager, hostOwnsDevClient, }: ServerRouteHandlerParams);
|
|
42
45
|
/**
|
|
43
46
|
* Determines if HMR script should be injected.
|
|
44
47
|
*
|
|
@@ -7,6 +7,7 @@ class ServerRouteHandler {
|
|
|
7
7
|
explicitStaticRouteMatcher;
|
|
8
8
|
watch;
|
|
9
9
|
hmrManager;
|
|
10
|
+
hostOwnsDevClient;
|
|
10
11
|
/**
|
|
11
12
|
* Creates a new ServerRouteHandler instance.
|
|
12
13
|
*
|
|
@@ -17,13 +18,15 @@ class ServerRouteHandler {
|
|
|
17
18
|
fileSystemResponseMatcher,
|
|
18
19
|
explicitStaticRouteMatcher,
|
|
19
20
|
watch = false,
|
|
20
|
-
hmrManager
|
|
21
|
+
hmrManager,
|
|
22
|
+
hostOwnsDevClient = false
|
|
21
23
|
}) {
|
|
22
24
|
this.router = router;
|
|
23
25
|
this.fileSystemResponseMatcher = fileSystemResponseMatcher;
|
|
24
26
|
this.explicitStaticRouteMatcher = explicitStaticRouteMatcher;
|
|
25
27
|
this.watch = watch;
|
|
26
28
|
this.hmrManager = hmrManager;
|
|
29
|
+
this.hostOwnsDevClient = hostOwnsDevClient;
|
|
27
30
|
}
|
|
28
31
|
/**
|
|
29
32
|
* Determines if HMR script should be injected.
|
|
@@ -31,7 +34,7 @@ class ServerRouteHandler {
|
|
|
31
34
|
* @returns true if in watch mode and HMR manager is enabled
|
|
32
35
|
*/
|
|
33
36
|
shouldInjectHmrScript() {
|
|
34
|
-
return shouldInjectHmrHtmlResponse(this.watch, this.hmrManager);
|
|
37
|
+
return shouldInjectHmrHtmlResponse(this.watch, this.hmrManager, this.hostOwnsDevClient);
|
|
35
38
|
}
|
|
36
39
|
/**
|
|
37
40
|
* Checks if a response contains HTML content.
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import type { EcoPagesAppConfig } from '../../types/internal-types.js';
|
|
1
|
+
import type { EcoPagesAppConfig, IHmrManager } from '../../types/internal-types.js';
|
|
2
|
+
import type { EcoBuildPlugin } from '../../build/build-types.js';
|
|
2
3
|
import type { ApiHandler, StaticRoute } from '../../types/public-types.js';
|
|
3
4
|
import type { RouteRegistry } from '../../router/server/route-registry.js';
|
|
4
5
|
import type { StaticSiteGenerator } from '../../static-site-generator/static-site-generator.js';
|
|
5
6
|
import type { StaticGenerationRendererResolver } from '../../route-renderer/route-renderer.js';
|
|
6
7
|
export interface StaticBuildOptions {
|
|
7
|
-
preview?: boolean;
|
|
8
8
|
baseUrl?: string;
|
|
9
|
+
force?: boolean;
|
|
9
10
|
}
|
|
10
11
|
export interface ServeOptions {
|
|
11
12
|
hostname?: string;
|
|
@@ -15,10 +16,12 @@ export interface ServerStaticBuilderParams {
|
|
|
15
16
|
appConfig: EcoPagesAppConfig;
|
|
16
17
|
staticSiteGenerator: StaticSiteGenerator;
|
|
17
18
|
serveOptions: ServeOptions;
|
|
19
|
+
runtimeOrigin: string;
|
|
18
20
|
apiHandlers?: ApiHandler[];
|
|
19
21
|
logger?: ServerStaticBuilderLogger;
|
|
20
|
-
previewServerFactory?: ServerStaticPreviewServerFactory;
|
|
21
22
|
entryFile?: string;
|
|
23
|
+
hmrManager?: IHmrManager;
|
|
24
|
+
onRuntimePlugin?: (plugin: EcoBuildPlugin) => void;
|
|
22
25
|
}
|
|
23
26
|
/**
|
|
24
27
|
* Minimal logger dependency used by the static builder.
|
|
@@ -29,50 +32,33 @@ export interface ServerStaticBuilderLogger {
|
|
|
29
32
|
error(message: string): unknown;
|
|
30
33
|
}
|
|
31
34
|
/**
|
|
32
|
-
*
|
|
33
|
-
*/
|
|
34
|
-
export interface ServerStaticPreviewServerFactory {
|
|
35
|
-
createServer(args: {
|
|
36
|
-
appConfig: EcoPagesAppConfig;
|
|
37
|
-
options: {
|
|
38
|
-
port: number;
|
|
39
|
-
};
|
|
40
|
-
}): {
|
|
41
|
-
server?: {
|
|
42
|
-
port?: number;
|
|
43
|
-
} | null;
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Handles static site generation and previews.
|
|
35
|
+
* Handles static site generation.
|
|
48
36
|
*/
|
|
49
37
|
export declare class ServerStaticBuilder {
|
|
50
38
|
private readonly appConfig;
|
|
51
39
|
private readonly staticSiteGenerator;
|
|
52
40
|
private readonly serveOptions;
|
|
41
|
+
private readonly runtimeOrigin;
|
|
53
42
|
private readonly apiHandlers;
|
|
54
43
|
private readonly logger;
|
|
55
|
-
private readonly previewServerFactory;
|
|
56
44
|
private readonly entryFile;
|
|
57
|
-
|
|
58
|
-
private
|
|
45
|
+
private readonly hmrManager?;
|
|
46
|
+
private readonly onRuntimePlugin?;
|
|
47
|
+
constructor({ appConfig, staticSiteGenerator, serveOptions, runtimeOrigin, apiHandlers, logger, entryFile, hmrManager, onRuntimePlugin, }: ServerStaticBuilderParams);
|
|
59
48
|
private prepareExportDirectory;
|
|
60
49
|
private refreshRuntimeAssets;
|
|
61
50
|
/**
|
|
62
51
|
* Bundles the server entry file for production use.
|
|
63
52
|
*
|
|
64
53
|
* @remarks
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
* `dist/{SERVER_BUNDLE_DIR}/{SERVER_BUNDLE_FILENAME}` and used by
|
|
69
|
-
* `ecopages start` in production.
|
|
54
|
+
* Every production build emits a runnable server entry for `ecopages start`,
|
|
55
|
+
* including static-only and websocket-only apps. Incremental builds may skip
|
|
56
|
+
* Rolldown when the `.eco/.server-entry` cache is still valid.
|
|
70
57
|
*
|
|
71
58
|
* Package imports remain external so native addons and runtime-owned
|
|
72
59
|
* dependencies continue to load through the app's installed
|
|
73
60
|
* `node_modules` tree. Only the app entry graph is bundled.
|
|
74
61
|
*
|
|
75
|
-
* Skips silently when no API endpoints are registered (static-only site).
|
|
76
62
|
* Throws if the build adapter is unavailable, is owned by a host
|
|
77
63
|
* runtime, or bundling fails.
|
|
78
64
|
*
|
|
@@ -81,7 +67,6 @@ export declare class ServerStaticBuilder {
|
|
|
81
67
|
private bundleServerEntry;
|
|
82
68
|
/**
|
|
83
69
|
* Generates a static build of the site for deployment.
|
|
84
|
-
* @param options.preview - If true, starts a preview server after build
|
|
85
70
|
* @param dependencies.router - The initialized router
|
|
86
71
|
* @param dependencies.routeRendererFactory - The route renderer factory
|
|
87
72
|
* @param dependencies.staticRoutes - Explicit static routes registered via app.static()
|
|
@@ -1,53 +1,65 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { fileSystem } from "@ecopages/file-system";
|
|
3
3
|
import { DEFAULT_ECOPAGES_HOSTNAME, DEFAULT_ECOPAGES_PORT } from "../../config/constants.js";
|
|
4
|
-
import { StaticContentServer } from "../../dev/sc-server.js";
|
|
5
4
|
import { appLogger } from "../../global/app-logger.js";
|
|
6
|
-
import { getAppBuildAdapter } from "../../build/build-adapter.js";
|
|
7
|
-
import {
|
|
5
|
+
import { build, getAppBuildAdapter, setupAppRuntimePlugins } from "../../build/build-adapter.js";
|
|
6
|
+
import { resolveBuildProfileOptions } from "../../build/build-profile-options.js";
|
|
7
|
+
import {
|
|
8
|
+
getServerBundleOutputPaths,
|
|
9
|
+
lookupServerEntryBuildCache,
|
|
10
|
+
recordServerEntryBuildCache,
|
|
11
|
+
writeServerBundleDeployManifest
|
|
12
|
+
} from "../../build/server-entry-build-cache.js";
|
|
13
|
+
import { getInstalledServerEntryBuildExecutor } from "../../build/runtime-build-executor.js";
|
|
14
|
+
import {
|
|
15
|
+
clearProductionBuildCaches,
|
|
16
|
+
shouldResetStaticExportDirectory
|
|
17
|
+
} from "../../static-site-generator/static-build-invalidation.js";
|
|
18
|
+
import { resolveEntryFile, SERVER_BUNDLE_FILENAME } from "../../utils/resolve-entry-file.js";
|
|
8
19
|
class ServerStaticBuilder {
|
|
9
20
|
appConfig;
|
|
10
21
|
staticSiteGenerator;
|
|
11
22
|
serveOptions;
|
|
23
|
+
runtimeOrigin;
|
|
12
24
|
apiHandlers;
|
|
13
25
|
logger;
|
|
14
|
-
previewServerFactory;
|
|
15
26
|
entryFile;
|
|
27
|
+
hmrManager;
|
|
28
|
+
onRuntimePlugin;
|
|
16
29
|
constructor({
|
|
17
30
|
appConfig,
|
|
18
31
|
staticSiteGenerator,
|
|
19
32
|
serveOptions,
|
|
33
|
+
runtimeOrigin,
|
|
20
34
|
apiHandlers,
|
|
21
35
|
logger,
|
|
22
|
-
|
|
23
|
-
|
|
36
|
+
entryFile,
|
|
37
|
+
hmrManager,
|
|
38
|
+
onRuntimePlugin
|
|
24
39
|
}) {
|
|
25
40
|
this.appConfig = appConfig;
|
|
26
41
|
this.staticSiteGenerator = staticSiteGenerator;
|
|
27
42
|
this.serveOptions = serveOptions;
|
|
43
|
+
this.runtimeOrigin = runtimeOrigin;
|
|
28
44
|
this.apiHandlers = apiHandlers ?? [];
|
|
29
45
|
this.logger = logger ?? appLogger;
|
|
30
|
-
this.previewServerFactory = previewServerFactory ?? StaticContentServer;
|
|
31
46
|
this.entryFile = resolveEntryFile({ entryFile });
|
|
47
|
+
this.hmrManager = hmrManager;
|
|
48
|
+
this.onRuntimePlugin = onRuntimePlugin;
|
|
32
49
|
}
|
|
33
|
-
|
|
34
|
-
if (
|
|
35
|
-
|
|
50
|
+
prepareExportDirectory(force) {
|
|
51
|
+
if (force) {
|
|
52
|
+
clearProductionBuildCaches(this.appConfig);
|
|
36
53
|
}
|
|
37
|
-
const uniqueHandlers = Array.from(
|
|
38
|
-
new Set(this.apiHandlers.map((handler) => `${handler.method} ${handler.path}`))
|
|
39
|
-
);
|
|
40
|
-
const visibleHandlers = uniqueHandlers.slice(0, 5).join(", ");
|
|
41
|
-
const remainingCount = uniqueHandlers.length - Math.min(uniqueHandlers.length, 5);
|
|
42
|
-
const summary = remainingCount > 0 ? `${visibleHandlers}, +${remainingCount} more` : visibleHandlers;
|
|
43
|
-
this.logger.warn(
|
|
44
|
-
"Registered API endpoints are not available in static build or preview modes because no server runtime is started. They are excluded from the generated output.\n",
|
|
45
|
-
`\u27A4 ${summary}`
|
|
46
|
-
);
|
|
47
|
-
}
|
|
48
|
-
prepareExportDirectory() {
|
|
49
54
|
const exportDir = this.appConfig.absolutePaths?.distDir ?? path.join(this.appConfig.rootDir, this.appConfig.distDir);
|
|
50
|
-
|
|
55
|
+
const shouldCleanDist = shouldResetStaticExportDirectory(this.appConfig, force);
|
|
56
|
+
fileSystem.ensureDir(exportDir, shouldCleanDist);
|
|
57
|
+
if (shouldCleanDist) {
|
|
58
|
+
this.appConfig.runtime = {
|
|
59
|
+
...this.appConfig.runtime ?? {},
|
|
60
|
+
runtimeAssetsPrepared: false
|
|
61
|
+
};
|
|
62
|
+
}
|
|
51
63
|
const srcPublicDir = path.join(
|
|
52
64
|
this.appConfig.rootDir,
|
|
53
65
|
this.appConfig.srcDir ?? "src",
|
|
@@ -56,39 +68,39 @@ class ServerStaticBuilder {
|
|
|
56
68
|
if (fileSystem.exists(srcPublicDir)) {
|
|
57
69
|
fileSystem.copyDir(srcPublicDir, exportDir);
|
|
58
70
|
}
|
|
71
|
+
return !shouldCleanDist;
|
|
59
72
|
}
|
|
60
73
|
async refreshRuntimeAssets() {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
74
|
+
appLogger.debugTime("refreshRuntimeAssets");
|
|
75
|
+
try {
|
|
76
|
+
await setupAppRuntimePlugins({
|
|
77
|
+
appConfig: this.appConfig,
|
|
78
|
+
runtimeOrigin: this.runtimeOrigin,
|
|
79
|
+
hmrManager: this.hmrManager,
|
|
80
|
+
onRuntimePlugin: this.onRuntimePlugin
|
|
81
|
+
});
|
|
82
|
+
} finally {
|
|
83
|
+
appLogger.debugTimeEnd("refreshRuntimeAssets");
|
|
66
84
|
}
|
|
67
85
|
}
|
|
68
86
|
/**
|
|
69
87
|
* Bundles the server entry file for production use.
|
|
70
88
|
*
|
|
71
89
|
* @remarks
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
* `dist/{SERVER_BUNDLE_DIR}/{SERVER_BUNDLE_FILENAME}` and used by
|
|
76
|
-
* `ecopages start` in production.
|
|
90
|
+
* Every production build emits a runnable server entry for `ecopages start`,
|
|
91
|
+
* including static-only and websocket-only apps. Incremental builds may skip
|
|
92
|
+
* Rolldown when the `.eco/.server-entry` cache is still valid.
|
|
77
93
|
*
|
|
78
94
|
* Package imports remain external so native addons and runtime-owned
|
|
79
95
|
* dependencies continue to load through the app's installed
|
|
80
96
|
* `node_modules` tree. Only the app entry graph is bundled.
|
|
81
97
|
*
|
|
82
|
-
* Skips silently when no API endpoints are registered (static-only site).
|
|
83
98
|
* Throws if the build adapter is unavailable, is owned by a host
|
|
84
99
|
* runtime, or bundling fails.
|
|
85
100
|
*
|
|
86
101
|
* @throws If the build adapter is unavailable, is host-owned, or bundling fails.
|
|
87
102
|
*/
|
|
88
|
-
async bundleServerEntry() {
|
|
89
|
-
if (this.apiHandlers.length === 0) {
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
103
|
+
async bundleServerEntry(options) {
|
|
92
104
|
const buildAdapter = getAppBuildAdapter(this.appConfig);
|
|
93
105
|
if (buildAdapter.ownership === "vite-host") {
|
|
94
106
|
throw new Error(
|
|
@@ -101,60 +113,69 @@ class ServerStaticBuilder {
|
|
|
101
113
|
`Cannot bundle server entry: file "${this.entryFile}" not found in "${this.appConfig.rootDir}".`
|
|
102
114
|
);
|
|
103
115
|
}
|
|
104
|
-
const
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
outdir: serverOutdir,
|
|
110
|
-
naming: SERVER_BUNDLE_FILENAME,
|
|
111
|
-
target: "node",
|
|
112
|
-
format: "esm",
|
|
113
|
-
sourcemap: "hidden",
|
|
114
|
-
externalPackages: true,
|
|
115
|
-
root: this.appConfig.rootDir
|
|
116
|
+
const { serverOutdir, serverEntryPath } = getServerBundleOutputPaths(this.appConfig);
|
|
117
|
+
const cached = lookupServerEntryBuildCache({
|
|
118
|
+
appConfig: this.appConfig,
|
|
119
|
+
entryPath,
|
|
120
|
+
force: options?.force
|
|
116
121
|
});
|
|
122
|
+
if (cached) {
|
|
123
|
+
const hasBundle = cached.outputPaths.some(
|
|
124
|
+
(outputPath) => path.resolve(outputPath) === path.resolve(serverEntryPath) && fileSystem.exists(outputPath)
|
|
125
|
+
);
|
|
126
|
+
if (hasBundle) {
|
|
127
|
+
this.logger.info("Reusing cached server entry bundle");
|
|
128
|
+
writeServerBundleDeployManifest(this.appConfig, serverEntryPath);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
this.logger.info("Bundling server entry file...");
|
|
133
|
+
const buildOptions = {
|
|
134
|
+
...resolveBuildProfileOptions("server-entry", this.appConfig, {
|
|
135
|
+
entrypoints: [entryPath],
|
|
136
|
+
outdir: serverOutdir,
|
|
137
|
+
naming: SERVER_BUNDLE_FILENAME,
|
|
138
|
+
sourcemap: "hidden"
|
|
139
|
+
}),
|
|
140
|
+
entrypoints: [entryPath]
|
|
141
|
+
};
|
|
142
|
+
const result = await build(buildOptions, getInstalledServerEntryBuildExecutor(this.appConfig));
|
|
117
143
|
if (!result.success) {
|
|
118
144
|
const errorMessages = result.logs.map((log) => log.message).join("\n");
|
|
119
145
|
throw new Error(`Failed to bundle server entry file:
|
|
120
146
|
${errorMessages}`);
|
|
121
147
|
}
|
|
148
|
+
const outputPaths = result.outputs.length > 0 ? result.outputs.map((output) => output.path) : fileSystem.exists(serverEntryPath) ? [serverEntryPath] : [];
|
|
149
|
+
recordServerEntryBuildCache({
|
|
150
|
+
appConfig: this.appConfig,
|
|
151
|
+
entryPath,
|
|
152
|
+
buildResult: result,
|
|
153
|
+
outputPaths
|
|
154
|
+
});
|
|
155
|
+
writeServerBundleDeployManifest(this.appConfig, serverEntryPath);
|
|
122
156
|
this.logger.info("Server entry file bundled successfully");
|
|
123
157
|
}
|
|
124
158
|
/**
|
|
125
159
|
* Generates a static build of the site for deployment.
|
|
126
|
-
* @param options.preview - If true, starts a preview server after build
|
|
127
160
|
* @param dependencies.router - The initialized router
|
|
128
161
|
* @param dependencies.routeRendererFactory - The route renderer factory
|
|
129
162
|
* @param dependencies.staticRoutes - Explicit static routes registered via app.static()
|
|
130
163
|
*/
|
|
131
164
|
async build(options, dependencies) {
|
|
132
|
-
const {
|
|
165
|
+
const { baseUrl: explicitBaseUrl, force = false } = options ?? {};
|
|
133
166
|
const baseUrl = explicitBaseUrl ?? `http://${this.serveOptions.hostname || DEFAULT_ECOPAGES_HOSTNAME}:${this.serveOptions.port || DEFAULT_ECOPAGES_PORT}`;
|
|
134
|
-
this.
|
|
135
|
-
this.prepareExportDirectory();
|
|
167
|
+
const preserveExportDirectory = this.prepareExportDirectory(force);
|
|
136
168
|
await this.refreshRuntimeAssets();
|
|
137
|
-
await this.bundleServerEntry();
|
|
169
|
+
await this.bundleServerEntry({ force });
|
|
138
170
|
await this.staticSiteGenerator.run({
|
|
139
171
|
router: dependencies.router,
|
|
140
172
|
baseUrl,
|
|
141
173
|
routeRendererFactory: dependencies.routeRendererFactory,
|
|
142
|
-
staticRoutes: dependencies.staticRoutes
|
|
174
|
+
staticRoutes: dependencies.staticRoutes,
|
|
175
|
+
force,
|
|
176
|
+
preserveExportDirectory
|
|
143
177
|
});
|
|
144
|
-
|
|
145
|
-
this.logger.info("Build completed");
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
const previewPort = this.serveOptions.port || DEFAULT_ECOPAGES_PORT;
|
|
149
|
-
const { server } = this.previewServerFactory.createServer({
|
|
150
|
-
appConfig: this.appConfig,
|
|
151
|
-
options: { port: Number(previewPort) }
|
|
152
|
-
});
|
|
153
|
-
if (server?.port) {
|
|
154
|
-
this.logger.info(`Preview running at http://localhost:${server.port}`);
|
|
155
|
-
} else {
|
|
156
|
-
this.logger.error("Failed to start preview server");
|
|
157
|
-
}
|
|
178
|
+
this.logger.info("Build completed");
|
|
158
179
|
}
|
|
159
180
|
}
|
|
160
181
|
export {
|
|
@@ -10,6 +10,7 @@ import type { ServerModuleTranspiler } from '../../services/module-loading/serve
|
|
|
10
10
|
type HandleFileChangeOptions = {
|
|
11
11
|
broadcast?: boolean;
|
|
12
12
|
};
|
|
13
|
+
export declare function resolveHmrRegistrationTimeoutMs(explicitTimeoutMs?: number): number;
|
|
13
14
|
type SharedHmrManagerParams = {
|
|
14
15
|
appConfig: EcoPagesAppConfig;
|
|
15
16
|
bridge: IClientBridge;
|
|
@@ -45,6 +46,16 @@ export declare abstract class SharedHmrManager implements IHmrManager {
|
|
|
45
46
|
broadcast(event: ClientBridgeEvent): void;
|
|
46
47
|
handleFileChange(filePath: string, options?: HandleFileChangeOptions): Promise<void>;
|
|
47
48
|
getOutputUrl(entrypointPath: string): string | undefined;
|
|
49
|
+
/**
|
|
50
|
+
* Returns the emitted HMR script output when the artifact already exists on disk.
|
|
51
|
+
*
|
|
52
|
+
* SSR must not block on entrypoint registration when a previous build already
|
|
53
|
+
* produced the browser bundle.
|
|
54
|
+
*/
|
|
55
|
+
getResolvedScriptOutput(entrypointPath: string): {
|
|
56
|
+
outputUrl: string;
|
|
57
|
+
outputPath: string;
|
|
58
|
+
} | undefined;
|
|
48
59
|
getWatchedFiles(): Map<string, string>;
|
|
49
60
|
getDistDir(): string;
|
|
50
61
|
getPlugins(): EcoBuildPlugin[];
|
|
@@ -55,5 +66,6 @@ export declare abstract class SharedHmrManager implements IHmrManager {
|
|
|
55
66
|
protected emitStrictEntrypoint(entrypointPath: string): Promise<void>;
|
|
56
67
|
protected emitScriptEntrypoint(entrypointPath: string, outputPath: string): Promise<void>;
|
|
57
68
|
stop(): void;
|
|
69
|
+
[Symbol.dispose](): void;
|
|
58
70
|
}
|
|
59
71
|
export {};
|
|
@@ -2,11 +2,13 @@ import fs from "node:fs";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
import { RESOLVED_ASSETS_DIR } from "../../config/constants.js";
|
|
5
|
-
import {
|
|
5
|
+
import { requireBuildRuntime } from "../../build/build-runtime.js";
|
|
6
6
|
import { fileSystem } from "@ecopages/file-system";
|
|
7
7
|
import { HmrStrategyType } from "../../hmr/hmr-strategy.js";
|
|
8
8
|
import { DefaultHmrStrategy } from "../../hmr/strategies/default-hmr-strategy.js";
|
|
9
9
|
import { JsHmrStrategy } from "../../hmr/strategies/js-hmr-strategy.js";
|
|
10
|
+
import { ServerRenderedTemplateHmrStrategy } from "../../hmr/strategies/server-rendered-template-hmr-strategy.js";
|
|
11
|
+
import { DevelopmentInvalidationService } from "../../services/invalidation/development-invalidation.service.js";
|
|
10
12
|
import { appLogger } from "../../global/app-logger.js";
|
|
11
13
|
import { HmrEntrypointRegistrar } from "./hmr-entrypoint-registrar.js";
|
|
12
14
|
import { BrowserBundleService } from "../../services/assets/browser-bundle.service.js";
|
|
@@ -16,6 +18,24 @@ import {
|
|
|
16
18
|
setAppEntrypointDependencyGraph
|
|
17
19
|
} from "../../services/runtime-state/entrypoint-dependency-graph.service.js";
|
|
18
20
|
import { resolveInternalExecutionDir, resolveInternalWorkDir } from "../../utils/resolve-work-dir.js";
|
|
21
|
+
const DEFAULT_HMR_REGISTRATION_TIMEOUT_MS = 4e3;
|
|
22
|
+
const DEVELOPMENT_HMR_REGISTRATION_TIMEOUT_MS = 15e3;
|
|
23
|
+
function resolveHmrRegistrationTimeoutMs(explicitTimeoutMs) {
|
|
24
|
+
if (explicitTimeoutMs !== void 0) {
|
|
25
|
+
return explicitTimeoutMs;
|
|
26
|
+
}
|
|
27
|
+
const envTimeoutMs = process.env.ECOPAGES_HMR_REGISTRATION_TIMEOUT_MS;
|
|
28
|
+
if (envTimeoutMs !== void 0 && envTimeoutMs !== "") {
|
|
29
|
+
const parsedTimeoutMs = Number(envTimeoutMs);
|
|
30
|
+
if (Number.isFinite(parsedTimeoutMs) && parsedTimeoutMs > 0) {
|
|
31
|
+
return parsedTimeoutMs;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (process.env.NODE_ENV === "development") {
|
|
35
|
+
return DEVELOPMENT_HMR_REGISTRATION_TIMEOUT_MS;
|
|
36
|
+
}
|
|
37
|
+
return DEFAULT_HMR_REGISTRATION_TIMEOUT_MS;
|
|
38
|
+
}
|
|
19
39
|
class SharedHmrManager {
|
|
20
40
|
appConfig;
|
|
21
41
|
bridge;
|
|
@@ -24,13 +44,13 @@ class SharedHmrManager {
|
|
|
24
44
|
entrypointRegistrations = /* @__PURE__ */ new Map();
|
|
25
45
|
distDir;
|
|
26
46
|
plugins = [];
|
|
27
|
-
enabled =
|
|
47
|
+
enabled = false;
|
|
28
48
|
strategies = [];
|
|
29
49
|
entrypointRegistrar;
|
|
30
50
|
browserBundleService;
|
|
31
51
|
entrypointDependencyGraph;
|
|
32
52
|
serverModuleTranspiler;
|
|
33
|
-
constructor({ appConfig, bridge, registrationTimeoutMs
|
|
53
|
+
constructor({ appConfig, bridge, registrationTimeoutMs }) {
|
|
34
54
|
this.appConfig = appConfig;
|
|
35
55
|
this.bridge = bridge;
|
|
36
56
|
this.distDir = path.join(resolveInternalWorkDir(this.appConfig), RESOLVED_ASSETS_DIR, "_hmr");
|
|
@@ -40,7 +60,7 @@ class SharedHmrManager {
|
|
|
40
60
|
entrypointRegistrations: this.entrypointRegistrations,
|
|
41
61
|
watchedFiles: this.watchedFiles,
|
|
42
62
|
clearFailedRegistration: (entrypointPath) => this.clearFailedEntrypointRegistration(entrypointPath),
|
|
43
|
-
registrationTimeoutMs
|
|
63
|
+
registrationTimeoutMs: resolveHmrRegistrationTimeoutMs(registrationTimeoutMs)
|
|
44
64
|
});
|
|
45
65
|
this.browserBundleService = new BrowserBundleService(appConfig);
|
|
46
66
|
this.entrypointDependencyGraph = this.createEntrypointDependencyGraph(
|
|
@@ -86,7 +106,12 @@ class SharedHmrManager {
|
|
|
86
106
|
getEntrypointDependencyGraph: () => this.entrypointDependencyGraph,
|
|
87
107
|
shouldProcessEntrypoint: (entrypointPath) => this.shouldJsStrategyProcessEntrypoint(entrypointPath)
|
|
88
108
|
};
|
|
89
|
-
|
|
109
|
+
const invalidationService = new DevelopmentInvalidationService(this.appConfig);
|
|
110
|
+
this.strategies = [
|
|
111
|
+
new JsHmrStrategy(jsContext),
|
|
112
|
+
new ServerRenderedTemplateHmrStrategy(invalidationService),
|
|
113
|
+
new DefaultHmrStrategy()
|
|
114
|
+
];
|
|
90
115
|
}
|
|
91
116
|
registerStrategy(strategy) {
|
|
92
117
|
this.strategies.push(strategy);
|
|
@@ -158,6 +183,24 @@ class SharedHmrManager {
|
|
|
158
183
|
getOutputUrl(entrypointPath) {
|
|
159
184
|
return this.watchedFiles.get(entrypointPath);
|
|
160
185
|
}
|
|
186
|
+
/**
|
|
187
|
+
* Returns the emitted HMR script output when the artifact already exists on disk.
|
|
188
|
+
*
|
|
189
|
+
* SSR must not block on entrypoint registration when a previous build already
|
|
190
|
+
* produced the browser bundle.
|
|
191
|
+
*/
|
|
192
|
+
getResolvedScriptOutput(entrypointPath) {
|
|
193
|
+
const normalizedEntrypoint = path.resolve(entrypointPath);
|
|
194
|
+
const relativePath = path.relative(this.appConfig.absolutePaths.srcDir, normalizedEntrypoint);
|
|
195
|
+
const relativePathJs = relativePath.replace(/\.(tsx?|jsx?|mdx?)$/, ".js").replace(/\[([^\]]+)\]/g, "_$1_");
|
|
196
|
+
const urlPath = relativePathJs.split(path.sep).join("/");
|
|
197
|
+
const outputPath = path.join(this.distDir, urlPath);
|
|
198
|
+
if (!fileSystem.exists(outputPath)) {
|
|
199
|
+
return void 0;
|
|
200
|
+
}
|
|
201
|
+
const outputUrl = this.watchedFiles.get(normalizedEntrypoint) ?? `/${path.join(RESOLVED_ASSETS_DIR, "_hmr", urlPath).split(path.sep).join("/")}`;
|
|
202
|
+
return { outputUrl, outputPath };
|
|
203
|
+
}
|
|
161
204
|
getWatchedFiles() {
|
|
162
205
|
return this.watchedFiles;
|
|
163
206
|
}
|
|
@@ -175,7 +218,7 @@ class SharedHmrManager {
|
|
|
175
218
|
getSrcDir: () => this.appConfig.absolutePaths.srcDir,
|
|
176
219
|
getLayoutsDir: () => this.appConfig.absolutePaths.layoutsDir,
|
|
177
220
|
getPagesDir: () => this.appConfig.absolutePaths.pagesDir,
|
|
178
|
-
getBuildExecutor: () =>
|
|
221
|
+
getBuildExecutor: () => requireBuildRuntime(this.appConfig).getProfile("browser-hmr"),
|
|
179
222
|
getBrowserBundleService: () => this.browserBundleService,
|
|
180
223
|
getEntrypointDependencyGraph: () => this.entrypointDependencyGraph,
|
|
181
224
|
importServerModule: async (filePath) => await this.serverModuleTranspiler.importModule({
|
|
@@ -220,6 +263,16 @@ class SharedHmrManager {
|
|
|
220
263
|
appLogger.error(`[HMR] Generic script entrypoint build failed for ${entrypointPath}:`, buildResult.logs);
|
|
221
264
|
return;
|
|
222
265
|
}
|
|
266
|
+
if (!fileSystem.exists(outputPath) && buildResult.outputs.length > 0) {
|
|
267
|
+
const resolvedOutputPath = path.resolve(outputPath);
|
|
268
|
+
const emittedOutput = buildResult.outputs.find((output) => path.resolve(output.path) === resolvedOutputPath)?.path ?? buildResult.outputs.find((output) => path.basename(output.path) === path.basename(outputPath))?.path;
|
|
269
|
+
if (emittedOutput && fileSystem.exists(emittedOutput)) {
|
|
270
|
+
fileSystem.ensureDir(path.dirname(outputPath));
|
|
271
|
+
if (path.resolve(emittedOutput) !== resolvedOutputPath) {
|
|
272
|
+
fileSystem.copyFile(emittedOutput, outputPath);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
223
276
|
const entrypointDependencies = buildResult.dependencyGraph?.entrypoints?.[entrypointPath];
|
|
224
277
|
if (entrypointDependencies) {
|
|
225
278
|
this.entrypointDependencyGraph.setEntrypointDependencies(entrypointPath, entrypointDependencies);
|
|
@@ -235,7 +288,11 @@ class SharedHmrManager {
|
|
|
235
288
|
this.entrypointDependencyGraph.reset();
|
|
236
289
|
this.plugins = [];
|
|
237
290
|
}
|
|
291
|
+
[Symbol.dispose]() {
|
|
292
|
+
this.stop();
|
|
293
|
+
}
|
|
238
294
|
}
|
|
239
295
|
export {
|
|
240
|
-
SharedHmrManager
|
|
296
|
+
SharedHmrManager,
|
|
297
|
+
resolveHmrRegistrationTimeoutMs
|
|
241
298
|
};
|