@ecopages/ecopages-jsx 0.2.0-alpha.21 → 0.2.0-alpha.23
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/CHANGELOG.md
CHANGED
|
@@ -8,8 +8,10 @@
|
|
|
8
8
|
|
|
9
9
|
### Bug Fixes
|
|
10
10
|
|
|
11
|
+
- Patched the Ecopages JSX browser runtime bundle so nested SVG templates restore canonical camel-cased SVG tag names during client rendering.
|
|
11
12
|
- Aligned Ecopages JSX peer dependency ranges with the current `@ecopages/jsx` and `@ecopages/radiant` alpha releases.
|
|
12
13
|
- Aligned Radiant SSR and hydration wiring with the public `@ecopages/radiant/server/render-component` and `@ecopages/radiant/client/hydrator` entrypoints so JSX apps install an explicit client hydrator bootstrap instead of relying on implicit side effects.
|
|
14
|
+
- Updated the Ecopages JSX Radiant browser runtime for the `RadiantElement` and `RadiantController` API surface and switched the explicit hydrator bootstrap to `@ecopages/radiant/client/install-hydrator`.
|
|
13
15
|
- Fixed Radiant SSR page inspection to install the light-DOM shim before JSX page modules are imported outside the normal render pass.
|
|
14
16
|
- Restored direct `EcopagesJsxPlugin` construction so the exported class still accepts the public plugin options shape.
|
|
15
17
|
- Fixed intrinsic custom-element asset discovery so Ecopages JSX registers scripts declared with decorator and function-call `customElement(...)` syntax.
|
package/README.md
CHANGED
|
@@ -48,9 +48,9 @@ Radiant support is enabled by default. When `radiant: true`, the plugin keeps th
|
|
|
48
48
|
|
|
49
49
|
- Ecopages JSX owns page-level JSX SSR and container hydration.
|
|
50
50
|
- Radiant SSR is activated on the server through `@ecopages/radiant/server/render-component`.
|
|
51
|
-
- Radiant host hydration is activated on the client through an explicit head bootstrap that
|
|
51
|
+
- Radiant host hydration is activated on the client through an explicit head bootstrap that imports `@ecopages/radiant/client/install-hydrator` before intrinsic custom-element modules load.
|
|
52
52
|
|
|
53
|
-
That means server-rendered `
|
|
53
|
+
That means server-rendered `RadiantElement` hosts hydrate in place only when both the SSR markers and the explicit client hydrator are present. Without the client hydrator, Radiant intentionally falls back to a fresh client render on first connect.
|
|
54
54
|
|
|
55
55
|
```ts
|
|
56
56
|
ecopagesJsxPlugin({
|
|
@@ -60,7 +60,7 @@ ecopagesJsxPlugin({
|
|
|
60
60
|
|
|
61
61
|
Set `radiant: false` when your JSX pages do not need Radiant SSR or the Radiant browser runtime on a given app.
|
|
62
62
|
|
|
63
|
-
The plugin bootstrap is intentionally explicit rather than
|
|
63
|
+
The plugin bootstrap is intentionally explicit rather than depending on custom-element modules to install the Radiant hydrator opportunistically.
|
|
64
64
|
|
|
65
65
|
## MDX Support
|
|
66
66
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ecopages/ecopages-jsx",
|
|
3
|
-
"version": "0.2.0-alpha.
|
|
3
|
+
"version": "0.2.0-alpha.23",
|
|
4
4
|
"description": "JSX integration plugin for Ecopages",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ecopages",
|
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
"vfile": "^6.0.3"
|
|
22
22
|
},
|
|
23
23
|
"peerDependencies": {
|
|
24
|
-
"@ecopages/core": "0.2.0-alpha.
|
|
25
|
-
"@ecopages/jsx": "
|
|
26
|
-
"@ecopages/radiant": "
|
|
24
|
+
"@ecopages/core": "0.2.0-alpha.23",
|
|
25
|
+
"@ecopages/jsx": "0.3.0-alpha.5",
|
|
26
|
+
"@ecopages/radiant": "0.3.0-alpha.5"
|
|
27
27
|
}
|
|
28
28
|
}
|
|
@@ -38,8 +38,9 @@ export type EcopagesJsxPluginOptions = Omit<IntegrationPluginConfig, 'name' | 'e
|
|
|
38
38
|
* When enabled, Ecopages JSX:
|
|
39
39
|
* - imports `@ecopages/radiant/server/render-component` before Radiant SSR
|
|
40
40
|
* - exposes browser-safe Radiant bare specifiers through the runtime import map
|
|
41
|
-
* - injects an explicit client bootstrap that
|
|
42
|
-
* before intrinsic
|
|
41
|
+
* - injects an explicit client bootstrap that imports
|
|
42
|
+
* `@ecopages/radiant/client/install-hydrator` before intrinsic
|
|
43
|
+
* custom-element modules load
|
|
43
44
|
*
|
|
44
45
|
* Set to `false` when pages do not use Radiant web components.
|
|
45
46
|
* @default true
|
|
@@ -20,6 +20,7 @@ export declare class JsxRuntimeBundleService {
|
|
|
20
20
|
private cachedSpecifierMap;
|
|
21
21
|
private cachedJsxEntryModulePath;
|
|
22
22
|
private cachedRadiantEntryModulePath;
|
|
23
|
+
private cachedRadiantInstallHydratorEntryModulePath;
|
|
23
24
|
constructor(config: JsxRuntimeBundleServiceConfig);
|
|
24
25
|
setRootDir(rootDir: string | undefined): void;
|
|
25
26
|
/**
|
|
@@ -54,4 +55,5 @@ export declare class JsxRuntimeBundleService {
|
|
|
54
55
|
private getRadiantBrowserRuntimeModules;
|
|
55
56
|
private resolvePackageExportModulePath;
|
|
56
57
|
private getOrCreateRadiantEntryModulePath;
|
|
58
|
+
private getOrCreateRadiantInstallHydratorEntryModulePath;
|
|
57
59
|
}
|
|
@@ -9,9 +9,21 @@ import {
|
|
|
9
9
|
} from "@ecopages/core/services/asset-processing-service";
|
|
10
10
|
const VENDOR_FILE_NAMES = {
|
|
11
11
|
jsx: "ecopages-jsx-esm.js",
|
|
12
|
-
radiant: "ecopages-radiant-esm.js"
|
|
12
|
+
radiant: "ecopages-radiant-esm.js",
|
|
13
|
+
radiantInstallHydrator: "ecopages-radiant-install-hydrator-esm.js"
|
|
13
14
|
};
|
|
14
15
|
const RADIANT_HYDRATOR_BOOTSTRAP_ATTRIBUTE = "data-ecopages-jsx-radiant-hydrator";
|
|
16
|
+
const JSX_RUNTIME_NAMESPACE_REPAIR_SNIPPET = "function rG(W,G,J){let j=G instanceof Element?G:G?.parentElement,U=j?.namespaceURI??K9,$=j?.localName,X=W.firstElementChild;if(!X)return;let F=J??X.localName,Z=O9(U,$,F);if(X.namespaceURI===Z&&X.localName===F)return;W.replaceChild(tG(X,Z,F),X)}function tG(W,G,J){let j=document.createElementNS(G,J);for(let U of Array.from(W.attributes)){if(U.namespaceURI){j.setAttributeNS(U.namespaceURI,U.name,U.value);continue}n(j,U.name,U.value)}return j.append(...W.childNodes),j}";
|
|
17
|
+
const JSX_RUNTIME_NAMESPACE_REPAIR_PATCH = [
|
|
18
|
+
"const eopHtmlNamespace='http://www.w3.org/1999/xhtml',eopSvgNamespace='http://www.w3.org/2000/svg',eopCanonicalSvgLocalNames={altglyph:'altGlyph',altglyphdef:'altGlyphDef',altglyphitem:'altGlyphItem',animatemotion:'animateMotion',animatetransform:'animateTransform',clippath:'clipPath',feblend:'feBlend',fecolormatrix:'feColorMatrix',fecomponenttransfer:'feComponentTransfer',fecomposite:'feComposite',feconvolvematrix:'feConvolveMatrix',fediffuselighting:'feDiffuseLighting',fedisplacementmap:'feDisplacementMap',fedistantlight:'feDistantLight',fedropshadow:'feDropShadow',feflood:'feFlood',fefunca:'feFuncA',fefuncb:'feFuncB',fefuncg:'feFuncG',fefuncr:'feFuncR',fegaussianblur:'feGaussianBlur',feimage:'feImage',femerge:'feMerge',femergenode:'feMergeNode',femorphology:'feMorphology',feoffset:'feOffset',fepointlight:'fePointLight',fespecularlighting:'feSpecularLighting',fespotlight:'feSpotLight',fetile:'feTile',feturbulence:'feTurbulence',foreignobject:'foreignObject',glyphref:'glyphRef',lineargradient:'linearGradient',radialgradient:'radialGradient',textpath:'textPath'};",
|
|
19
|
+
"function eopGetCanonicalSvgLocalName(W){return eopCanonicalSvgLocalNames[W]??W}",
|
|
20
|
+
"function eopIsSvgNamespace(W){return W===eopSvgNamespace}",
|
|
21
|
+
"function rG(W,G,J){let j=G instanceof Element?G:G?.parentElement,U=j?.namespaceURI??K9,$=j?.localName;eopRepairNamespaceFragment(W,U??eopHtmlNamespace,$,J)}",
|
|
22
|
+
"function eopRepairNamespaceFragment(W,G,J,j){let U=W.firstElementChild;if(!U)return;let $=j??U.localName,X=O9(G,J,$),F=eopIsSvgNamespace(X)?eopGetCanonicalSvgLocalName($):$;eopRepairNamespaceElement(W,U,X,F)}",
|
|
23
|
+
"function eopRepairNamespaceElement(W,G,J,j){let U=G;if(G.namespaceURI!==J||G.localName!==j)U=tG(G,J,j),W.replaceChild(U,G);eopRepairNamespaceChildren(U,J,j)}",
|
|
24
|
+
"function eopRepairNamespaceChildren(W,G,J){for(let j of Array.from(W.children)){let U=O9(G,J,j.localName),$=eopIsSvgNamespace(U)?eopGetCanonicalSvgLocalName(j.localName):j.localName,X=j;if(j.namespaceURI!==U||j.localName!==$)X=tG(j,U,$),W.replaceChild(X,j);eopRepairNamespaceChildren(X,U,$)}}",
|
|
25
|
+
"function tG(W,G,J){let j=document.createElementNS(G,eopIsSvgNamespace(G)?eopGetCanonicalSvgLocalName(J):J);for(let U of Array.from(W.attributes)){if(U.namespaceURI){j.setAttributeNS(U.namespaceURI,U.name,U.value);continue}n(j,U.name,U.value)}return j.append(...W.childNodes),j}"
|
|
26
|
+
].join("");
|
|
15
27
|
function getNamedExportNamesFromModuleSource(source) {
|
|
16
28
|
const exportNames = /* @__PURE__ */ new Set();
|
|
17
29
|
for (const match of source.matchAll(/export\s*\{([^}]+)\}/g)) {
|
|
@@ -39,13 +51,33 @@ function isBrowserRuntimeRadiantSpecifier(exportKey) {
|
|
|
39
51
|
if (exportKey === "." || exportKey.startsWith("./context/")) {
|
|
40
52
|
return true;
|
|
41
53
|
}
|
|
54
|
+
if (exportKey === "./controller-registry") {
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
42
57
|
if (exportKey === "./client/hydrator") {
|
|
43
58
|
return true;
|
|
44
59
|
}
|
|
60
|
+
if (exportKey === "./client/install-hydrator") {
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
45
63
|
if (exportKey.startsWith("./decorators/") || exportKey.startsWith("./helpers/")) {
|
|
46
64
|
return true;
|
|
47
65
|
}
|
|
48
|
-
return exportKey === "./core/radiant-
|
|
66
|
+
return exportKey === "./core/radiant-controller" || exportKey === "./core/radiant-element";
|
|
67
|
+
}
|
|
68
|
+
function replaceExactOnce(source, search, replacement, label) {
|
|
69
|
+
if (!source.includes(search)) {
|
|
70
|
+
throw new Error(`Could not find ${label} in @ecopages/jsx browser runtime source`);
|
|
71
|
+
}
|
|
72
|
+
return source.replace(search, replacement);
|
|
73
|
+
}
|
|
74
|
+
function createPatchedJsxBrowserRuntimeSource(source) {
|
|
75
|
+
return replaceExactOnce(
|
|
76
|
+
source,
|
|
77
|
+
JSX_RUNTIME_NAMESPACE_REPAIR_SNIPPET,
|
|
78
|
+
JSX_RUNTIME_NAMESPACE_REPAIR_PATCH,
|
|
79
|
+
"SVG namespace repair snippet"
|
|
80
|
+
);
|
|
49
81
|
}
|
|
50
82
|
function findPackageManifestPath(packageName) {
|
|
51
83
|
let currentDir = path.dirname(new URL(import.meta.url).pathname);
|
|
@@ -67,6 +99,7 @@ class JsxRuntimeBundleService {
|
|
|
67
99
|
cachedSpecifierMap;
|
|
68
100
|
cachedJsxEntryModulePath;
|
|
69
101
|
cachedRadiantEntryModulePath;
|
|
102
|
+
cachedRadiantInstallHydratorEntryModulePath;
|
|
70
103
|
constructor(config) {
|
|
71
104
|
this.config = config;
|
|
72
105
|
}
|
|
@@ -124,11 +157,17 @@ class JsxRuntimeBundleService {
|
|
|
124
157
|
);
|
|
125
158
|
if (this.config.radiant) {
|
|
126
159
|
const radiantEntryModulePath = await this.getOrCreateRadiantEntryModulePath();
|
|
160
|
+
const radiantInstallHydratorEntryModulePath = await this.getOrCreateRadiantInstallHydratorEntryModulePath();
|
|
127
161
|
deps.push(
|
|
128
162
|
createBrowserRuntimeScriptAsset({
|
|
129
163
|
importPath: radiantEntryModulePath,
|
|
130
164
|
name: "ecopages-radiant-esm",
|
|
131
165
|
fileName: VENDOR_FILE_NAMES.radiant
|
|
166
|
+
}),
|
|
167
|
+
createBrowserRuntimeScriptAsset({
|
|
168
|
+
importPath: radiantInstallHydratorEntryModulePath,
|
|
169
|
+
name: "ecopages-radiant-install-hydrator-esm",
|
|
170
|
+
fileName: VENDOR_FILE_NAMES.radiantInstallHydrator
|
|
132
171
|
})
|
|
133
172
|
);
|
|
134
173
|
}
|
|
@@ -146,10 +185,7 @@ class JsxRuntimeBundleService {
|
|
|
146
185
|
});
|
|
147
186
|
}
|
|
148
187
|
createRadiantHydratorBootstrapSource() {
|
|
149
|
-
return
|
|
150
|
-
"import { installRadiantHydrator } from '@ecopages/radiant/client/hydrator';",
|
|
151
|
-
"installRadiantHydrator();"
|
|
152
|
-
].join("\n");
|
|
188
|
+
return "import '@ecopages/radiant/client/install-hydrator';";
|
|
153
189
|
}
|
|
154
190
|
getArtifactsDir() {
|
|
155
191
|
const rootDir = this.config.rootDir ?? process.cwd();
|
|
@@ -172,6 +208,9 @@ class JsxRuntimeBundleService {
|
|
|
172
208
|
};
|
|
173
209
|
if (this.config.radiant) {
|
|
174
210
|
const radiantVendorUrl = buildBrowserRuntimeAssetUrl(VENDOR_FILE_NAMES.radiant);
|
|
211
|
+
const radiantInstallHydratorVendorUrl = buildBrowserRuntimeAssetUrl(
|
|
212
|
+
VENDOR_FILE_NAMES.radiantInstallHydrator
|
|
213
|
+
);
|
|
175
214
|
const radiantPkg = JSON.parse(
|
|
176
215
|
readFileSync(findPackageManifestPath("@ecopages/radiant"), "utf8")
|
|
177
216
|
);
|
|
@@ -180,7 +219,7 @@ class JsxRuntimeBundleService {
|
|
|
180
219
|
continue;
|
|
181
220
|
}
|
|
182
221
|
const specifier = key === "." ? "@ecopages/radiant" : `@ecopages/radiant${key.slice(1)}`;
|
|
183
|
-
specifierMap[specifier] = radiantVendorUrl;
|
|
222
|
+
specifierMap[specifier] = key === "./client/install-hydrator" ? radiantInstallHydratorVendorUrl : radiantVendorUrl;
|
|
184
223
|
}
|
|
185
224
|
}
|
|
186
225
|
this.cachedSpecifierMap = specifierMap;
|
|
@@ -200,9 +239,9 @@ class JsxRuntimeBundleService {
|
|
|
200
239
|
".",
|
|
201
240
|
jsxPkg.exports?.["."]
|
|
202
241
|
);
|
|
203
|
-
const
|
|
242
|
+
const patchedRuntimeSource = createPatchedJsxBrowserRuntimeSource(readFileSync(jsxModulePath, "utf8"));
|
|
204
243
|
mkdirSync(artifactsDir, { recursive: true });
|
|
205
|
-
writeFileSync(filePath,
|
|
244
|
+
writeFileSync(filePath, patchedRuntimeSource, "utf8");
|
|
206
245
|
this.cachedJsxEntryModulePath = filePath;
|
|
207
246
|
return filePath;
|
|
208
247
|
}
|
|
@@ -255,6 +294,31 @@ class JsxRuntimeBundleService {
|
|
|
255
294
|
this.cachedRadiantEntryModulePath = filePath;
|
|
256
295
|
return filePath;
|
|
257
296
|
}
|
|
297
|
+
async getOrCreateRadiantInstallHydratorEntryModulePath() {
|
|
298
|
+
if (this.cachedRadiantInstallHydratorEntryModulePath) {
|
|
299
|
+
return this.cachedRadiantInstallHydratorEntryModulePath;
|
|
300
|
+
}
|
|
301
|
+
const artifactsDir = this.getArtifactsDir();
|
|
302
|
+
const filePath = path.join(artifactsDir, "ecopages-radiant-install-hydrator-esm-entry.mjs");
|
|
303
|
+
const manifestPath = findPackageManifestPath("@ecopages/radiant");
|
|
304
|
+
const packageDir = path.dirname(realpathSync(manifestPath));
|
|
305
|
+
const radiantPkg = JSON.parse(readFileSync(manifestPath, "utf8"));
|
|
306
|
+
const modulePath = this.resolvePackageExportModulePath(
|
|
307
|
+
packageDir,
|
|
308
|
+
"./client/install-hydrator",
|
|
309
|
+
radiantPkg.exports?.["./client/install-hydrator"]
|
|
310
|
+
);
|
|
311
|
+
mkdirSync(artifactsDir, { recursive: true });
|
|
312
|
+
writeFileSync(
|
|
313
|
+
filePath,
|
|
314
|
+
`import '${this.getEntryImportPath(artifactsDir, modulePath)}';
|
|
315
|
+
export {};
|
|
316
|
+
`,
|
|
317
|
+
"utf8"
|
|
318
|
+
);
|
|
319
|
+
this.cachedRadiantInstallHydratorEntryModulePath = filePath;
|
|
320
|
+
return filePath;
|
|
321
|
+
}
|
|
258
322
|
}
|
|
259
323
|
export {
|
|
260
324
|
JsxRuntimeBundleService,
|