@ecopages/core 0.2.0-beta.7 → 0.2.0-beta.8
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 +26 -2
- package/src/adapters/abstract/application-adapter.d.ts +12 -1
- package/src/adapters/abstract/application-adapter.js +13 -0
- package/src/adapters/abstract/server-adapter.d.ts +3 -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 +2 -0
- package/src/adapters/bun/create-app.js +28 -9
- package/src/adapters/bun/server-adapter.d.ts +13 -0
- package/src/adapters/bun/server-adapter.js +29 -4
- 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 +1 -0
- package/src/adapters/node/create-app.js +17 -7
- 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/server-adapter.d.ts +10 -13
- package/src/adapters/node/server-adapter.js +37 -82
- package/src/adapters/node/static-content-server.d.ts +1 -0
- package/src/adapters/node/static-content-server.js +3 -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/runtime-app-bootstrap.d.ts +0 -1
- package/src/adapters/shared/runtime-app-bootstrap.js +1 -6
- package/src/adapters/shared/server-static-builder.d.ts +4 -6
- package/src/adapters/shared/server-static-builder.js +90 -34
- package/src/adapters/shared/shared-hmr-manager.d.ts +1 -0
- package/src/adapters/shared/shared-hmr-manager.js +15 -2
- package/src/build/README.md +44 -4
- package/src/build/build-adapter.d.ts +8 -2
- package/src/build/build-adapter.js +71 -33
- package/src/build/build-input-fingerprint.d.ts +28 -0
- package/src/build/build-input-fingerprint.js +31 -0
- package/src/build/jsx-ownership-plugins.d.ts +10 -0
- package/src/build/jsx-ownership-plugins.js +17 -0
- package/src/build/pages-unified-graph-build.d.ts +31 -0
- package/src/build/pages-unified-graph-build.js +208 -0
- package/src/build/parallel-build-executor.d.ts +21 -0
- package/src/build/parallel-build-executor.js +52 -0
- package/src/build/rolldown-adapter-helpers.js +5 -0
- package/src/build/rolldown-build-adapter.js +2 -0
- 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-dev-build-adapter.d.ts +2 -2
- package/src/build/rolldown-dev-build-adapter.js +30 -14
- package/src/build/runtime-build-executor.d.ts +7 -13
- package/src/build/runtime-build-executor.js +31 -7
- package/src/build/server-entry-build-cache.d.ts +44 -0
- package/src/build/server-entry-build-cache.js +169 -0
- package/src/hmr/hmr.test.e2e.js +15 -4
- package/src/plugins/integration-plugin.d.ts +19 -8
- package/src/plugins/integration-plugin.js +7 -2
- package/src/plugins/processor.d.ts +5 -0
- package/src/plugins/processor.js +7 -0
- package/src/route-renderer/GRAPH.md +4 -4
- package/src/route-renderer/README.md +6 -5
- package/src/route-renderer/orchestration/foreign-subtree-execution.service.js +1 -3
- package/src/route-renderer/orchestration/integration-renderer.d.ts +10 -2
- package/src/route-renderer/orchestration/integration-renderer.js +32 -12
- 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-render-orchestrator.d.ts +2 -2
- package/src/route-renderer/orchestration/route-render-orchestrator.js +17 -16
- package/src/router/client/navigation-coordinator.js +10 -0
- 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/node-module-script.processor.js +17 -3
- package/src/services/assets/browser-bundle.service.d.ts +1 -0
- package/src/services/assets/browser-bundle.service.js +9 -3
- 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 +29 -0
- package/src/services/module-loading/README.md +49 -0
- package/src/services/module-loading/app-server-module-transpiler.service.js +4 -17
- package/src/services/module-loading/page-module-import.service.d.ts +4 -1
- package/src/services/module-loading/page-module-import.service.js +52 -29
- 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 +203 -0
- package/src/services/module-loading/route-module-build-manifest.d.ts +61 -0
- package/src/services/module-loading/route-module-build-manifest.js +124 -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 +78 -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 -8
- package/src/static-site-generator/static-site-generator.js +176 -62
- package/src/types/internal-types.d.ts +8 -0
- 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 +8 -0
- package/src/watchers/project-watcher.js +32 -12
|
@@ -8,7 +8,17 @@ import {
|
|
|
8
8
|
toBuildLogs,
|
|
9
9
|
transpileProfileToOptions
|
|
10
10
|
} from "./rolldown-adapter-helpers.js";
|
|
11
|
+
import { recordRolldownBuildInvocation } from "./rolldown-build-invocation-metrics.js";
|
|
11
12
|
const moduleRequire = createRequire(import.meta.url);
|
|
13
|
+
function normalizeEntrypointList(entrypoints) {
|
|
14
|
+
if (Array.isArray(entrypoints)) {
|
|
15
|
+
return entrypoints.map((entrypoint) => path.resolve(entrypoint)).sort();
|
|
16
|
+
}
|
|
17
|
+
if (entrypoints && typeof entrypoints === "object") {
|
|
18
|
+
return Object.values(entrypoints).map((entrypoint) => path.resolve(entrypoint)).sort();
|
|
19
|
+
}
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
12
22
|
class RolldownDevBuildAdapter {
|
|
13
23
|
/**
|
|
14
24
|
* `'rolldown-dev'` (not `'rolldown'`) so {@link getBuildAdapterOwnership}
|
|
@@ -22,12 +32,22 @@ class RolldownDevBuildAdapter {
|
|
|
22
32
|
appRootRequireCache = /* @__PURE__ */ new Map();
|
|
23
33
|
/**
|
|
24
34
|
* Stable key over the inputs that affect the engine configuration.
|
|
25
|
-
*
|
|
26
|
-
*
|
|
35
|
+
* Output paths and entrypoints must participate — HMR registers many
|
|
36
|
+
* distinct script entrypoints with literal naming under the same outdir.
|
|
27
37
|
*/
|
|
28
|
-
getCacheKey(
|
|
29
|
-
const pluginNames = plugins.map((
|
|
30
|
-
|
|
38
|
+
getCacheKey(options, contextRoot) {
|
|
39
|
+
const pluginNames = (options.plugins ?? []).map((plugin) => plugin.name).sort().join(":");
|
|
40
|
+
const outdir = path.resolve(options.outdir ?? "dist/assets");
|
|
41
|
+
const entrypoints = normalizeEntrypointList(options.entrypoints).join("|");
|
|
42
|
+
return [
|
|
43
|
+
contextRoot,
|
|
44
|
+
pluginNames,
|
|
45
|
+
options.target ?? "default",
|
|
46
|
+
options.format ?? "esm",
|
|
47
|
+
outdir,
|
|
48
|
+
options.naming ?? "[name]",
|
|
49
|
+
entrypoints
|
|
50
|
+
].join("::");
|
|
31
51
|
}
|
|
32
52
|
/**
|
|
33
53
|
* Returns the cached engine, creating a new one when the cache
|
|
@@ -36,15 +56,9 @@ class RolldownDevBuildAdapter {
|
|
|
36
56
|
*/
|
|
37
57
|
async getOrCreateEngine(options, contextRoot) {
|
|
38
58
|
const bundlePlugins = options.plugins ?? [];
|
|
39
|
-
const cacheKey = this.getCacheKey(
|
|
59
|
+
const cacheKey = this.getCacheKey(options, contextRoot);
|
|
40
60
|
if (this.cachedEngine) {
|
|
41
|
-
|
|
42
|
-
this.cachedEngine.bundlePlugins,
|
|
43
|
-
this.cachedEngine.contextRoot,
|
|
44
|
-
options.target,
|
|
45
|
-
options.format
|
|
46
|
-
);
|
|
47
|
-
if (existingKey === cacheKey) {
|
|
61
|
+
if (this.cachedEngine.cacheKey === cacheKey) {
|
|
48
62
|
return this.cachedEngine;
|
|
49
63
|
}
|
|
50
64
|
await this.cachedEngine.engine.close();
|
|
@@ -73,7 +87,8 @@ class RolldownDevBuildAdapter {
|
|
|
73
87
|
engine,
|
|
74
88
|
engineStarted: false,
|
|
75
89
|
contextRoot,
|
|
76
|
-
bundlePlugins
|
|
90
|
+
bundlePlugins,
|
|
91
|
+
cacheKey
|
|
77
92
|
};
|
|
78
93
|
this.engineInstanceCount += 1;
|
|
79
94
|
return this.cachedEngine;
|
|
@@ -108,6 +123,7 @@ class RolldownDevBuildAdapter {
|
|
|
108
123
|
}
|
|
109
124
|
/** Throws on error; see {@link build} for the no-throw variant. */
|
|
110
125
|
async buildOrThrow(options) {
|
|
126
|
+
recordRolldownBuildInvocation("rolldown-dev");
|
|
111
127
|
const contextRoot = options.root ? path.resolve(options.root) : process.cwd();
|
|
112
128
|
const outdir = path.resolve(options.outdir ?? "dist/assets");
|
|
113
129
|
const plugins = options.plugins ?? [];
|
|
@@ -1,21 +1,15 @@
|
|
|
1
1
|
import type { EcoPagesAppConfig } from '../types/internal-types.js';
|
|
2
2
|
import { type BuildExecutor } from './build-adapter.js';
|
|
3
3
|
/**
|
|
4
|
-
* Installs the app-owned runtime build
|
|
4
|
+
* Installs the app-owned runtime build executors for one app instance.
|
|
5
5
|
*
|
|
6
6
|
* @remarks
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* so app-owned plugins are merged into every rebuild without callers
|
|
11
|
-
* having to know about the manifest.
|
|
7
|
+
* Route-module and HMR browser builds run through a {@link ParallelBuildExecutor}
|
|
8
|
+
* so independent compiles can overlap. Server-entry bundling continues to call
|
|
9
|
+
* the raw adapter directly and stays single-flight by design.
|
|
12
10
|
*
|
|
13
|
-
* Idempotent across calls: re-invoking replaces the existing
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* @param appConfig - The app config whose runtime state is updated.
|
|
17
|
-
* The function reads the existing executor (falling back to the
|
|
18
|
-
* app-owned adapter) and writes the wrapped executor back.
|
|
19
|
-
* @returns The installed {@link BuildExecutor}.
|
|
11
|
+
* Idempotent across calls: re-invoking replaces the existing executors on
|
|
12
|
+
* `appConfig.runtime` with fresh wrappers.
|
|
20
13
|
*/
|
|
21
14
|
export declare function installAppRuntimeBuildExecutor(appConfig: EcoPagesAppConfig): BuildExecutor;
|
|
15
|
+
export declare function getInstalledServerEntryBuildExecutor(appConfig: EcoPagesAppConfig): BuildExecutor;
|
|
@@ -1,19 +1,43 @@
|
|
|
1
|
+
import { availableParallelism } from "node:os";
|
|
1
2
|
import {
|
|
2
3
|
getAppBuildAdapter,
|
|
3
|
-
getAppBuildExecutor,
|
|
4
4
|
getAppServerBuildPlugins,
|
|
5
5
|
setAppBuildExecutor,
|
|
6
|
+
setAppHmrBuildExecutor,
|
|
7
|
+
setAppRouteModuleBuildExecutor,
|
|
6
8
|
withBuildExecutorPlugins
|
|
7
9
|
} from "./build-adapter.js";
|
|
10
|
+
import { ParallelBuildExecutor } from "./parallel-build-executor.js";
|
|
8
11
|
import { SerializedBuildExecutor } from "./serialized-build-executor.js";
|
|
12
|
+
function createPluginWrappedExecutor(appConfig) {
|
|
13
|
+
return withBuildExecutorPlugins(getAppBuildAdapter(appConfig), () => getAppServerBuildPlugins(appConfig));
|
|
14
|
+
}
|
|
15
|
+
function resolveParallelismLimit() {
|
|
16
|
+
return Math.max(1, availableParallelism() - 1);
|
|
17
|
+
}
|
|
9
18
|
function installAppRuntimeBuildExecutor(appConfig) {
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
);
|
|
14
|
-
|
|
15
|
-
|
|
19
|
+
const pluginWrappedExecutor = createPluginWrappedExecutor(appConfig);
|
|
20
|
+
const parallelismLimit = resolveParallelismLimit();
|
|
21
|
+
const routeModuleBuildExecutor = new ParallelBuildExecutor(pluginWrappedExecutor, parallelismLimit);
|
|
22
|
+
const hmrBuildExecutor = new ParallelBuildExecutor(pluginWrappedExecutor, Math.min(3, parallelismLimit));
|
|
23
|
+
setAppRouteModuleBuildExecutor(appConfig, routeModuleBuildExecutor);
|
|
24
|
+
setAppHmrBuildExecutor(appConfig, hmrBuildExecutor);
|
|
25
|
+
setAppBuildExecutor(appConfig, routeModuleBuildExecutor);
|
|
26
|
+
return routeModuleBuildExecutor;
|
|
27
|
+
}
|
|
28
|
+
function getInstalledServerEntryBuildExecutor(appConfig) {
|
|
29
|
+
const existing = appConfig.runtime?.serverEntryBuildExecutor;
|
|
30
|
+
if (existing) {
|
|
31
|
+
return existing;
|
|
32
|
+
}
|
|
33
|
+
const serverEntryBuildExecutor = new SerializedBuildExecutor(createPluginWrappedExecutor(appConfig));
|
|
34
|
+
appConfig.runtime = {
|
|
35
|
+
...appConfig.runtime ?? {},
|
|
36
|
+
serverEntryBuildExecutor
|
|
37
|
+
};
|
|
38
|
+
return serverEntryBuildExecutor;
|
|
16
39
|
}
|
|
17
40
|
export {
|
|
41
|
+
getInstalledServerEntryBuildExecutor,
|
|
18
42
|
installAppRuntimeBuildExecutor
|
|
19
43
|
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { BuildResult } from './build-adapter.js';
|
|
2
|
+
import type { EcoPagesAppConfig } from '../types/internal-types.js';
|
|
3
|
+
/** @deprecated Use {@link ROUTE_MODULE_BUILD_CACHE_FILENAME}; both caches share the same manifest filename. */
|
|
4
|
+
export declare const SERVER_ENTRY_BUILD_CACHE_FILENAME = ".build-cache.json";
|
|
5
|
+
export declare const SERVER_BUNDLE_MANIFEST_FILENAME = "manifest.json";
|
|
6
|
+
export interface ServerBundleDeployManifest {
|
|
7
|
+
serverEntry: string;
|
|
8
|
+
distDir: string;
|
|
9
|
+
builtAt: number;
|
|
10
|
+
}
|
|
11
|
+
export interface ServerEntryBuildCacheManifest {
|
|
12
|
+
invalidationVersion: string;
|
|
13
|
+
entryPath: string;
|
|
14
|
+
entryHash: string;
|
|
15
|
+
buildInputsFingerprint: string;
|
|
16
|
+
buildKey: string;
|
|
17
|
+
outputPaths: string[];
|
|
18
|
+
dependencyHashes: Record<string, string>;
|
|
19
|
+
builtAt: number;
|
|
20
|
+
}
|
|
21
|
+
export interface ServerEntryBuildCacheLookup {
|
|
22
|
+
manifest: ServerEntryBuildCacheManifest;
|
|
23
|
+
outputPaths: string[];
|
|
24
|
+
}
|
|
25
|
+
export declare function getServerBundleOutputPaths(appConfig: EcoPagesAppConfig): {
|
|
26
|
+
distDir: string;
|
|
27
|
+
serverOutdir: string;
|
|
28
|
+
serverEntryPath: string;
|
|
29
|
+
manifestPath: string;
|
|
30
|
+
};
|
|
31
|
+
export declare function readServerEntryBuildCacheManifest(appConfig: EcoPagesAppConfig): ServerEntryBuildCacheManifest | undefined;
|
|
32
|
+
export declare function writeServerBundleDeployManifest(appConfig: EcoPagesAppConfig, serverEntryPath: string): void;
|
|
33
|
+
export declare function lookupServerEntryBuildCache(options: {
|
|
34
|
+
appConfig: EcoPagesAppConfig;
|
|
35
|
+
entryPath: string;
|
|
36
|
+
force?: boolean;
|
|
37
|
+
}): ServerEntryBuildCacheLookup | undefined;
|
|
38
|
+
export declare function recordServerEntryBuildCache(options: {
|
|
39
|
+
appConfig: EcoPagesAppConfig;
|
|
40
|
+
entryPath: string;
|
|
41
|
+
buildResult: BuildResult;
|
|
42
|
+
outputPaths: string[];
|
|
43
|
+
}): void;
|
|
44
|
+
export declare function resolveProductionServerEntry(cwd?: string): string | undefined;
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { fileSystem } from "@ecopages/file-system";
|
|
3
|
+
import { getAppServerBuildPlugins } from "./build-adapter.js";
|
|
4
|
+
import { createBuildInputsFingerprint } from "./build-input-fingerprint.js";
|
|
5
|
+
import { getCorePackageVersion } from "../services/module-loading/route-module-build-manifest.js";
|
|
6
|
+
import {
|
|
7
|
+
RouteModuleDependencyHasher,
|
|
8
|
+
createRouteModuleDependencyHashes
|
|
9
|
+
} from "../services/module-loading/route-module-dependency-hasher.js";
|
|
10
|
+
import { resolveInternalExecutionDir } from "../utils/resolve-work-dir.js";
|
|
11
|
+
import { SERVER_BUNDLE_DIR, SERVER_BUNDLE_FILENAME } from "../utils/resolve-entry-file.js";
|
|
12
|
+
import { ROUTE_MODULE_BUILD_CACHE_FILENAME } from "../services/module-loading/route-module-build-manifest.js";
|
|
13
|
+
const SERVER_ENTRY_BUILD_CACHE_FILENAME = ROUTE_MODULE_BUILD_CACHE_FILENAME;
|
|
14
|
+
const SERVER_BUNDLE_MANIFEST_FILENAME = "manifest.json";
|
|
15
|
+
function getServerEntryCacheDir(appConfig) {
|
|
16
|
+
return path.join(resolveInternalExecutionDir(appConfig), ".server-entry");
|
|
17
|
+
}
|
|
18
|
+
function getServerEntryCacheManifestPath(appConfig) {
|
|
19
|
+
return path.join(getServerEntryCacheDir(appConfig), SERVER_ENTRY_BUILD_CACHE_FILENAME);
|
|
20
|
+
}
|
|
21
|
+
function hashDependencyGraph(entryPath, dependencyGraph, hasher, rootDir) {
|
|
22
|
+
if (!dependencyGraph) {
|
|
23
|
+
return { [path.resolve(entryPath)]: fileSystem.hash(entryPath) };
|
|
24
|
+
}
|
|
25
|
+
return createRouteModuleDependencyHashes(hasher, { dependencyGraph }, entryPath, rootDir);
|
|
26
|
+
}
|
|
27
|
+
function createServerEntryBuildKey(appConfig) {
|
|
28
|
+
try {
|
|
29
|
+
const plugins = getAppServerBuildPlugins(appConfig);
|
|
30
|
+
const pluginNames = plugins.map((plugin) => plugin.name).sort().join("|");
|
|
31
|
+
return ["node", "esm", "external-packages", pluginNames].join("::");
|
|
32
|
+
} catch {
|
|
33
|
+
return "node::esm::external-packages";
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function getServerBundleOutputPaths(appConfig) {
|
|
37
|
+
const distDir = appConfig.absolutePaths?.distDir ?? path.join(appConfig.rootDir, appConfig.distDir);
|
|
38
|
+
const serverOutdir = path.join(distDir, SERVER_BUNDLE_DIR);
|
|
39
|
+
const serverEntryPath = path.join(serverOutdir, SERVER_BUNDLE_FILENAME);
|
|
40
|
+
const manifestPath = path.join(serverOutdir, SERVER_BUNDLE_MANIFEST_FILENAME);
|
|
41
|
+
return { distDir, serverOutdir, serverEntryPath, manifestPath };
|
|
42
|
+
}
|
|
43
|
+
function readServerEntryBuildCacheManifest(appConfig) {
|
|
44
|
+
const manifestPath = getServerEntryCacheManifestPath(appConfig);
|
|
45
|
+
if (!fileSystem.exists(manifestPath)) {
|
|
46
|
+
return void 0;
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
const parsed = JSON.parse(fileSystem.readFileSync(manifestPath));
|
|
50
|
+
if (!parsed || typeof parsed !== "object") {
|
|
51
|
+
return void 0;
|
|
52
|
+
}
|
|
53
|
+
return parsed;
|
|
54
|
+
} catch {
|
|
55
|
+
return void 0;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function writeServerEntryBuildCacheManifest(appConfig, manifest) {
|
|
59
|
+
const cacheDir = getServerEntryCacheDir(appConfig);
|
|
60
|
+
fileSystem.ensureDir(cacheDir);
|
|
61
|
+
fileSystem.write(
|
|
62
|
+
path.join(cacheDir, SERVER_ENTRY_BUILD_CACHE_FILENAME),
|
|
63
|
+
`${JSON.stringify(manifest, null, " ")}
|
|
64
|
+
`
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
function writeServerBundleDeployManifest(appConfig, serverEntryPath) {
|
|
68
|
+
const { distDir, manifestPath } = getServerBundleOutputPaths(appConfig);
|
|
69
|
+
fileSystem.ensureDir(path.dirname(manifestPath));
|
|
70
|
+
const payload = {
|
|
71
|
+
serverEntry: path.relative(path.dirname(manifestPath), serverEntryPath) || SERVER_BUNDLE_FILENAME,
|
|
72
|
+
distDir,
|
|
73
|
+
builtAt: Date.now()
|
|
74
|
+
};
|
|
75
|
+
fileSystem.write(manifestPath, `${JSON.stringify(payload, null, " ")}
|
|
76
|
+
`);
|
|
77
|
+
}
|
|
78
|
+
function lookupServerEntryBuildCache(options) {
|
|
79
|
+
if (options.force) {
|
|
80
|
+
return void 0;
|
|
81
|
+
}
|
|
82
|
+
if (process.env.NODE_ENV !== "production") {
|
|
83
|
+
return void 0;
|
|
84
|
+
}
|
|
85
|
+
const entryPath = path.resolve(options.entryPath);
|
|
86
|
+
const entryHash = fileSystem.hash(entryPath);
|
|
87
|
+
const buildInputsFingerprint = createBuildInputsFingerprint(options.appConfig);
|
|
88
|
+
const buildKey = createServerEntryBuildKey(options.appConfig);
|
|
89
|
+
const manifest = readServerEntryBuildCacheManifest(options.appConfig);
|
|
90
|
+
if (!manifest) {
|
|
91
|
+
return void 0;
|
|
92
|
+
}
|
|
93
|
+
if (manifest.invalidationVersion !== getCorePackageVersion()) {
|
|
94
|
+
return void 0;
|
|
95
|
+
}
|
|
96
|
+
if (manifest.entryPath !== entryPath || manifest.entryHash !== entryHash || manifest.buildInputsFingerprint !== buildInputsFingerprint || manifest.buildKey !== buildKey) {
|
|
97
|
+
return void 0;
|
|
98
|
+
}
|
|
99
|
+
const hasher = new RouteModuleDependencyHasher();
|
|
100
|
+
if (!hasher.matchesStoredHashes(manifest.dependencyHashes, entryPath, entryHash)) {
|
|
101
|
+
return void 0;
|
|
102
|
+
}
|
|
103
|
+
const existingOutputs = manifest.outputPaths.filter((outputPath) => fileSystem.exists(outputPath));
|
|
104
|
+
if (existingOutputs.length === 0) {
|
|
105
|
+
return void 0;
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
manifest,
|
|
109
|
+
outputPaths: existingOutputs
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
function recordServerEntryBuildCache(options) {
|
|
113
|
+
if (process.env.NODE_ENV !== "production") {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
const entryPath = path.resolve(options.entryPath);
|
|
117
|
+
const entryHash = fileSystem.hash(entryPath);
|
|
118
|
+
const hasher = new RouteModuleDependencyHasher();
|
|
119
|
+
const dependencyHashes = hashDependencyGraph(
|
|
120
|
+
entryPath,
|
|
121
|
+
options.buildResult.dependencyGraph,
|
|
122
|
+
hasher,
|
|
123
|
+
options.appConfig.rootDir
|
|
124
|
+
);
|
|
125
|
+
const manifest = {
|
|
126
|
+
invalidationVersion: getCorePackageVersion(),
|
|
127
|
+
entryPath,
|
|
128
|
+
entryHash,
|
|
129
|
+
buildInputsFingerprint: createBuildInputsFingerprint(options.appConfig),
|
|
130
|
+
buildKey: createServerEntryBuildKey(options.appConfig),
|
|
131
|
+
outputPaths: options.outputPaths,
|
|
132
|
+
dependencyHashes,
|
|
133
|
+
builtAt: Date.now()
|
|
134
|
+
};
|
|
135
|
+
writeServerEntryBuildCacheManifest(options.appConfig, manifest);
|
|
136
|
+
}
|
|
137
|
+
function resolveProductionServerEntry(cwd = process.cwd()) {
|
|
138
|
+
const manifestPath = path.join(cwd, "dist", SERVER_BUNDLE_DIR, SERVER_BUNDLE_MANIFEST_FILENAME);
|
|
139
|
+
if (fileSystem.exists(manifestPath)) {
|
|
140
|
+
try {
|
|
141
|
+
const parsed = JSON.parse(fileSystem.readFileSync(manifestPath));
|
|
142
|
+
if (parsed?.serverEntry) {
|
|
143
|
+
const fromManifest = path.isAbsolute(parsed.serverEntry) ? parsed.serverEntry : path.join(path.dirname(manifestPath), parsed.serverEntry);
|
|
144
|
+
if (fileSystem.exists(fromManifest)) {
|
|
145
|
+
return fromManifest;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
if (parsed?.distDir) {
|
|
149
|
+
const fromDistDir = path.join(parsed.distDir, SERVER_BUNDLE_DIR, SERVER_BUNDLE_FILENAME);
|
|
150
|
+
if (fileSystem.exists(fromDistDir)) {
|
|
151
|
+
return fromDistDir;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
} catch {
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
const legacyPath = path.join(cwd, "dist", SERVER_BUNDLE_DIR, SERVER_BUNDLE_FILENAME);
|
|
158
|
+
return fileSystem.exists(legacyPath) ? legacyPath : void 0;
|
|
159
|
+
}
|
|
160
|
+
export {
|
|
161
|
+
SERVER_BUNDLE_MANIFEST_FILENAME,
|
|
162
|
+
SERVER_ENTRY_BUILD_CACHE_FILENAME,
|
|
163
|
+
getServerBundleOutputPaths,
|
|
164
|
+
lookupServerEntryBuildCache,
|
|
165
|
+
readServerEntryBuildCacheManifest,
|
|
166
|
+
recordServerEntryBuildCache,
|
|
167
|
+
resolveProductionServerEntry,
|
|
168
|
+
writeServerBundleDeployManifest
|
|
169
|
+
};
|
package/src/hmr/hmr.test.e2e.js
CHANGED
|
@@ -4,6 +4,15 @@ import { writeFile } from "node:fs/promises";
|
|
|
4
4
|
import { resolve } from "node:path";
|
|
5
5
|
const FIXTURE_DIR = resolve(process.cwd(), "packages/core/__fixtures__/app");
|
|
6
6
|
const TEST_CSS_FILE = resolve(FIXTURE_DIR, "src/pages/index.css");
|
|
7
|
+
async function readMainTitleColor(page) {
|
|
8
|
+
return page.evaluate(() => {
|
|
9
|
+
const element = document.querySelector(".main-title");
|
|
10
|
+
if (!(element instanceof HTMLElement)) {
|
|
11
|
+
return "";
|
|
12
|
+
}
|
|
13
|
+
return getComputedStyle(element).color;
|
|
14
|
+
});
|
|
15
|
+
}
|
|
7
16
|
test.describe("HMR E2E", () => {
|
|
8
17
|
test("should load page with .main-title element", async ({ page }) => {
|
|
9
18
|
await page.goto("/", { waitUntil: "networkidle" });
|
|
@@ -23,9 +32,10 @@ test.describe("HMR E2E", () => {
|
|
|
23
32
|
const originalCss = readFileSync(TEST_CSS_FILE, "utf-8");
|
|
24
33
|
const title = page.locator(".main-title").first();
|
|
25
34
|
try {
|
|
26
|
-
await page.goto("/", { waitUntil: "
|
|
35
|
+
await page.goto("/", { waitUntil: "domcontentloaded" });
|
|
27
36
|
await expect(title).toBeVisible();
|
|
28
|
-
|
|
37
|
+
await expect.poll(async () => readMainTitleColor(page), { timeout: 1e4 }).not.toBe("");
|
|
38
|
+
const initialColor = await readMainTitleColor(page);
|
|
29
39
|
expect(initialColor).toBeTruthy();
|
|
30
40
|
const modifiedCss = originalCss.replace(".main-title {", ".main-title {\n color: rgb(255, 0, 0);");
|
|
31
41
|
const reloadPromise = page.waitForEvent("framenavigated", {
|
|
@@ -34,8 +44,9 @@ test.describe("HMR E2E", () => {
|
|
|
34
44
|
});
|
|
35
45
|
await writeFile(TEST_CSS_FILE, modifiedCss, { flush: true });
|
|
36
46
|
await reloadPromise;
|
|
37
|
-
await page.waitForLoadState("
|
|
38
|
-
await expect
|
|
47
|
+
await page.waitForLoadState("domcontentloaded");
|
|
48
|
+
await expect(title).toBeVisible();
|
|
49
|
+
await expect.poll(async () => readMainTitleColor(page), { timeout: 1e4 }).toBe("rgb(255, 0, 0)");
|
|
39
50
|
} finally {
|
|
40
51
|
await writeFile(TEST_CSS_FILE, originalCss, { flush: true });
|
|
41
52
|
}
|
|
@@ -6,10 +6,12 @@ import type { EcoPagesElement } from '../types/public-types.js';
|
|
|
6
6
|
import type { IntegrationRenderer } from '../route-renderer/orchestration/integration-renderer.js';
|
|
7
7
|
import { AssetProcessingService } from '../services/assets/asset-processing-service/asset-processing.service.js';
|
|
8
8
|
import type { AssetDefinition, ProcessedAsset } from '../services/assets/asset-processing-service/assets.types.js';
|
|
9
|
+
import type { StaticExportContext } from '../static-site-generator/static-export-context.js';
|
|
9
10
|
import type { RuntimeCapabilityDeclaration } from './runtime-capability.js';
|
|
10
11
|
export type { RuntimeCapabilityDeclaration, RuntimeCapabilityTag } from './runtime-capability.js';
|
|
11
12
|
export type { EcoBuildLoader, EcoBuildOnLoadArgs, EcoBuildOnLoadResult, EcoBuildOnResolveArgs, EcoBuildOnResolveResult, EcoBuildPlugin, EcoBuildPluginBuilder, } from '../build/build-types.js';
|
|
12
13
|
export type { PageBrowserGraphContribution, PageBrowserGraphContributionContext } from '../types/public-types.js';
|
|
14
|
+
export type { StaticExportContext } from '../static-site-generator/static-export-context.js';
|
|
13
15
|
export type { HtmlDocumentContribution, HtmlDocumentContributionContext, } from '../route-renderer/orchestration/integration-renderer.js';
|
|
14
16
|
/**
|
|
15
17
|
* Type-erased integration plugin stored in app-level registries.
|
|
@@ -47,13 +49,6 @@ export interface IntegrationPluginConfig {
|
|
|
47
49
|
* They are not specific to any particular page or component.
|
|
48
50
|
*/
|
|
49
51
|
integrationDependencies?: AssetDefinition[];
|
|
50
|
-
/**
|
|
51
|
-
* The strategy to use for static building.
|
|
52
|
-
* - 'render': Execute component function directly (faster, efficient).
|
|
53
|
-
* - 'fetch': Start server and fetch URL (slower, needed for some SSR like Lit).
|
|
54
|
-
* @default 'render'
|
|
55
|
-
*/
|
|
56
|
-
staticBuildStep?: 'render' | 'fetch';
|
|
57
52
|
/**
|
|
58
53
|
* Declares runtime-specific requirements that must be satisfied before the
|
|
59
54
|
* app can start with this integration enabled.
|
|
@@ -96,7 +91,6 @@ export declare abstract class IntegrationPlugin<C = EcoPagesElement> {
|
|
|
96
91
|
readonly name: string;
|
|
97
92
|
readonly extensions: string[];
|
|
98
93
|
abstract renderer: RendererClass<C>;
|
|
99
|
-
readonly staticBuildStep: 'render' | 'fetch';
|
|
100
94
|
readonly runtimeCapability?: RuntimeCapabilityDeclaration;
|
|
101
95
|
readonly jsxImportSource?: string;
|
|
102
96
|
protected integrationDependencies: AssetDefinition[];
|
|
@@ -213,6 +207,23 @@ export declare abstract class IntegrationPlugin<C = EcoPagesElement> {
|
|
|
213
207
|
* `setup()`.
|
|
214
208
|
*/
|
|
215
209
|
prepareBuildContributions(): Promise<void>;
|
|
210
|
+
/**
|
|
211
|
+
* Reports whether this integration's build inputs changed since the last
|
|
212
|
+
* incremental static build.
|
|
213
|
+
*/
|
|
214
|
+
didChange(): boolean;
|
|
215
|
+
/**
|
|
216
|
+
* Runs integration-specific setup before static page generation begins.
|
|
217
|
+
*
|
|
218
|
+
* @remarks
|
|
219
|
+
* Integrations that need build-scoped SSR preload or worker sessions should
|
|
220
|
+
* start them here rather than per-page inside the renderer.
|
|
221
|
+
*/
|
|
222
|
+
beforeStaticExport?(_context: StaticExportContext): Promise<void>;
|
|
223
|
+
/**
|
|
224
|
+
* Releases resources started in {@link beforeStaticExport}.
|
|
225
|
+
*/
|
|
226
|
+
afterStaticExport?(_context: StaticExportContext): Promise<void>;
|
|
216
227
|
/**
|
|
217
228
|
* Performs runtime-only integration setup after config build has already
|
|
218
229
|
* sealed manifest contributions.
|
|
@@ -15,7 +15,6 @@ function assertIntegrationInvariant(condition, message) {
|
|
|
15
15
|
class IntegrationPlugin {
|
|
16
16
|
name;
|
|
17
17
|
extensions;
|
|
18
|
-
staticBuildStep;
|
|
19
18
|
runtimeCapability;
|
|
20
19
|
jsxImportSource;
|
|
21
20
|
integrationDependencies;
|
|
@@ -60,7 +59,6 @@ class IntegrationPlugin {
|
|
|
60
59
|
this.name = config.name;
|
|
61
60
|
this.extensions = config.extensions;
|
|
62
61
|
this.integrationDependencies = config.integrationDependencies || [];
|
|
63
|
-
this.staticBuildStep = config.staticBuildStep || "render";
|
|
64
62
|
this.runtimeCapability = config.runtimeCapability;
|
|
65
63
|
this.jsxImportSource = config.jsxImportSource;
|
|
66
64
|
}
|
|
@@ -169,6 +167,13 @@ class IntegrationPlugin {
|
|
|
169
167
|
*/
|
|
170
168
|
async prepareBuildContributions() {
|
|
171
169
|
}
|
|
170
|
+
/**
|
|
171
|
+
* Reports whether this integration's build inputs changed since the last
|
|
172
|
+
* incremental static build.
|
|
173
|
+
*/
|
|
174
|
+
didChange() {
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
172
177
|
/**
|
|
173
178
|
* Performs runtime-only integration setup after config build has already
|
|
174
179
|
* sealed manifest contributions.
|
|
@@ -80,6 +80,11 @@ export declare abstract class Processor<TOptions = Record<string, unknown>> {
|
|
|
80
80
|
* warming or watcher registration should stay in `setup()`.
|
|
81
81
|
*/
|
|
82
82
|
prepareBuildContributions(): Promise<void>;
|
|
83
|
+
/**
|
|
84
|
+
* Reports whether this processor's build inputs changed since the last
|
|
85
|
+
* incremental static build.
|
|
86
|
+
*/
|
|
87
|
+
didChange(): boolean;
|
|
83
88
|
abstract setup(): Promise<void>;
|
|
84
89
|
abstract teardown(): Promise<void>;
|
|
85
90
|
abstract process(input: unknown, filePath?: string): Promise<unknown>;
|
package/src/plugins/processor.js
CHANGED
|
@@ -54,6 +54,13 @@ class Processor {
|
|
|
54
54
|
*/
|
|
55
55
|
async prepareBuildContributions() {
|
|
56
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Reports whether this processor's build inputs changed since the last
|
|
59
|
+
* incremental static build.
|
|
60
|
+
*/
|
|
61
|
+
didChange() {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
57
64
|
getCachePath(key) {
|
|
58
65
|
return `${this.context?.cache}/${key}`;
|
|
59
66
|
}
|
|
@@ -33,11 +33,11 @@ flowchart TD
|
|
|
33
33
|
|
|
34
34
|
## 2) Route Render Flow
|
|
35
35
|
|
|
36
|
-
`IntegrationRenderer.execute()` delegates shared route orchestration to `
|
|
36
|
+
`IntegrationRenderer.execute()` delegates shared route orchestration to `RouteRenderOrchestrator`.
|
|
37
37
|
|
|
38
38
|
```mermaid
|
|
39
39
|
flowchart TD
|
|
40
|
-
A[IntegrationRenderer.execute] --> B[
|
|
40
|
+
A[IntegrationRenderer.execute] --> B[RouteRenderOrchestrator.prepareRenderOptions]
|
|
41
41
|
B --> C[resolvePageModule]
|
|
42
42
|
C --> D[ownershipValidationService.validate]
|
|
43
43
|
D --> E[resolvePageData]
|
|
@@ -121,7 +121,7 @@ flowchart TD
|
|
|
121
121
|
The most useful reading order is:
|
|
122
122
|
|
|
123
123
|
1. `route-renderer.ts`
|
|
124
|
-
2. `orchestration/route-render-
|
|
124
|
+
2. `orchestration/route-render-orchestrator.ts`
|
|
125
125
|
3. `orchestration/integration-renderer.ts`
|
|
126
126
|
4. `orchestration/ownership-validation.service.ts`
|
|
127
127
|
5. `orchestration/ownership-planning.service.ts`
|
|
@@ -134,7 +134,7 @@ The most useful reading order is:
|
|
|
134
134
|
## 7) Key Files
|
|
135
135
|
|
|
136
136
|
- `packages/core/src/route-renderer/route-renderer.ts`
|
|
137
|
-
- `packages/core/src/route-renderer/orchestration/route-render-
|
|
137
|
+
- `packages/core/src/route-renderer/orchestration/route-render-orchestrator.ts`
|
|
138
138
|
- `packages/core/src/route-renderer/orchestration/integration-renderer.ts`
|
|
139
139
|
- `packages/core/src/route-renderer/orchestration/ownership-validation.service.ts`
|
|
140
140
|
- `packages/core/src/route-renderer/orchestration/ownership-planning.service.ts`
|
|
@@ -27,7 +27,7 @@ These concepts intentionally live in different places:
|
|
|
27
27
|
- `component-render-context.ts` intercepts foreign children during active component render
|
|
28
28
|
- `queued-foreign-subtree-resolution.service.ts` resolves queued foreign subtrees for renderers that cannot hand them off inline
|
|
29
29
|
- `integration-renderer.ts` owns renderer-to-renderer delegation and shared shell composition
|
|
30
|
-
- `route-render-
|
|
30
|
+
- `route-render-orchestrator.ts` owns route preparation, final response capture, and unresolved artifact enforcement
|
|
31
31
|
|
|
32
32
|
## Main Files
|
|
33
33
|
|
|
@@ -38,7 +38,7 @@ These concepts intentionally live in different places:
|
|
|
38
38
|
|
|
39
39
|
### `orchestration/`
|
|
40
40
|
|
|
41
|
-
- `route-render-
|
|
41
|
+
- `route-render-orchestrator.ts`: one route render from page-module loading through final HTML output
|
|
42
42
|
- `integration-renderer.ts`: abstract base class for route rendering, explicit view rendering, and foreign-child delegation
|
|
43
43
|
- `ownership-planning.service.ts`: declared ownership graph construction
|
|
44
44
|
- `ownership-validation.service.ts`: up-front ownership validation for route roots and declared descendants
|
|
@@ -56,11 +56,11 @@ These concepts intentionally live in different places:
|
|
|
56
56
|
The route-render contract is:
|
|
57
57
|
|
|
58
58
|
1. `RouteRendererFactory` selects the owning integration renderer.
|
|
59
|
-
2. `IntegrationRenderer.execute()` delegates preparation and finalization to `
|
|
60
|
-
3. `
|
|
59
|
+
2. `IntegrationRenderer.execute()` delegates preparation and finalization to `RouteRenderOrchestrator`.
|
|
60
|
+
3. `RouteRenderOrchestrator.prepareRenderOptions()` loads the page module, validates ownership, builds `ownershipPlan`, resolves page data, resolves dependencies, and builds the page browser graph.
|
|
61
61
|
4. The integration renderer performs page, layout, and document-shell rendering. When it encounters a foreign child, it delegates that child back to the owning renderer.
|
|
62
62
|
5. If a renderer needs queued handoff, it emits internal foreign-subtree tokens and resolves them before returning final HTML.
|
|
63
|
-
6. `
|
|
63
|
+
6. `RouteRenderOrchestrator.executePrepared()` captures the final body, rejects unresolved `<eco-marker>` artifacts, stamps root or document attributes when needed, and runs the HTML transformer.
|
|
64
64
|
|
|
65
65
|
Important:
|
|
66
66
|
|
|
@@ -115,4 +115,5 @@ Not every integration needs queue-based handoff.
|
|
|
115
115
|
## Current Limits
|
|
116
116
|
|
|
117
117
|
- `ownershipPlan` is still diagnostic and preparatory metadata; it does not yet drive a full route-composer execution model.
|
|
118
|
+
- `integration-renderer.ts` remains large (~1,400 lines); document-shell helpers and foreign-subtree wiring are the likely future extraction targets.
|
|
118
119
|
- Different integrations still own different foreign-child runtime strategies, which is intentional where child transport or hydration behavior differs.
|
|
@@ -5,9 +5,7 @@ import {
|
|
|
5
5
|
import {
|
|
6
6
|
QueuedForeignSubtreeResolutionService
|
|
7
7
|
} from "./queued-foreign-subtree-resolution.service.js";
|
|
8
|
-
|
|
9
|
-
return typeof value === "object" && value !== null && "nodeType" in value && typeof value.nodeType === "number" && (!("outerHTML" in value) || typeof value.outerHTML === "string");
|
|
10
|
-
}
|
|
8
|
+
import { isMarkupNodeLike } from "./render-output.utils.js";
|
|
11
9
|
class ForeignSubtreeExecutionService {
|
|
12
10
|
queuedForeignSubtreeResolutionService;
|
|
13
11
|
constructor(queuedForeignSubtreeResolutionService = new QueuedForeignSubtreeResolutionService()) {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
6
|
import type { EcoPagesAppConfig, IHmrManager } from '../../types/internal-types.js';
|
|
7
|
-
import type { ComponentRenderInput, ComponentRenderResult, ForeignSubtreeRenderPayload, EcoComponent, EcoComponentDependencies, EcoPageFile, EcoPagesElement, BaseIntegrationContext, HtmlTemplateProps, IntegrationRendererRenderOptions, PageBrowserGraphContribution, PageBrowserGraphContributionContext, PageBrowserGraphResult, PageMetadataProps, RouteRendererBody, RouteRendererOptions, RouteRenderResult } from '../../types/public-types.js';
|
|
7
|
+
import type { ComponentRenderInput, ComponentRenderResult, ForeignSubtreeRenderPayload, EcoComponent, EcoComponentDependencies, EcoPageFile, EcoPagesElement, BaseIntegrationContext, HtmlTemplateProps, IntegrationRendererRenderOptions, PageBrowserGraphContribution, PageBrowserGraphContributionContext, PageBrowserGraphResult, PageMetadataProps, PagePackageResult, RouteRendererBody, RouteRendererOptions, RouteRenderResult } from '../../types/public-types.js';
|
|
8
8
|
import { type AssetProcessingService, type ProcessedAsset } from '../../services/assets/asset-processing-service/index.js';
|
|
9
9
|
import { HtmlTransformerService } from '../../services/html/html-transformer.service.js';
|
|
10
10
|
import type { HtmlDocumentContribution } from '../../services/html/html-transformer.service.js';
|
|
@@ -59,7 +59,15 @@ export declare abstract class IntegrationRenderer<C = EcoPagesElement> {
|
|
|
59
59
|
protected pageModuleLoaderService: PageModuleLoaderService;
|
|
60
60
|
protected routeRenderOrchestrator: RouteRenderOrchestrator;
|
|
61
61
|
protected readonly foreignSubtreeExecutionService: ForeignSubtreeExecutionService;
|
|
62
|
+
/**
|
|
63
|
+
* Serializes route and view renders that mutate `htmlTransformer` state.
|
|
64
|
+
*
|
|
65
|
+
* Integration renderers are cached per integration, so concurrent static builds
|
|
66
|
+
* and overlapping SSR requests must not share one transformer page package.
|
|
67
|
+
*/
|
|
68
|
+
private renderExclusiveChain;
|
|
62
69
|
protected DOC_TYPE: string;
|
|
70
|
+
private runRenderExclusive;
|
|
63
71
|
/**
|
|
64
72
|
* Loads one route module through the owning renderer's import path.
|
|
65
73
|
*
|
|
@@ -351,7 +359,7 @@ export declare abstract class IntegrationRenderer<C = EcoPagesElement> {
|
|
|
351
359
|
}): Promise<ComponentRenderResult | undefined>;
|
|
352
360
|
protected renderRouteBody(renderOptions: IntegrationRendererRenderOptions<C>): Promise<RouteRendererBody>;
|
|
353
361
|
protected getRouteHtmlFinalization(renderOptions: IntegrationRendererRenderOptions<C>): RouteHtmlFinalization;
|
|
354
|
-
protected transformRouteResponse(response: Response, htmlContributions?: HtmlDocumentContribution[]): Promise<RouteRendererBody>;
|
|
362
|
+
protected transformRouteResponse(response: Response, htmlContributions?: HtmlDocumentContribution[], pagePackage?: PagePackageResult): Promise<RouteRendererBody>;
|
|
355
363
|
/**
|
|
356
364
|
* Prepares the render options for the integration renderer.
|
|
357
365
|
* It imports the page file, collects dependencies, and prepares the render options.
|