@ecopages/ecopages-jsx 0.2.1-beta.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -16
- package/package.json +10 -6
- package/src/dev-transform/ecopages-jsx-dev-transform-contributor.d.ts +17 -0
- package/src/dev-transform/ecopages-jsx-dev-transform-contributor.js +21 -0
- package/src/eco-embed.js +8 -10
- package/src/ecopages-jsx-hmr-ownership.d.ts +43 -0
- package/src/ecopages-jsx-hmr-ownership.js +91 -0
- package/src/ecopages-jsx-hmr-strategy.d.ts +19 -0
- package/src/ecopages-jsx-hmr-strategy.js +67 -0
- package/src/ecopages-jsx-mdx.d.ts +22 -11
- package/src/ecopages-jsx-mdx.js +43 -108
- package/src/ecopages-jsx-radiant-ssr-policy.d.ts +12 -6
- package/src/ecopages-jsx-radiant-ssr-policy.js +116 -73
- package/src/ecopages-jsx-renderer.d.ts +10 -45
- package/src/ecopages-jsx-renderer.js +148 -233
- package/src/ecopages-jsx.constants.js +7 -4
- package/src/ecopages-jsx.plugin.d.ts +19 -23
- package/src/ecopages-jsx.plugin.js +137 -111
- package/src/ecopages-jsx.types.d.ts +4 -34
- package/src/ecopages-jsx.types.js +1 -0
- package/src/page-owned-content-script-grouping.d.ts +11 -0
- package/src/page-owned-content-script-grouping.js +57 -0
- package/src/radiant-registered-script-ssr-invalidation.d.ts +19 -0
- package/src/radiant-registered-script-ssr-invalidation.js +49 -0
- package/src/resolve-radiant-install-hydrator.d.ts +2 -0
- package/src/resolve-radiant-install-hydrator.js +3 -0
- package/src/ecopages-jsx-render-session.d.ts +0 -46
- package/src/ecopages-jsx-render-session.js +0 -93
|
@@ -4,13 +4,15 @@ import { createMarkupNodeLike } from '@ecopages/jsx';
|
|
|
4
4
|
*
|
|
5
5
|
* @remarks
|
|
6
6
|
* Radiant's server bridge and light-DOM shim are loaded lazily because most JSX
|
|
7
|
-
* renders do not need them.
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* renders do not need them. Resolved runtime modules are cached on the policy
|
|
8
|
+
* instance so repeated renders on the same renderer reuse one load without
|
|
9
|
+
* process-wide mutable class state. Light-DOM constructor installation remains
|
|
10
|
+
* process-global and idempotent via {@link ensureRadiantLightDomGlobals}; the
|
|
11
|
+
* Radiant installer also repairs incomplete DOM globals left by another runtime.
|
|
10
12
|
*/
|
|
11
13
|
export declare class EcopagesJsxRadiantSsrPolicy {
|
|
12
|
-
private
|
|
13
|
-
private
|
|
14
|
+
private runtimeModules;
|
|
15
|
+
private runtimeModulesPromise;
|
|
14
16
|
private readonly enabled;
|
|
15
17
|
constructor(enabled: boolean);
|
|
16
18
|
/**
|
|
@@ -27,7 +29,11 @@ export declare class EcopagesJsxRadiantSsrPolicy {
|
|
|
27
29
|
* @remarks
|
|
28
30
|
* The returned node-like wrapper lets the JSX server renderer preserve the
|
|
29
31
|
* generated host HTML without escaping it back into plain text.
|
|
32
|
+
*
|
|
33
|
+
* The render hook owns the host's JSX children, so `applyChildren` runs inside the host's context providers.
|
|
34
|
+
* A consumer passed as a child of a provider host then resolves that provider in the server HTML instead of
|
|
35
|
+
* rendering its fallback state.
|
|
30
36
|
*/
|
|
31
|
-
renderIntrinsicElementMarkup(instance: unknown): ReturnType<typeof createMarkupNodeLike> | undefined;
|
|
37
|
+
renderIntrinsicElementMarkup(instance: unknown, applyChildren?: () => void): ReturnType<typeof createMarkupNodeLike> | undefined;
|
|
32
38
|
private ensureRuntimeInstalled;
|
|
33
39
|
}
|
|
@@ -1,79 +1,122 @@
|
|
|
1
|
-
import { createMarkupNodeLike } from
|
|
2
|
-
import { createServerHydrationBindingState, withServerHydrationBindingState } from
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
1
|
+
import { createMarkupNodeLike } from '@ecopages/jsx';
|
|
2
|
+
import { createServerHydrationBindingState, withServerHydrationBindingState } from '@ecopages/jsx/server';
|
|
3
|
+
/**
|
|
4
|
+
* Owns optional Radiant SSR runtime installation for the JSX integration.
|
|
5
|
+
*
|
|
6
|
+
* @remarks
|
|
7
|
+
* Radiant's server bridge and light-DOM shim are loaded lazily because most JSX
|
|
8
|
+
* renders do not need them. Resolved runtime modules are cached on the policy
|
|
9
|
+
* instance so repeated renders on the same renderer reuse one load without
|
|
10
|
+
* process-wide mutable class state. Light-DOM constructor installation remains
|
|
11
|
+
* process-global and idempotent via {@link ensureRadiantLightDomGlobals}; the
|
|
12
|
+
* Radiant installer also repairs incomplete DOM globals left by another runtime.
|
|
13
|
+
*/
|
|
14
|
+
export class EcopagesJsxRadiantSsrPolicy {
|
|
15
|
+
runtimeModules;
|
|
16
|
+
runtimeModulesPromise;
|
|
17
|
+
enabled;
|
|
18
|
+
constructor(enabled) {
|
|
19
|
+
this.enabled = enabled;
|
|
16
20
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Ensures the Radiant SSR runtime is installed before a render needs it.
|
|
23
|
+
*/
|
|
24
|
+
async prepareRuntime() {
|
|
25
|
+
if (!this.enabled) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
await this.ensureRuntimeInstalled();
|
|
25
29
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
30
|
+
/**
|
|
31
|
+
* Runs one render inside Radiant's server runtime when the policy is enabled.
|
|
32
|
+
*/
|
|
33
|
+
async withRuntime(render) {
|
|
34
|
+
if (!this.enabled) {
|
|
35
|
+
return render();
|
|
36
|
+
}
|
|
37
|
+
const runtimeModules = await this.runtimeModulesPromise;
|
|
38
|
+
if (!runtimeModules) {
|
|
39
|
+
return render();
|
|
40
|
+
}
|
|
41
|
+
return runtimeModules.withServerRadiantElementSsrRuntime(render);
|
|
29
42
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
+
/**
|
|
44
|
+
* Converts one Radiant custom-element instance into trusted SSR markup.
|
|
45
|
+
*
|
|
46
|
+
* @remarks
|
|
47
|
+
* The returned node-like wrapper lets the JSX server renderer preserve the
|
|
48
|
+
* generated host HTML without escaping it back into plain text.
|
|
49
|
+
*
|
|
50
|
+
* The render hook owns the host's JSX children, so `applyChildren` runs inside the host's context providers.
|
|
51
|
+
* A consumer passed as a child of a provider host then resolves that provider in the server HTML instead of
|
|
52
|
+
* rendering its fallback state.
|
|
53
|
+
*/
|
|
54
|
+
renderIntrinsicElementMarkup(instance, applyChildren) {
|
|
55
|
+
const runtime = this.runtimeModules;
|
|
56
|
+
if (!runtime?.resolveRadiantElementRenderBridge(instance)) {
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
return createMarkupNodeLike(withServerHydrationBindingState(createServerHydrationBindingState(), () => {
|
|
60
|
+
const service = runtime.createRadiantElementSsrService(instance);
|
|
61
|
+
service.applyLightDom(() => applyChildren?.());
|
|
62
|
+
return service.renderHostToString({ mode: 'hydrate' }, service.getHostAttributes());
|
|
63
|
+
}));
|
|
43
64
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
EcopagesJsxRadiantSsrPolicy.runtimeModules = modules;
|
|
70
|
-
return modules;
|
|
71
|
-
});
|
|
65
|
+
async ensureRuntimeInstalled() {
|
|
66
|
+
if (!this.runtimeModulesPromise) {
|
|
67
|
+
const radiantLightDomShimEntry = import.meta.resolve('@ecopages/radiant/server/light-dom-shim');
|
|
68
|
+
const radiantElementSsrRuntimeModuleUrl = import.meta
|
|
69
|
+
.resolve('@ecopages/radiant/server/radiant-element-ssr');
|
|
70
|
+
this.runtimeModulesPromise = (async () => {
|
|
71
|
+
const lightDomShimModule = await import(/* @vite-ignore */ radiantLightDomShimEntry);
|
|
72
|
+
ensureRadiantLightDomGlobals(lightDomShimModule.ensureLightDomShim);
|
|
73
|
+
const radiantElementSsrRuntimeModule = (await import(
|
|
74
|
+
/* @vite-ignore */ radiantElementSsrRuntimeModuleUrl));
|
|
75
|
+
const modules = {
|
|
76
|
+
createRadiantElementSsrService: radiantElementSsrRuntimeModule.createRadiantElementSsrService,
|
|
77
|
+
ensureLightDomShim: lightDomShimModule.ensureLightDomShim,
|
|
78
|
+
resolveRadiantElementRenderBridge: radiantElementSsrRuntimeModule.resolveRadiantElementRenderBridge,
|
|
79
|
+
withServerRadiantElementSsrRuntime: radiantElementSsrRuntimeModule.withServerRadiantElementSsrRuntime,
|
|
80
|
+
};
|
|
81
|
+
this.runtimeModules = modules;
|
|
82
|
+
return modules;
|
|
83
|
+
})();
|
|
84
|
+
}
|
|
85
|
+
await this.runtimeModulesPromise;
|
|
86
|
+
const lightDomShimModule = this.runtimeModules;
|
|
87
|
+
if (lightDomShimModule) {
|
|
88
|
+
ensureRadiantLightDomGlobals(lightDomShimModule.ensureLightDomShim);
|
|
89
|
+
}
|
|
72
90
|
}
|
|
73
|
-
const lightDomShimModule = await EcopagesJsxRadiantSsrPolicy.runtimeModulesPromise;
|
|
74
|
-
lightDomShimModule.installLightDomShim();
|
|
75
|
-
}
|
|
76
91
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
92
|
+
/**
|
|
93
|
+
* Installs Radiant light-DOM constructors on `globalThis` once.
|
|
94
|
+
*
|
|
95
|
+
* @remarks
|
|
96
|
+
* Custom-element constructors must be process-global; undoing them between tests
|
|
97
|
+
* is unsafe. Callers that clear globals for isolation must rely on a fresh policy
|
|
98
|
+
* instance so {@link EcopagesJsxRadiantSsrPolicy.prepareRuntime} re-runs the
|
|
99
|
+
* completeness check.
|
|
100
|
+
*/
|
|
101
|
+
function ensureRadiantLightDomGlobals(ensureLightDomShim) {
|
|
102
|
+
const window = ensureLightDomShim();
|
|
103
|
+
if (!window) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
Object.assign(globalThis, {
|
|
107
|
+
CSS: window.CSS,
|
|
108
|
+
CustomEvent: window.CustomEvent,
|
|
109
|
+
Document: window.Document,
|
|
110
|
+
Element: window.Element,
|
|
111
|
+
Event: window.Event,
|
|
112
|
+
EventTarget: window.EventTarget,
|
|
113
|
+
HTMLScriptElement: window.HTMLScriptElement,
|
|
114
|
+
HTMLElement: window.HTMLElement,
|
|
115
|
+
Node: window.Node,
|
|
116
|
+
document: window.document,
|
|
117
|
+
customElements: window.customElements,
|
|
118
|
+
requestAnimationFrame: window.requestAnimationFrame,
|
|
119
|
+
cancelAnimationFrame: window.cancelAnimationFrame,
|
|
120
|
+
window,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
@@ -1,47 +1,12 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { IntegrationRenderer, type RenderToResponseContext, type RouteModuleLoadOptions } from '@ecopages/core/route-renderer/integration-renderer';
|
|
3
|
-
import type { ForeignChildRuntime } from '@ecopages/core/route-renderer/component-render-context';
|
|
1
|
+
import { createIntegrationRenderer, type IntegrationRendererHookFactory } from '@ecopages/core/integration';
|
|
4
2
|
import { type JsxRenderable } from '@ecopages/jsx';
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
export type
|
|
8
|
-
/**
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
*/
|
|
14
|
-
export declare class EcopagesJsxRenderer extends IntegrationRenderer<JsxRenderable> {
|
|
3
|
+
import type { EcopagesJsxRendererConfig } from './ecopages-jsx.types.js';
|
|
4
|
+
export type { EcopagesJsxRendererConfig } from './ecopages-jsx.types.js';
|
|
5
|
+
export type EcopagesJsxRenderer = InstanceType<ReturnType<typeof createEcopagesJsxRenderer>>;
|
|
6
|
+
/** Creates the hook-based Ecopages JSX renderer for one plugin configuration. */
|
|
7
|
+
export declare function createEcopagesJsxRenderer(jsxConfig?: EcopagesJsxRendererConfig): ReturnType<typeof createIntegrationRenderer<JsxRenderable>>;
|
|
8
|
+
/** Creates JSX renderer hooks that can also configure a custom renderer subclass. */
|
|
9
|
+
export declare function createEcopagesJsxRendererHookFactory(jsxConfig?: EcopagesJsxRendererConfig): IntegrationRendererHookFactory;
|
|
10
|
+
export declare const EcopagesJsxRenderer: new (options: import("@ecopages/core/integration").IntegrationRendererOptions) => import("@ecopages/core/integration").IntegrationRenderer<JsxRenderable> & {
|
|
15
11
|
name: string;
|
|
16
|
-
|
|
17
|
-
private readonly renderSession;
|
|
18
|
-
private readonly radiantSsrPolicy;
|
|
19
|
-
private normalizeForeignChildProps;
|
|
20
|
-
/**
|
|
21
|
-
* Re-renders queued JSX children inside the owning renderer so nested custom
|
|
22
|
-
* elements and queued foreign subtrees contribute assets to the same frame.
|
|
23
|
-
*/
|
|
24
|
-
private renderQueuedForeignSubtreeChildren;
|
|
25
|
-
/**
|
|
26
|
-
* Resolves queued foreign subtrees after JSX has been stringified.
|
|
27
|
-
*
|
|
28
|
-
* JSX content needs one extra render pass because child foreign subtrees may emit
|
|
29
|
-
* additional browser assets while also replacing placeholder tokens.
|
|
30
|
-
*/
|
|
31
|
-
private resolveOwnedForeignSubtreeHtml;
|
|
32
|
-
protected createForeignChildRuntime(options: {
|
|
33
|
-
renderInput: ComponentRenderInput;
|
|
34
|
-
rendererCache: Map<string, IntegrationRenderer<any>>;
|
|
35
|
-
}): ForeignChildRuntime;
|
|
36
|
-
constructor({ appConfig, assetProcessingService, resolvedIntegrationDependencies, jsxConfig, runtimeOrigin, }: EcopagesJsxRendererOptions);
|
|
37
|
-
/** Returns whether the requested page file should be treated as MDX. */
|
|
38
|
-
isMdxFile(filePath: string): boolean;
|
|
39
|
-
protected importPageFile(file: string, options?: RouteModuleLoadOptions): Promise<EcopagesJsxMdxPageModule>;
|
|
40
|
-
render(options: IntegrationRendererRenderOptions<JsxRenderable>): Promise<RouteRendererBody>;
|
|
41
|
-
renderComponent(input: ComponentRenderInput): Promise<ComponentRenderResult>;
|
|
42
|
-
renderToResponse<P = any>(view: EcoComponent<P>, props: P, ctx: RenderToResponseContext): Promise<Response>;
|
|
43
|
-
private renderJsx;
|
|
44
|
-
private withCustomElementRenderHook;
|
|
45
|
-
private withPreparedRadiantRuntime;
|
|
46
|
-
private createIntrinsicCustomElementRenderHook;
|
|
47
|
-
}
|
|
12
|
+
};
|