@ecopages/core 0.2.0-beta.36 → 0.2.0-beta.38
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 +11 -3
- package/src/dev-toolbar/README.md +9 -9
- package/src/eco/eco.browser.js +9 -2
- package/src/eco/eco.js +8 -2
- package/src/eco/eco.types.d.ts +29 -2
- package/src/hmr/README.md +5 -5
- package/src/route-renderer/README.md +2 -1
- package/src/route-renderer/orchestration/integration-renderer.d.ts +19 -3
- package/src/route-renderer/orchestration/integration-renderer.js +89 -8
- package/src/route-renderer/orchestration/page-browser-graph/grouped-graph-build-plan.d.ts +15 -0
- package/src/route-renderer/orchestration/page-browser-graph/grouped-graph-build-plan.js +9 -0
- package/src/route-renderer/orchestration/page-browser-graph/page-browser-graph-contribution.merge.d.ts +5 -0
- package/src/route-renderer/orchestration/page-browser-graph/page-browser-graph-contribution.merge.js +30 -0
- package/src/route-renderer/orchestration/page-browser-graph/page-browser-graph-session.d.ts +22 -6
- package/src/route-renderer/orchestration/page-browser-graph/page-browser-graph-session.js +145 -68
- package/src/route-renderer/orchestration/page-browser-graph/page-browser-graph.service.d.ts +9 -2
- package/src/route-renderer/orchestration/page-browser-graph/page-browser-graph.service.js +56 -39
- package/src/route-renderer/orchestration/page-browser-graph/route-instance-key.d.ts +29 -0
- package/src/route-renderer/orchestration/page-browser-graph/route-instance-key.js +54 -0
- package/src/route-renderer/orchestration/route-pipeline/integration-route-render-adapter.d.ts +3 -0
- package/src/route-renderer/orchestration/route-pipeline/integration-route-render-adapter.js +3 -2
- package/src/route-renderer/orchestration/route-pipeline/route-prepared-options.builder.d.ts +1 -0
- package/src/route-renderer/orchestration/route-pipeline/route-prepared-options.builder.js +3 -5
- package/src/route-renderer/orchestration/route-pipeline/route-render-orchestrator.d.ts +14 -4
- package/src/route-renderer/orchestration/route-pipeline/route-render-orchestrator.js +31 -4
- package/src/route-renderer/page-loading/file-scoped-dependency-components.d.ts +42 -0
- package/src/route-renderer/page-loading/file-scoped-dependency-components.js +93 -0
- package/src/route-renderer/page-loading/page-module-loader.d.ts +1 -0
- package/src/route-renderer/page-loading/page-module-loader.js +1 -0
- package/src/route-renderer/page-loading/resolved-page-dependencies.d.ts +12 -0
- package/src/route-renderer/page-loading/resolved-page-dependencies.js +38 -0
- package/src/static-site-generator/production-page-browser-graph-prebuild.d.ts +10 -6
- package/src/static-site-generator/production-page-browser-graph-prebuild.js +29 -10
- package/src/static-site-generator/static-site-generator.js +4 -1
- package/src/types/public-types.d.ts +9 -1
- package/src/route-renderer/orchestration/page-browser-graph/page-browser-graph-contribution.loader.d.ts +0 -9
- package/src/route-renderer/orchestration/page-browser-graph/page-browser-graph-contribution.loader.js +0 -11
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.38",
|
|
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.38",
|
|
21
21
|
"@ecopages/logger": "^0.2.3",
|
|
22
22
|
"@ecopages/scripts-injector": "^0.1.5",
|
|
23
23
|
"@oxc-project/runtime": "0.141.0",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"@standard-schema/utils": "^0.3.0"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
|
-
"@ecopages/dev-toolbar": "0.2.0-beta.
|
|
35
|
+
"@ecopages/dev-toolbar": "0.2.0-beta.38"
|
|
36
36
|
},
|
|
37
37
|
"peerDependenciesMeta": {
|
|
38
38
|
"@ecopages/dev-toolbar": {
|
|
@@ -80,6 +80,10 @@
|
|
|
80
80
|
"types": "./src/route-renderer/orchestration/page-browser-graph/page-browser-graph-merge.utils.d.ts",
|
|
81
81
|
"default": "./src/route-renderer/orchestration/page-browser-graph/page-browser-graph-merge.utils.js"
|
|
82
82
|
},
|
|
83
|
+
"./route-renderer/page-loading/file-scoped-dependency-components": {
|
|
84
|
+
"types": "./src/route-renderer/page-loading/file-scoped-dependency-components.d.ts",
|
|
85
|
+
"default": "./src/route-renderer/page-loading/file-scoped-dependency-components.js"
|
|
86
|
+
},
|
|
83
87
|
"./route-renderer/orchestration/foreign-child/owning-renderer-resolution": {
|
|
84
88
|
"types": "./src/route-renderer/orchestration/foreign-child/owning-renderer-resolution.d.ts",
|
|
85
89
|
"default": "./src/route-renderer/orchestration/foreign-child/owning-renderer-resolution.js"
|
|
@@ -357,6 +361,10 @@
|
|
|
357
361
|
"types": "./src/route-renderer/orchestration/page-browser-graph/page-browser-graph-merge.utils.d.ts",
|
|
358
362
|
"default": "./src/route-renderer/orchestration/page-browser-graph/page-browser-graph-merge.utils.js"
|
|
359
363
|
},
|
|
364
|
+
"./route-renderer/page-loading/file-scoped-dependency-components.ts": {
|
|
365
|
+
"types": "./src/route-renderer/page-loading/file-scoped-dependency-components.d.ts",
|
|
366
|
+
"default": "./src/route-renderer/page-loading/file-scoped-dependency-components.js"
|
|
367
|
+
},
|
|
360
368
|
"./route-renderer/orchestration/foreign-child/owning-renderer-resolution.ts": {
|
|
361
369
|
"types": "./src/route-renderer/orchestration/foreign-child/owning-renderer-resolution.d.ts",
|
|
362
370
|
"default": "./src/route-renderer/orchestration/foreign-child/owning-renderer-resolution.js"
|
|
@@ -14,16 +14,16 @@ Server-side wiring for the development-only in-browser inspector. Public docs: [
|
|
|
14
14
|
|
|
15
15
|
## Module map
|
|
16
16
|
|
|
17
|
-
| File
|
|
18
|
-
|
|
|
19
|
-
| `dev-toolbar-host.ts`
|
|
17
|
+
| File | Role |
|
|
18
|
+
| ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
19
|
+
| `dev-toolbar-host.ts` | Enablement, manifest contribution, runtime bundling, HTML injection |
|
|
20
20
|
| `dev-toolbar-manifest-contract.ts` | `#__ECO_DEV_MANIFEST__` id and payload types (public: `@ecopages/core/dev-toolbar/dev-toolbar-manifest-contract`; mirrored in `@ecopages/dev-toolbar` for browser bundling) |
|
|
21
|
-
| `dev-toolbar-manifest.ts`
|
|
22
|
-
| `dev-toolbar-package.ts`
|
|
23
|
-
| `dev-toolbar-config.ts`
|
|
24
|
-
| `dev-toolbar-html-response.ts`
|
|
25
|
-
| `dev-toolbar-runtime-paths.ts`
|
|
26
|
-
| `define-dev-tool.ts`
|
|
21
|
+
| `dev-toolbar-manifest.ts` | Builds and serializes the per-page dev manifest |
|
|
22
|
+
| `dev-toolbar-package.ts` | Resolves `devToolbar.package` bootstrap entry (`bootstrap.js`, then `.ts`) |
|
|
23
|
+
| `dev-toolbar-config.ts` | `isDevToolbarEnabled` — watch mode, env var, package required |
|
|
24
|
+
| `dev-toolbar-html-response.ts` | Adapter helpers for injecting `import '/_dev_toolbar.js'` |
|
|
25
|
+
| `dev-toolbar-runtime-paths.ts` | `/_dev_toolbar.js` URL and work-dir paths |
|
|
26
|
+
| `define-dev-tool.ts` | Config helper for bring-your-own client packages |
|
|
27
27
|
|
|
28
28
|
## Injection order
|
|
29
29
|
|
package/src/eco/eco.browser.js
CHANGED
|
@@ -22,12 +22,16 @@ function layout(options) {
|
|
|
22
22
|
return createComponentFactory(options);
|
|
23
23
|
}
|
|
24
24
|
function page(options) {
|
|
25
|
-
const { layout: pageLayout, dependencies, render, staticPaths, staticProps, metadata, cache, requires, middleware, } = options;
|
|
25
|
+
const { layout: pageLayout, dependencies: dependenciesInput, render, staticPaths, staticProps, metadata, cache, requires, middleware, } = options;
|
|
26
26
|
const layoutEntries = normalizePageLayouts(pageLayout);
|
|
27
|
+
const resolveDependencies = typeof dependenciesInput === 'function' ? dependenciesInput : undefined;
|
|
28
|
+
const staticDependencies = typeof dependenciesInput === 'function'
|
|
29
|
+
? mergeLayoutDependencies(undefined, layoutEntries)
|
|
30
|
+
: mergeLayoutDependencies(dependenciesInput, layoutEntries);
|
|
27
31
|
const pageComponent = createComponentFactory({
|
|
28
32
|
__eco: options.__eco,
|
|
29
33
|
integration: options.integration,
|
|
30
|
-
dependencies:
|
|
34
|
+
dependencies: staticDependencies,
|
|
31
35
|
render,
|
|
32
36
|
});
|
|
33
37
|
if (pageComponent.config) {
|
|
@@ -42,6 +46,9 @@ function page(options) {
|
|
|
42
46
|
if (metadata) {
|
|
43
47
|
pageComponent.metadata = metadata;
|
|
44
48
|
}
|
|
49
|
+
if (resolveDependencies) {
|
|
50
|
+
pageComponent.resolveDependencies = resolveDependencies;
|
|
51
|
+
}
|
|
45
52
|
if (cache) {
|
|
46
53
|
pageComponent.cache = cache;
|
|
47
54
|
}
|
package/src/eco/eco.js
CHANGED
|
@@ -110,12 +110,16 @@ function layout(options) {
|
|
|
110
110
|
* @returns Eco page component.
|
|
111
111
|
*/
|
|
112
112
|
function page(options) {
|
|
113
|
-
const { layout, dependencies, render, staticPaths, staticProps, metadata, cache, requires, middleware } = options;
|
|
113
|
+
const { layout, dependencies: dependenciesInput, render, staticPaths, staticProps, metadata, cache, requires, middleware, } = options;
|
|
114
114
|
const layoutEntries = normalizePageLayouts(layout);
|
|
115
|
+
const resolveDependencies = typeof dependenciesInput === 'function' ? dependenciesInput : undefined;
|
|
116
|
+
const staticDependencies = typeof dependenciesInput === 'function'
|
|
117
|
+
? mergeLayoutDependencies(undefined, layoutEntries)
|
|
118
|
+
: mergeLayoutDependencies(dependenciesInput, layoutEntries);
|
|
115
119
|
const componentOptions = {
|
|
116
120
|
__eco: options.__eco,
|
|
117
121
|
integration: options.integration,
|
|
118
|
-
dependencies:
|
|
122
|
+
dependencies: staticDependencies,
|
|
119
123
|
render,
|
|
120
124
|
};
|
|
121
125
|
const pageComponent = createComponentFactory(componentOptions);
|
|
@@ -128,6 +132,8 @@ function page(options) {
|
|
|
128
132
|
pageComponent.staticProps = staticProps;
|
|
129
133
|
if (metadata)
|
|
130
134
|
pageComponent.metadata = metadata;
|
|
135
|
+
if (resolveDependencies)
|
|
136
|
+
pageComponent.resolveDependencies = resolveDependencies;
|
|
131
137
|
if (cache)
|
|
132
138
|
pageComponent.cache = cache;
|
|
133
139
|
if (requires)
|
package/src/eco/eco.types.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Type definitions for the eco namespace API
|
|
3
3
|
* @module
|
|
4
4
|
*/
|
|
5
|
-
import type { DependencyLazyTrigger, EcoComponent, EcoComponentDependencies, EcoHtmlComponent, EcoInjectedMeta, EcoLayoutComponent, EcoPageLayouts, EcoPagesElement, FileRouteMiddleware, GetMetadata, GetStaticPaths, GetStaticProps, HtmlTemplateProps, LayoutProps, RequestLocals, RequestPageContext } from '../types/public-types.js';
|
|
5
|
+
import type { DependencyLazyTrigger, EcoComponent, EcoComponentDependencies, EcoHtmlComponent, EcoInjectedMeta, EcoLayoutComponent, EcoPageLayouts, EcoPagesElement, FileRouteMiddleware, GetMetadata, GetStaticPaths, GetStaticProps, HtmlTemplateProps, LayoutProps, RequestLocals, RequestPageContext, PageParams, PageQuery } from '../types/public-types.js';
|
|
6
6
|
import type { CacheStrategy } from '../services/cache/cache.types.js';
|
|
7
7
|
/**
|
|
8
8
|
* Extracts the props type from one eco component.
|
|
@@ -54,6 +54,28 @@ type WithRequiredLocals<K extends keyof RequestLocals> = Omit<RequestLocals, K>
|
|
|
54
54
|
};
|
|
55
55
|
type RequiresKeys = keyof RequestLocals;
|
|
56
56
|
export type PageRequires<K extends RequiresKeys = RequiresKeys> = K | readonly K[];
|
|
57
|
+
/**
|
|
58
|
+
* Context passed to a page `dependencies` resolver for one concrete route render.
|
|
59
|
+
*/
|
|
60
|
+
export type GetPageDependenciesContext<T = Record<string, unknown>> = {
|
|
61
|
+
props: PagePropsFor<T>;
|
|
62
|
+
params?: PageParams;
|
|
63
|
+
query?: PageQuery;
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Page dependency bag optionally scoped to a declaring file.
|
|
67
|
+
*/
|
|
68
|
+
export type PageDependenciesResult = EcoComponentDependencies & {
|
|
69
|
+
ownerFile?: string;
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* Resolves request-specific page dependencies for one route render.
|
|
73
|
+
*/
|
|
74
|
+
export type GetPageDependencies<T = Record<string, unknown>> = (context: GetPageDependenciesContext<T>) => PageDependenciesResult | undefined | Promise<PageDependenciesResult | undefined>;
|
|
75
|
+
/**
|
|
76
|
+
* Static page dependencies or a per-render resolver.
|
|
77
|
+
*/
|
|
78
|
+
export type PageDependenciesInput<T = Record<string, unknown>> = EcoComponentDependencies | GetPageDependencies<T>;
|
|
57
79
|
/**
|
|
58
80
|
* Lazy trigger options map directly to scripts-injector attributes.
|
|
59
81
|
* Only one trigger type can be active at a time.
|
|
@@ -91,7 +113,11 @@ export interface PageOptionsBase<T, E = EcoPagesElement> {
|
|
|
91
113
|
/** @internal Injected by eco-component-meta-plugin */
|
|
92
114
|
__eco?: EcoInjectedMeta;
|
|
93
115
|
integration?: string;
|
|
94
|
-
|
|
116
|
+
/**
|
|
117
|
+
* Declares browser dependencies for the page, or resolves them per render after
|
|
118
|
+
* `staticProps` are available.
|
|
119
|
+
*/
|
|
120
|
+
dependencies?: PageDependenciesInput<T>;
|
|
95
121
|
layout?: EcoPageLayouts<E>;
|
|
96
122
|
/**
|
|
97
123
|
* Define static paths for dynamic routes (e.g., [slug].tsx).
|
|
@@ -178,6 +204,7 @@ export type EcoPageComponent<T> = EcoComponent<PagePropsFor<T> & Partial<Request
|
|
|
178
204
|
staticPaths?: GetStaticPaths;
|
|
179
205
|
staticProps?: GetStaticProps<T>;
|
|
180
206
|
metadata?: GetMetadata<T>;
|
|
207
|
+
resolveDependencies?: GetPageDependencies<T>;
|
|
181
208
|
cache?: CacheStrategy;
|
|
182
209
|
requires?: PageRequires;
|
|
183
210
|
middleware?: FileRouteMiddleware[];
|
package/src/hmr/README.md
CHANGED
|
@@ -37,11 +37,11 @@ Hosts call `prepareHmrFileChange()` before HMR dispatch (`hmr/hmr-file-change-pr
|
|
|
37
37
|
|
|
38
38
|
## Client events
|
|
39
39
|
|
|
40
|
-
| Event
|
|
41
|
-
|
|
|
42
|
-
| `update`
|
|
43
|
-
| `css-update`
|
|
40
|
+
| Event | Client behavior |
|
|
41
|
+
| --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
42
|
+
| `update` | Cache-bust and re-import the changed module URL (or reload the active page module) |
|
|
43
|
+
| `css-update` | Refresh matching stylesheet `link` hrefs |
|
|
44
44
|
| `layout-update` | Soft current-page reload with layout cache cleared (`persistLayouts` remounts the updated layout without a full document reload). Falls back to `location.reload()` only if no navigation owner handles it |
|
|
45
|
-
| `reload`
|
|
45
|
+
| `reload` | Full `location.reload()` |
|
|
46
46
|
|
|
47
47
|
Dev-transform local imports are rewritten with a content-hash query (`?v=…`) so transitive layout/component modules get a new ESM module-map key after invalidation. Soft `layout-update` then picks up the new layout while shared outer layout persistence still applies across normal SPA navigations.
|
|
@@ -84,7 +84,7 @@ The route-render contract is:
|
|
|
84
84
|
|
|
85
85
|
1. `RouteRendererFactory` selects the owning integration renderer.
|
|
86
86
|
2. `IntegrationRenderer.execute()` delegates preparation and finalization to `RouteRenderOrchestrator`.
|
|
87
|
-
3. `RouteRenderOrchestrator.prepareRenderOptions()` loads the page module, validates ownership (fail-fast), resolves page
|
|
87
|
+
3. `RouteRenderOrchestrator.prepareRenderOptions()` loads the page module, validates ownership (fail-fast), resolves final page props, resolves dependencies, and builds the page browser graph. Graph cache identity includes route params and query; contribution collection receives those same final props.
|
|
88
88
|
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.
|
|
89
89
|
5. If a renderer needs queued handoff, it emits internal foreign-subtree tokens and resolves them before returning final HTML.
|
|
90
90
|
6. `RouteRenderOrchestrator.executePrepared()` captures the final body, rejects unresolved `<eco-marker>` artifacts, stamps document attributes when needed, and runs the HTML transformer.
|
|
@@ -93,6 +93,7 @@ Important:
|
|
|
93
93
|
|
|
94
94
|
- route-level fallback resolution is gone; unresolved artifacts are now a hard failure
|
|
95
95
|
- ownership is declared from component metadata, not inferred from final HTML
|
|
96
|
+
- declared page dependencies are resolved from final render inputs and carried to the owning integration; integrations may use them for renderer-specific lifecycle work such as HMR ownership
|
|
96
97
|
- same-integration children stay renderer-local and do not need to pass through a universal transport
|
|
97
98
|
|
|
98
99
|
## Declared Foreign Child Contract
|
|
@@ -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, EcoComponent, EcoPageFile, EcoPagesElement, HtmlTemplateProps, IntegrationRendererRenderOptions, PageBrowserGraphContribution, PageBrowserGraphContributionContext, PageBrowserGraphResult, PageMetadataProps, RouteRendererBody, RouteRendererOptions, RouteRenderResult } from '../../types/public-types.js';
|
|
7
|
+
import type { ComponentRenderInput, ComponentRenderResult, EcoComponent, EcoComponentDependencies, EcoPageFile, EcoPagesElement, HtmlTemplateProps, IntegrationRendererRenderOptions, PageBrowserGraphContribution, PageBrowserGraphContributionContext, PageBrowserGraphResult, PageMetadataProps, 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';
|
|
@@ -12,6 +12,8 @@ import { HttpError } from '../../errors/http-error.js';
|
|
|
12
12
|
import { DependencyResolverService } from '../page-loading/dependency-resolver.js';
|
|
13
13
|
import { PageModuleLoaderService } from '../page-loading/page-module-loader.js';
|
|
14
14
|
import { RouteRenderOrchestrator, type RouteRenderOrchestratorAdapter, type RouteRenderOrchestratorResolvedInputs } from './route-pipeline/route-render-orchestrator.js';
|
|
15
|
+
import { type ResolvedPageDependencies } from '../page-loading/resolved-page-dependencies.js';
|
|
16
|
+
import { type GroupedGraphBuildPlan } from './page-browser-graph/grouped-graph-build-plan.js';
|
|
15
17
|
import type { ForeignChildRuntime } from './foreign-child/component-render-context.js';
|
|
16
18
|
import { ForeignSubtreeExecutionService } from './foreign-child/foreign-subtree-execution.service.js';
|
|
17
19
|
/**
|
|
@@ -72,9 +74,19 @@ export declare abstract class IntegrationRenderer<C = EcoPagesElement> {
|
|
|
72
74
|
*/
|
|
73
75
|
protected ensureIntegrationRuntimeActivated(): Promise<void>;
|
|
74
76
|
/**
|
|
75
|
-
* Prebuilds the production Page Browser Graph for one route file.
|
|
77
|
+
* Prebuilds the production Page Browser Graph for one route file and optional params.
|
|
76
78
|
*/
|
|
77
|
-
prebuildProductionPageBrowserGraph(routeFile: string
|
|
79
|
+
prebuildProductionPageBrowserGraph(routeFile: string, options?: Pick<RouteRendererOptions, 'params' | 'query'> & {
|
|
80
|
+
groupedBuildPlan?: GroupedGraphBuildPlan;
|
|
81
|
+
}): Promise<void>;
|
|
82
|
+
/**
|
|
83
|
+
* Builds one production grouped graph plan for the supplied static route instances.
|
|
84
|
+
*/
|
|
85
|
+
buildGroupedGraphBuildPlan(instances: ReadonlyArray<{
|
|
86
|
+
routeFile: string;
|
|
87
|
+
params?: RouteRendererOptions['params'];
|
|
88
|
+
query?: RouteRendererOptions['query'];
|
|
89
|
+
}>): Promise<GroupedGraphBuildPlan>;
|
|
78
90
|
/**
|
|
79
91
|
* Loads one route module through the owning renderer's import path.
|
|
80
92
|
*
|
|
@@ -118,6 +130,7 @@ export declare abstract class IntegrationRenderer<C = EcoPagesElement> {
|
|
|
118
130
|
*/
|
|
119
131
|
protected prepareViewDependencies(view: EcoComponent, layout?: EcoComponent): Promise<ProcessedAsset[]>;
|
|
120
132
|
protected resolvePageBrowserGraphForFile(filePath: string): Promise<PageBrowserGraphResult | undefined>;
|
|
133
|
+
protected resolvePageBrowserGraphForRoute(filePath: string, routeOptions?: Pick<RouteRendererOptions, 'params' | 'query'>, groupedBuildPlan?: GroupedGraphBuildPlan): Promise<PageBrowserGraphResult | undefined>;
|
|
121
134
|
/**
|
|
122
135
|
* Merges component-scoped assets into the active HTML transformer state.
|
|
123
136
|
*
|
|
@@ -270,6 +283,9 @@ export declare abstract class IntegrationRenderer<C = EcoPagesElement> {
|
|
|
270
283
|
*/
|
|
271
284
|
protected createRouteRenderOrchestratorAdapter(): RouteRenderOrchestratorAdapter<C>;
|
|
272
285
|
protected resolveRouteRenderInputs(routeOptions: RouteRendererOptions): Promise<RouteRenderOrchestratorResolvedInputs>;
|
|
286
|
+
protected buildPageBrowserGraphContributionContext(routeFile: string, routeOptions?: Pick<RouteRendererOptions, 'params' | 'query'>): Promise<PageBrowserGraphContributionContext>;
|
|
287
|
+
protected resolvePageDependencies(context: PageBrowserGraphContributionContext): Promise<ResolvedPageDependencies | undefined>;
|
|
288
|
+
protected resolvePageBrowserGraphContributionFromDependencies(dependencies: EcoComponentDependencies, ownerFile: string): Promise<PageBrowserGraphContribution | undefined>;
|
|
273
289
|
protected resolveRouteDependencies(input: {
|
|
274
290
|
components: (EcoComponent | Partial<EcoComponent>)[];
|
|
275
291
|
}): Promise<{
|
|
@@ -13,7 +13,11 @@ import { OwnershipValidationService } from './ownership-graph/ownership-validati
|
|
|
13
13
|
import { hasForeignChildDescendantsInGraph } from './ownership-graph/component-graph-collectors.js';
|
|
14
14
|
import { RouteRenderOrchestrator, } from './route-pipeline/route-render-orchestrator.js';
|
|
15
15
|
import { createIntegrationRouteRenderAdapter } from './route-pipeline/integration-route-render-adapter.js';
|
|
16
|
-
import {
|
|
16
|
+
import { createPageDependencyInstanceKey } from './page-browser-graph/route-instance-key.js';
|
|
17
|
+
import { mergePageBrowserGraphContributions } from './page-browser-graph/page-browser-graph-contribution.merge.js';
|
|
18
|
+
import { collectDependencyWatchPaths, collectFileScopedDependencyComponents, } from '../page-loading/file-scoped-dependency-components.js';
|
|
19
|
+
import { resolvePageDependenciesFromContext, } from '../page-loading/resolved-page-dependencies.js';
|
|
20
|
+
import { createGroupedGraphBuildPlanKey, } from './page-browser-graph/grouped-graph-build-plan.js';
|
|
17
21
|
import { normalizeUnresolvedMarkerArtifactHtml } from './route-pipeline/marker-artifact.utils.js';
|
|
18
22
|
import { isMarkupNodeLike } from './foreign-child/foreign-child-output.utils.js';
|
|
19
23
|
import { getForeignSubtreeResolutionContextKey, getForeignSubtreeTokenPrefix, resolveOwningIntegrationRenderer, } from './foreign-child/owning-renderer-resolution.js';
|
|
@@ -66,11 +70,30 @@ export class IntegrationRenderer {
|
|
|
66
70
|
});
|
|
67
71
|
}
|
|
68
72
|
/**
|
|
69
|
-
* Prebuilds the production Page Browser Graph for one route file.
|
|
73
|
+
* Prebuilds the production Page Browser Graph for one route file and optional params.
|
|
70
74
|
*/
|
|
71
|
-
async prebuildProductionPageBrowserGraph(routeFile) {
|
|
75
|
+
async prebuildProductionPageBrowserGraph(routeFile, options) {
|
|
72
76
|
await this.ensureIntegrationRuntimeActivated();
|
|
73
|
-
await this.
|
|
77
|
+
await this.resolvePageBrowserGraphForRoute(routeFile, options, options?.groupedBuildPlan);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Builds one production grouped graph plan for the supplied static route instances.
|
|
81
|
+
*/
|
|
82
|
+
async buildGroupedGraphBuildPlan(instances) {
|
|
83
|
+
const builtInstances = await Promise.all(instances.map(async (routeInstance) => {
|
|
84
|
+
const context = await this.buildPageBrowserGraphContributionContext(routeInstance.routeFile, routeInstance);
|
|
85
|
+
const resolvedPageDependencies = await this.resolvePageDependencies(context);
|
|
86
|
+
return {
|
|
87
|
+
routeFile: routeInstance.routeFile,
|
|
88
|
+
dependencyInstanceKey: context.dependencyInstanceKey ?? '',
|
|
89
|
+
contribution: mergePageBrowserGraphContributions(await this.collectPageBrowserGraphContribution(context), resolvedPageDependencies?.contribution),
|
|
90
|
+
};
|
|
91
|
+
}));
|
|
92
|
+
return {
|
|
93
|
+
integrationName: this.name,
|
|
94
|
+
planKey: createGroupedGraphBuildPlanKey(this.name, builtInstances),
|
|
95
|
+
instances: builtInstances,
|
|
96
|
+
};
|
|
74
97
|
}
|
|
75
98
|
/**
|
|
76
99
|
* Loads one route module through the owning renderer's import path.
|
|
@@ -173,10 +196,23 @@ export class IntegrationRenderer {
|
|
|
173
196
|
return resolvedDependencies;
|
|
174
197
|
}
|
|
175
198
|
async resolvePageBrowserGraphForFile(filePath) {
|
|
199
|
+
/**
|
|
200
|
+
* @remarks
|
|
201
|
+
* Integration renderers such as React still call this file-only entry point
|
|
202
|
+
* during explicit view rendering. Route-instance-aware callers should prefer
|
|
203
|
+
* `resolvePageBrowserGraphForRoute`.
|
|
204
|
+
*/
|
|
205
|
+
return this.resolvePageBrowserGraphForRoute(filePath);
|
|
206
|
+
}
|
|
207
|
+
async resolvePageBrowserGraphForRoute(filePath, routeOptions, groupedBuildPlan) {
|
|
208
|
+
const graphContext = await this.buildPageBrowserGraphContributionContext(filePath, routeOptions);
|
|
209
|
+
const resolvedPageDependencies = await this.resolvePageDependencies(graphContext);
|
|
176
210
|
return await this.routeRenderOrchestrator.resolveDeclaredPageBrowserGraph({
|
|
177
211
|
routeFile: filePath,
|
|
212
|
+
dependencyInstanceKey: graphContext.dependencyInstanceKey,
|
|
178
213
|
integrationName: this.name,
|
|
179
|
-
|
|
214
|
+
groupedBuildPlan,
|
|
215
|
+
collectContribution: async () => mergePageBrowserGraphContributions(await this.collectPageBrowserGraphContribution(graphContext), resolvedPageDependencies?.contribution),
|
|
180
216
|
});
|
|
181
217
|
}
|
|
182
218
|
/**
|
|
@@ -494,6 +530,8 @@ export class IntegrationRenderer {
|
|
|
494
530
|
resolveRouteDependencies: (input) => this.resolveRouteDependencies(input),
|
|
495
531
|
importPageFile: (file) => this.importPageFile(file),
|
|
496
532
|
collectPageBrowserGraphContribution: (context) => this.collectPageBrowserGraphContribution(context),
|
|
533
|
+
resolvePageDependencies: (context) => this.resolvePageDependencies(context),
|
|
534
|
+
buildPageBrowserGraphContributionContext: (routeFile, routeOptions) => this.buildPageBrowserGraphContributionContext(routeFile, routeOptions),
|
|
497
535
|
renderRouteBody: (renderOptions) => this.renderRouteBody(renderOptions),
|
|
498
536
|
getDocumentAttributes: (renderOptions) => this.getDocumentAttributes(renderOptions),
|
|
499
537
|
getHtmlDocumentContributions: (options) => this.getHtmlDocumentContributions(options),
|
|
@@ -506,20 +544,21 @@ export class IntegrationRenderer {
|
|
|
506
544
|
});
|
|
507
545
|
}
|
|
508
546
|
async resolveRouteRenderInputs(routeOptions) {
|
|
509
|
-
const
|
|
547
|
+
const resolvedPageModule = await this.pageModuleLoaderService.resolvePageModule({
|
|
510
548
|
file: routeOptions.file,
|
|
511
549
|
importPageFileFn: (targetFile) => this.importPageFile(targetFile),
|
|
512
550
|
});
|
|
513
|
-
const { Page, integrationSpecificProps } =
|
|
551
|
+
const { Page, integrationSpecificProps, module: pageModule } = resolvedPageModule;
|
|
514
552
|
const HtmlTemplate = await this.getHtmlTemplate();
|
|
515
553
|
const Layouts = resolvePageLayoutComponents(Page.config?.layouts);
|
|
516
554
|
const Layout = resolveInnermostPageLayout(Layouts);
|
|
517
555
|
const { props, metadata } = await this.pageModuleLoaderService.resolvePageData({
|
|
518
|
-
pageModule,
|
|
556
|
+
pageModule: resolvedPageModule,
|
|
519
557
|
routeOptions,
|
|
520
558
|
});
|
|
521
559
|
return {
|
|
522
560
|
Page,
|
|
561
|
+
pageModule,
|
|
523
562
|
HtmlTemplate: HtmlTemplate,
|
|
524
563
|
Layouts,
|
|
525
564
|
Layout,
|
|
@@ -529,6 +568,48 @@ export class IntegrationRenderer {
|
|
|
529
568
|
integrationSpecificProps,
|
|
530
569
|
};
|
|
531
570
|
}
|
|
571
|
+
async buildPageBrowserGraphContributionContext(routeFile, routeOptions) {
|
|
572
|
+
const { module: pageModule, ...resolvedPageModule } = await this.pageModuleLoaderService.resolvePageModule({
|
|
573
|
+
file: routeFile,
|
|
574
|
+
importPageFileFn: (targetFile) => this.importPageFile(targetFile),
|
|
575
|
+
});
|
|
576
|
+
const { props } = await this.pageModuleLoaderService.resolvePageData({
|
|
577
|
+
pageModule: resolvedPageModule,
|
|
578
|
+
routeOptions: {
|
|
579
|
+
file: routeFile,
|
|
580
|
+
params: routeOptions?.params,
|
|
581
|
+
query: routeOptions?.query,
|
|
582
|
+
},
|
|
583
|
+
});
|
|
584
|
+
return {
|
|
585
|
+
file: routeFile,
|
|
586
|
+
pageModule,
|
|
587
|
+
props,
|
|
588
|
+
params: routeOptions?.params,
|
|
589
|
+
query: routeOptions?.query,
|
|
590
|
+
dependencyInstanceKey: createPageDependencyInstanceKey({
|
|
591
|
+
params: routeOptions?.params,
|
|
592
|
+
query: routeOptions?.query,
|
|
593
|
+
}),
|
|
594
|
+
};
|
|
595
|
+
}
|
|
596
|
+
async resolvePageDependencies(context) {
|
|
597
|
+
return resolvePageDependenciesFromContext(context, this.name, (dependencies, ownerFile) => this.resolvePageBrowserGraphContributionFromDependencies(dependencies, ownerFile));
|
|
598
|
+
}
|
|
599
|
+
async resolvePageBrowserGraphContributionFromDependencies(dependencies, ownerFile) {
|
|
600
|
+
const components = collectFileScopedDependencyComponents({
|
|
601
|
+
ownerFile,
|
|
602
|
+
integrationName: this.name,
|
|
603
|
+
dependencies,
|
|
604
|
+
});
|
|
605
|
+
if (components.length === 0) {
|
|
606
|
+
return undefined;
|
|
607
|
+
}
|
|
608
|
+
return {
|
|
609
|
+
assets: await this.processComponentDependencies(components),
|
|
610
|
+
watchPaths: collectDependencyWatchPaths(ownerFile, components),
|
|
611
|
+
};
|
|
612
|
+
}
|
|
532
613
|
async resolveRouteDependencies(input) {
|
|
533
614
|
return {
|
|
534
615
|
resolvedDependencies: await this.resolveDependencies(input.components),
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { PageBrowserGraphContribution } from '../../../types/public-types.js';
|
|
2
|
+
export type GroupedGraphBuildPlanInstance = {
|
|
3
|
+
routeFile: string;
|
|
4
|
+
dependencyInstanceKey: string;
|
|
5
|
+
contribution?: PageBrowserGraphContribution;
|
|
6
|
+
};
|
|
7
|
+
export type GroupedGraphBuildPlan = {
|
|
8
|
+
integrationName: string;
|
|
9
|
+
planKey: string;
|
|
10
|
+
instances: ReadonlyArray<GroupedGraphBuildPlanInstance>;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Builds a stable grouped-cache identity for one integration static export plan.
|
|
14
|
+
*/
|
|
15
|
+
export declare function createGroupedGraphBuildPlanKey(integrationName: string, instances: ReadonlyArray<Pick<GroupedGraphBuildPlanInstance, 'routeFile' | 'dependencyInstanceKey'>>): string;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds a stable grouped-cache identity for one integration static export plan.
|
|
3
|
+
*/
|
|
4
|
+
export function createGroupedGraphBuildPlanKey(integrationName, instances) {
|
|
5
|
+
const canonicalInstances = [...instances]
|
|
6
|
+
.map((instance) => [instance.routeFile, instance.dependencyInstanceKey])
|
|
7
|
+
.sort((left, right) => JSON.stringify(left).localeCompare(JSON.stringify(right)));
|
|
8
|
+
return JSON.stringify(['grouped-plan', integrationName, canonicalInstances]);
|
|
9
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { PageBrowserGraphContribution } from '../../../types/public-types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Merges multiple Page Browser Graph contributions into one declarative payload.
|
|
4
|
+
*/
|
|
5
|
+
export declare function mergePageBrowserGraphContributions(...contributions: Array<PageBrowserGraphContribution | undefined>): PageBrowserGraphContribution | undefined;
|
package/src/route-renderer/orchestration/page-browser-graph/page-browser-graph-contribution.merge.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Merges multiple Page Browser Graph contributions into one declarative payload.
|
|
3
|
+
*/
|
|
4
|
+
export function mergePageBrowserGraphContributions(...contributions) {
|
|
5
|
+
const dependencies = [];
|
|
6
|
+
const assets = [];
|
|
7
|
+
const watchPaths = new Set();
|
|
8
|
+
for (const contribution of contributions) {
|
|
9
|
+
if (!contribution) {
|
|
10
|
+
continue;
|
|
11
|
+
}
|
|
12
|
+
if (contribution.dependencies?.length) {
|
|
13
|
+
dependencies.push(...contribution.dependencies);
|
|
14
|
+
}
|
|
15
|
+
if (contribution.assets?.length) {
|
|
16
|
+
assets.push(...contribution.assets);
|
|
17
|
+
}
|
|
18
|
+
for (const watchPath of contribution.watchPaths ?? []) {
|
|
19
|
+
watchPaths.add(watchPath);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
if (dependencies.length === 0 && assets.length === 0 && watchPaths.size === 0) {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
...(dependencies.length > 0 ? { dependencies } : {}),
|
|
27
|
+
...(assets.length > 0 ? { assets } : {}),
|
|
28
|
+
...(watchPaths.size > 0 ? { watchPaths: Array.from(watchPaths) } : {}),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { GroupedGraphScope } from './route-instance-key.js';
|
|
1
2
|
import type { EcoPagesAppConfig } from '../../../types/internal-types.js';
|
|
2
3
|
import type { PageBrowserGraphContribution, PageBrowserGraphResult } from '../../../types/public-types.js';
|
|
3
4
|
import type { ProcessedAsset } from '../../../services/assets/asset-processing-service/assets.types.js';
|
|
@@ -5,6 +6,7 @@ export type GraphPolicy = 'development' | 'production';
|
|
|
5
6
|
export type GraphKey = {
|
|
6
7
|
integrationName: string;
|
|
7
8
|
routeFile: string;
|
|
9
|
+
dependencyInstanceKey: string;
|
|
8
10
|
entryFingerprint: string;
|
|
9
11
|
policy: GraphPolicy;
|
|
10
12
|
};
|
|
@@ -18,6 +20,11 @@ export type GraphRecord = {
|
|
|
18
20
|
export type GraphBuildResult = {
|
|
19
21
|
result: PageBrowserGraphResult;
|
|
20
22
|
dependencyPaths: ReadonlySet<string>;
|
|
23
|
+
/**
|
|
24
|
+
* @remarks
|
|
25
|
+
* When false, the build result is returned to callers but not committed to the session cache.
|
|
26
|
+
*/
|
|
27
|
+
cacheable?: boolean;
|
|
21
28
|
};
|
|
22
29
|
type GroupedGraphRecord = {
|
|
23
30
|
assetsByRoute: Map<string, ProcessedAsset[]>;
|
|
@@ -32,6 +39,7 @@ export type GroupedGraphBuildOutcome = GroupedGraphRecord | {
|
|
|
32
39
|
export type AffectedGraphIdentity = {
|
|
33
40
|
integrationName: string;
|
|
34
41
|
routeFile: string;
|
|
42
|
+
dependencyInstanceKey: string;
|
|
35
43
|
policy: GraphPolicy;
|
|
36
44
|
entryFingerprint: string;
|
|
37
45
|
};
|
|
@@ -42,8 +50,10 @@ export declare class GraphDependencyIndex {
|
|
|
42
50
|
private readonly dependencyToGraphKeys;
|
|
43
51
|
bindRecord(record: GraphRecord): void;
|
|
44
52
|
unbindRecord(record: GraphRecord): void;
|
|
45
|
-
bindGroupedRecord(
|
|
46
|
-
unbindGroupedRecord(
|
|
53
|
+
bindGroupedRecord(cacheKey: string, record: GroupedGraphRecord): void;
|
|
54
|
+
unbindGroupedRecord(cacheKey: string, record: GroupedGraphRecord): void;
|
|
55
|
+
bindPaths(serializedKey: string, dependencyPaths: ReadonlySet<string>): void;
|
|
56
|
+
unbindPaths(serializedKey: string, dependencyPaths: ReadonlySet<string>): void;
|
|
47
57
|
getAffectedKeys(filePath: string): Set<string>;
|
|
48
58
|
resetForTests(): void;
|
|
49
59
|
private addDependencyBinding;
|
|
@@ -55,21 +65,23 @@ export declare class GraphDependencyIndex {
|
|
|
55
65
|
export declare class SessionPageBrowserGraphCache {
|
|
56
66
|
private readonly records;
|
|
57
67
|
private readonly inFlight;
|
|
68
|
+
private readonly inFlightDependencyPaths;
|
|
69
|
+
private readonly inFlightGenerations;
|
|
58
70
|
private readonly groupedRecords;
|
|
59
71
|
private readonly groupedInFlight;
|
|
60
72
|
private readonly dependencyIndex;
|
|
61
73
|
private readonly graphGenerations;
|
|
62
74
|
private readonly groupedGenerations;
|
|
63
75
|
private buildCount;
|
|
64
|
-
getGraphByRoute(integrationName: string, routeFile: string, policy: GraphPolicy): PageBrowserGraphResult | undefined;
|
|
65
76
|
/**
|
|
66
77
|
* Page Browser Graph compilations in this dev-server session.
|
|
67
78
|
*/
|
|
68
79
|
getBuildCount(): number;
|
|
80
|
+
getGraphByRoute(integrationName: string, routeFile: string, policy: GraphPolicy, dependencyInstanceKey?: string): PageBrowserGraphResult | undefined;
|
|
69
81
|
getAffectedGraphIdentities(filePath: string): AffectedGraphIdentity[];
|
|
70
|
-
resolveGraph(key: GraphKey, build: () => Promise<GraphBuildResult | undefined>): Promise<PageBrowserGraphResult | undefined>;
|
|
71
|
-
resolveGroupedGraph(
|
|
72
|
-
peekGroupedGraph(
|
|
82
|
+
resolveGraph(key: GraphKey, provisionalDependencyPaths: ReadonlySet<string>, build: () => Promise<GraphBuildResult | undefined>): Promise<PageBrowserGraphResult | undefined>;
|
|
83
|
+
resolveGroupedGraph(scope: GroupedGraphScope, build: () => Promise<GroupedGraphBuildOutcome | undefined>): Promise<Map<string, ProcessedAsset[]>>;
|
|
84
|
+
peekGroupedGraph(scope: GroupedGraphScope): Map<string, ProcessedAsset[]> | undefined;
|
|
73
85
|
invalidateByFilePath(filePath: string): number;
|
|
74
86
|
invalidateRoute(integrationName: string, routeFile: string): void;
|
|
75
87
|
invalidateByRouteFile(routeFile: string): void;
|
|
@@ -85,6 +97,10 @@ export declare class SessionPageBrowserGraphCache {
|
|
|
85
97
|
private runGroupedBuild;
|
|
86
98
|
private canCommitGraphBuild;
|
|
87
99
|
private canCommitGroupedBuild;
|
|
100
|
+
private bindDependencyPaths;
|
|
101
|
+
private unbindDependencyPaths;
|
|
102
|
+
private clearInFlightBuild;
|
|
103
|
+
private releaseInFlightDependencyPaths;
|
|
88
104
|
}
|
|
89
105
|
/**
|
|
90
106
|
* Returns the session graph cache for one app instance.
|