@ecopages/react 0.2.0-alpha.8 → 0.2.0-beta.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 +30 -13
- package/package.json +23 -12
- package/src/eco-embed.d.ts +11 -0
- package/src/eco-embed.js +11 -0
- package/src/react-hmr-strategy.d.ts +102 -18
- package/src/react-hmr-strategy.js +427 -50
- package/src/react-renderer.d.ts +100 -92
- package/src/react-renderer.js +356 -340
- package/src/react.constants.d.ts +1 -0
- package/src/react.constants.js +4 -0
- package/src/react.plugin.d.ts +25 -107
- package/src/react.plugin.js +109 -61
- package/src/react.types.d.ts +88 -0
- package/src/react.types.js +0 -0
- package/src/router-adapter.d.ts +7 -14
- package/src/runtime/use-sync-external-store-with-selector.d.ts +3 -0
- package/src/runtime/use-sync-external-store-with-selector.js +56 -0
- package/src/services/pages-index.d.ts +64 -0
- package/src/services/pages-index.js +73 -0
- package/src/services/react-bundle.service.d.ts +24 -9
- package/src/services/react-bundle.service.js +35 -24
- package/src/services/react-hmr-page-metadata-cache.d.ts +10 -1
- package/src/services/react-hmr-page-metadata-cache.js +18 -2
- package/src/services/react-hydration-asset.service.d.ts +28 -19
- package/src/services/react-hydration-asset.service.js +83 -64
- package/src/services/react-mdx-config-dependency.service.d.ts +36 -0
- package/src/services/react-mdx-config-dependency.service.js +122 -0
- package/src/services/react-page-module.service.d.ts +8 -3
- package/src/services/react-page-module.service.js +33 -26
- package/src/services/react-page-payload.service.d.ts +46 -0
- package/src/services/react-page-payload.service.js +67 -0
- package/src/services/react-runtime-bundle.service.d.ts +9 -2
- package/src/services/react-runtime-bundle.service.js +77 -16
- package/src/utils/client-graph-boundary-cache.d.ts +108 -0
- package/src/utils/client-graph-boundary-cache.js +116 -0
- package/src/utils/client-graph-boundary-plugin.d.ts +13 -5
- package/src/utils/client-graph-boundary-plugin.js +63 -5
- package/src/utils/component-config-traversal.d.ts +36 -0
- package/src/utils/component-config-traversal.js +54 -0
- package/src/utils/declared-modules.d.ts +1 -1
- package/src/utils/declared-modules.js +7 -16
- package/src/utils/dynamic.test.browser.d.ts +1 -0
- package/src/utils/dynamic.test.browser.js +33 -0
- package/src/utils/hydration-scripts.d.ts +9 -5
- package/src/utils/hydration-scripts.js +119 -34
- package/src/utils/hydration-scripts.test.browser.d.ts +1 -0
- package/src/utils/hydration-scripts.test.browser.js +198 -0
- package/src/utils/react-dom-runtime-interop-plugin.d.ts +1 -1
- package/src/utils/react-dom-runtime-interop-plugin.js +9 -0
- package/src/utils/react-mdx-loader-plugin.d.ts +1 -1
- package/src/utils/{react-runtime-specifier-map.d.ts → react-runtime-alias-map.d.ts} +3 -1
- package/src/utils/react-runtime-alias-map.js +90 -0
- package/CHANGELOG.md +0 -27
- package/src/react-hmr-strategy.ts +0 -386
- package/src/react-renderer.ts +0 -803
- package/src/react.plugin.ts +0 -276
- package/src/router-adapter.ts +0 -95
- package/src/services/react-bundle.service.ts +0 -108
- package/src/services/react-hmr-page-metadata-cache.ts +0 -24
- package/src/services/react-hydration-asset.service.ts +0 -263
- package/src/services/react-page-module.service.ts +0 -224
- package/src/services/react-runtime-bundle.service.ts +0 -172
- package/src/utils/client-graph-boundary-plugin.ts +0 -831
- package/src/utils/client-only.ts +0 -27
- package/src/utils/declared-modules.ts +0 -99
- package/src/utils/dynamic.ts +0 -27
- package/src/utils/hmr-scripts.ts +0 -47
- package/src/utils/html-boundary.ts +0 -66
- package/src/utils/hydration-scripts.ts +0 -459
- package/src/utils/reachability-analyzer.ts +0 -593
- package/src/utils/react-dom-runtime-interop-plugin.ts +0 -33
- package/src/utils/react-mdx-loader-plugin.ts +0 -63
- package/src/utils/react-runtime-specifier-map.js +0 -37
- package/src/utils/react-runtime-specifier-map.ts +0 -45
- package/src/utils/use-sync-external-store-shim-plugin.d.ts +0 -5
- package/src/utils/use-sync-external-store-shim-plugin.js +0 -41
- package/src/utils/use-sync-external-store-shim-plugin.ts +0 -45
|
@@ -31,19 +31,44 @@ function getProdPageRootCleanupScript() {
|
|
|
31
31
|
return 'window.__ECO_PAGES__=window.__ECO_PAGES__||{};window.__ECO_PAGES__.react=window.__ECO_PAGES__.react||{};window.__ECO_PAGES__.react.cleanupPageRoot=()=>{const a=window.__ECO_PAGES__.react?.pageRoot||root;if(!a){window.__ECO_PAGES__.react.pageRoot=null;window.__ECO_PAGES__?.navigation?.releaseOwnership?.("react-router");delete window.__ECO_PAGES__.page;return}window.__ECO_PAGES__.react.pageRoot=null;window.__ECO_PAGES__?.navigation?.releaseOwnership?.("react-router");delete window.__ECO_PAGES__.page;root=null;a.unmount()};';
|
|
32
32
|
}
|
|
33
33
|
function getDevRouterBootstrapRegistrationScript() {
|
|
34
|
-
return `window.__ECO_PAGES__?.navigation?.
|
|
34
|
+
return `const currentOwnerState = window.__ECO_PAGES__?.navigation?.getOwnerState?.();
|
|
35
|
+
if (!(currentOwnerState?.owner === "react-router" && currentOwnerState.canHandleSpaNavigation)) {
|
|
36
|
+
window.__ECO_PAGES__?.navigation?.register({
|
|
35
37
|
owner: "react-router",
|
|
36
38
|
cleanupBeforeHandoff: async () => {
|
|
37
39
|
window.__ECO_PAGES__?.react?.cleanupPageRoot?.();
|
|
38
40
|
}
|
|
39
41
|
});
|
|
40
|
-
window.__ECO_PAGES__?.navigation?.claimOwnership?.("react-router")
|
|
42
|
+
window.__ECO_PAGES__?.navigation?.claimOwnership?.("react-router");
|
|
43
|
+
}`;
|
|
41
44
|
}
|
|
42
45
|
function getProdRouterBootstrapRegistrationScript() {
|
|
43
|
-
return 'window.__ECO_PAGES__?.navigation?.register({owner:"react-router",cleanupBeforeHandoff:async()=>{window.__ECO_PAGES__?.react?.cleanupPageRoot?.()}});window.__ECO_PAGES__?.navigation?.claimOwnership?.("react-router")
|
|
46
|
+
return 'const o=window.__ECO_PAGES__?.navigation?.getOwnerState?.();if(!(o?.owner==="react-router"&&o.canHandleSpaNavigation)){window.__ECO_PAGES__?.navigation?.register({owner:"react-router",cleanupBeforeHandoff:async()=>{window.__ECO_PAGES__?.react?.cleanupPageRoot?.()}});window.__ECO_PAGES__?.navigation?.claimOwnership?.("react-router")}';
|
|
47
|
+
}
|
|
48
|
+
function getDevReuseExistingRouterRootScript() {
|
|
49
|
+
return `const shouldReuseExistingRouterRoot = () => {
|
|
50
|
+
const ownerState = window.__ECO_PAGES__?.navigation?.getOwnerState?.();
|
|
51
|
+
return Boolean(
|
|
52
|
+
window.__ECO_PAGES__.react?.pageRoot &&
|
|
53
|
+
ownerState?.owner === "react-router" &&
|
|
54
|
+
ownerState.canHandleSpaNavigation
|
|
55
|
+
);
|
|
56
|
+
};`;
|
|
57
|
+
}
|
|
58
|
+
function getProdReuseExistingRouterRootScript() {
|
|
59
|
+
return 'const sr=()=>{const o=window.__ECO_PAGES__?.navigation?.getOwnerState?.();return!!(window.__ECO_PAGES__.react?.pageRoot&&o?.owner==="react-router"&&o.canHandleSpaNavigation)};';
|
|
60
|
+
}
|
|
61
|
+
function getDevRerunRegistrationScript(scriptId) {
|
|
62
|
+
return `window.__ECO_PAGES__ = window.__ECO_PAGES__ || {};
|
|
63
|
+
window.__ECO_PAGES__.rerunScripts = window.__ECO_PAGES__.rerunScripts || {};
|
|
64
|
+
window.__ECO_PAGES__.rerunScripts[${JSON.stringify(scriptId)}] = mount;`;
|
|
65
|
+
}
|
|
66
|
+
function getProdRerunRegistrationScript(scriptId) {
|
|
67
|
+
return `window.__ECO_PAGES__=window.__ECO_PAGES__||{};window.__ECO_PAGES__.rerunScripts=window.__ECO_PAGES__.rerunScripts||{};window.__ECO_PAGES__.rerunScripts[${JSON.stringify(scriptId)}]=m;`;
|
|
44
68
|
}
|
|
45
69
|
function createDevScriptWithRouter(options) {
|
|
46
|
-
const { importPath, isMdx, router, reactImportPath, reactDomClientImportPath, routerImportPath } = options;
|
|
70
|
+
const { importPath, isMdx, router, reactImportPath, reactDomClientImportPath, routerImportPath, scriptId } = options;
|
|
71
|
+
const pageModuleUrlExpression = options.pageModuleUrlExpression ?? "import.meta.url";
|
|
47
72
|
const { components, getRouterProps } = router;
|
|
48
73
|
if (!routerImportPath) {
|
|
49
74
|
throw new Error("routerImportPath is required when router adapter is configured");
|
|
@@ -53,6 +78,12 @@ import { hydrateRoot } from "${reactDomClientImportPath}";
|
|
|
53
78
|
import { createElement } from "${reactImportPath}";
|
|
54
79
|
import { ${components.router}, ${components.pageContent} } from "${routerImportPath}";
|
|
55
80
|
${getImportStatement(importPath, isMdx)}
|
|
81
|
+
const pageModuleUrl = ${pageModuleUrlExpression};
|
|
82
|
+
export default Page;
|
|
83
|
+
export const config = Page.config;
|
|
84
|
+
const isActivePageEntry = Boolean(document.querySelector('script[data-eco-script-id="${scriptId}"]'));
|
|
85
|
+
|
|
86
|
+
if (isActivePageEntry) {
|
|
56
87
|
|
|
57
88
|
window.__ECO_PAGES__ = window.__ECO_PAGES__ || {};
|
|
58
89
|
window.__ECO_PAGES__.hmrHandlers = window.__ECO_PAGES__.hmrHandlers || {};
|
|
@@ -61,6 +92,7 @@ window.__ECO_PAGES__.react.pageRoot = window.__ECO_PAGES__.react.pageRoot || nul
|
|
|
61
92
|
let root = window.__ECO_PAGES__.react.pageRoot;
|
|
62
93
|
${getDevPageRootCleanupScript()}
|
|
63
94
|
${getDevRouterBootstrapRegistrationScript()}
|
|
95
|
+
${getDevReuseExistingRouterRootScript()}
|
|
64
96
|
|
|
65
97
|
const getPageData = () => {
|
|
66
98
|
const el = document.getElementById("__ECO_PAGE_DATA__");
|
|
@@ -73,7 +105,7 @@ const getPageData = () => {
|
|
|
73
105
|
const props = getPageData();
|
|
74
106
|
|
|
75
107
|
window.__ECO_PAGES__.page = {
|
|
76
|
-
module:
|
|
108
|
+
module: pageModuleUrl,
|
|
77
109
|
props
|
|
78
110
|
};
|
|
79
111
|
|
|
@@ -83,25 +115,49 @@ const createTree = (Component, props) => {
|
|
|
83
115
|
};
|
|
84
116
|
|
|
85
117
|
const mount = () => {
|
|
118
|
+
const props = getPageData();
|
|
119
|
+
window.__ECO_PAGES__.page = {
|
|
120
|
+
module: pageModuleUrl,
|
|
121
|
+
props
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
if (shouldReuseExistingRouterRoot()) {
|
|
125
|
+
root = window.__ECO_PAGES__.react.pageRoot;
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
86
129
|
if (window.__ECO_PAGES__.react?.pageRoot) {
|
|
87
130
|
root = window.__ECO_PAGES__.react.pageRoot;
|
|
88
|
-
|
|
89
|
-
} else {
|
|
90
|
-
root = hydrateRoot(document.body, createTree(Page, props), {
|
|
91
|
-
onRecoverableError: (err) => console.warn("[ecopages] Hydration error:", err)
|
|
92
|
-
});
|
|
93
|
-
window.__ECO_PAGES__.react.pageRoot = root;
|
|
131
|
+
return;
|
|
94
132
|
}
|
|
133
|
+
|
|
134
|
+
root = hydrateRoot(document.body, createTree(Page, props), {
|
|
135
|
+
onRecoverableError: (err) => console.warn("[ecopages] Hydration error:", err)
|
|
136
|
+
});
|
|
137
|
+
window.__ECO_PAGES__.react.pageRoot = root;
|
|
95
138
|
window.__ECO_PAGES__.hmrHandlers["${importPath}"] = async (newUrl) => {
|
|
96
|
-
if (window.__ECO_PAGES__?.navigation?.getOwnerState().owner === "react-router") {
|
|
97
|
-
await window.__ECO_PAGES__?.navigation?.reloadCurrentPage?.({ clearCache: false, source: "react-router" });
|
|
98
|
-
console.log("[ecopages] ${getComponentType(isMdx)} component updated via router");
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
139
|
try {
|
|
102
140
|
const newModule = await import(newUrl);
|
|
141
|
+
const nextProps = getPageData();
|
|
103
142
|
${getHmrImportStatement(isMdx)}
|
|
104
|
-
|
|
143
|
+
const currentPageLayout = Page.config?.layout;
|
|
144
|
+
const nextPageLayout = NewPage.config?.layout;
|
|
145
|
+
|
|
146
|
+
if (window.__ECO_PAGES__?.navigation?.getOwnerState().owner === "react-router") {
|
|
147
|
+
await window.__ECO_PAGES__?.navigation?.reloadCurrentPage?.({
|
|
148
|
+
clearCache: currentPageLayout !== nextPageLayout,
|
|
149
|
+
moduleUrl: "${importPath}",
|
|
150
|
+
source: "react-router"
|
|
151
|
+
});
|
|
152
|
+
console.log("[ecopages] ${getComponentType(isMdx)} component updated via router");
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
window.__ECO_PAGES__.page = {
|
|
157
|
+
module: pageModuleUrl,
|
|
158
|
+
props: nextProps
|
|
159
|
+
};
|
|
160
|
+
root.render(createTree(NewPage, nextProps));
|
|
105
161
|
console.log("[ecopages] ${getComponentType(isMdx)} component updated");
|
|
106
162
|
} catch (e) {
|
|
107
163
|
console.error("[ecopages] Failed to hot-reload ${getComponentType(isMdx)} component:", e);
|
|
@@ -109,19 +165,29 @@ const mount = () => {
|
|
|
109
165
|
};
|
|
110
166
|
};
|
|
111
167
|
|
|
168
|
+
${getDevRerunRegistrationScript(scriptId)}
|
|
169
|
+
|
|
112
170
|
if (document.readyState === "loading") {
|
|
113
171
|
document.addEventListener("DOMContentLoaded", mount);
|
|
114
172
|
} else {
|
|
115
173
|
mount();
|
|
116
174
|
}
|
|
175
|
+
}
|
|
117
176
|
`.trim();
|
|
118
177
|
}
|
|
119
178
|
function createDevScriptWithoutRouter(options) {
|
|
120
|
-
const { importPath, isMdx, reactImportPath, reactDomClientImportPath } = options;
|
|
179
|
+
const { importPath, isMdx, reactImportPath, reactDomClientImportPath, scriptId } = options;
|
|
180
|
+
const pageModuleUrlExpression = options.pageModuleUrlExpression ?? "import.meta.url";
|
|
121
181
|
return `
|
|
122
182
|
import { hydrateRoot } from "${reactDomClientImportPath}";
|
|
123
183
|
import { createElement } from "${reactImportPath}";
|
|
124
184
|
${getImportStatement(importPath, isMdx)}
|
|
185
|
+
const pageModuleUrl = ${pageModuleUrlExpression};
|
|
186
|
+
export default Page;
|
|
187
|
+
export const config = Page.config;
|
|
188
|
+
const isActivePageEntry = Boolean(document.querySelector('script[data-eco-script-id="${scriptId}"]'));
|
|
189
|
+
|
|
190
|
+
if (isActivePageEntry) {
|
|
125
191
|
|
|
126
192
|
window.__ECO_PAGES__ = window.__ECO_PAGES__ || {};
|
|
127
193
|
window.__ECO_PAGES__.hmrHandlers = window.__ECO_PAGES__.hmrHandlers || {};
|
|
@@ -141,7 +207,7 @@ const getPageData = () => {
|
|
|
141
207
|
const props = getPageData();
|
|
142
208
|
|
|
143
209
|
window.__ECO_PAGES__.page = {
|
|
144
|
-
module:
|
|
210
|
+
module: pageModuleUrl,
|
|
145
211
|
props
|
|
146
212
|
};
|
|
147
213
|
|
|
@@ -153,6 +219,12 @@ const createTree = (Component, props) => {
|
|
|
153
219
|
};
|
|
154
220
|
|
|
155
221
|
const mount = () => {
|
|
222
|
+
const props = getPageData();
|
|
223
|
+
window.__ECO_PAGES__.page = {
|
|
224
|
+
module: pageModuleUrl,
|
|
225
|
+
props
|
|
226
|
+
};
|
|
227
|
+
|
|
156
228
|
if (window.__ECO_PAGES__.react?.pageRoot) {
|
|
157
229
|
root = window.__ECO_PAGES__.react.pageRoot;
|
|
158
230
|
root.render(createTree(Page, props));
|
|
@@ -174,30 +246,35 @@ const mount = () => {
|
|
|
174
246
|
};
|
|
175
247
|
};
|
|
176
248
|
|
|
249
|
+
${getDevRerunRegistrationScript(scriptId)}
|
|
250
|
+
|
|
177
251
|
if (document.readyState === "loading") {
|
|
178
252
|
document.addEventListener("DOMContentLoaded", mount);
|
|
179
253
|
} else {
|
|
180
254
|
mount();
|
|
181
255
|
}
|
|
256
|
+
}
|
|
182
257
|
`.trim();
|
|
183
258
|
}
|
|
184
259
|
function createProdScriptWithRouter(options) {
|
|
185
|
-
const { importPath, isMdx, router, reactImportPath, reactDomClientImportPath, routerImportPath } = options;
|
|
260
|
+
const { importPath, isMdx, router, reactImportPath, reactDomClientImportPath, routerImportPath, scriptId } = options;
|
|
261
|
+
const pageModuleUrlExpression = options.pageModuleUrlExpression ?? "import.meta.url";
|
|
186
262
|
const { components, getRouterProps } = router;
|
|
187
263
|
if (!routerImportPath) {
|
|
188
264
|
throw new Error("routerImportPath is required when router adapter is configured");
|
|
189
265
|
}
|
|
190
266
|
if (isMdx) {
|
|
191
|
-
return `import{hydrateRoot as hr}from"${reactDomClientImportPath}";import{createElement as ce}from"${reactImportPath}";import{${components.router} as R,${components.pageContent} as PC}from"${routerImportPath}";import*as M from"${importPath}";const P=M.default;if(M.config)P.config=M.config;window.__ECO_PAGES__=window.__ECO_PAGES__||{};window.__ECO_PAGES__.react=window.__ECO_PAGES__.react||{};window.__ECO_PAGES__.react.pageRoot=window.__ECO_PAGES__.react.pageRoot||null;let root=window.__ECO_PAGES__.react.pageRoot;${getProdPageRootCleanupScript()}${getProdRouterBootstrapRegistrationScript()}const gd=()=>{const e=document.getElementById("__ECO_PAGE_DATA__");if(e?.textContent){try{return JSON.parse(e.textContent)}catch{}}return{}};const
|
|
267
|
+
return `import{hydrateRoot as hr}from"${reactDomClientImportPath}";import{createElement as ce}from"${reactImportPath}";import{${components.router} as R,${components.pageContent} as PC}from"${routerImportPath}";import*as M from"${importPath}";const P=M.default;if(M.config)P.config=M.config;const u=${pageModuleUrlExpression};export default P;export const config=P.config;const a=!!document.querySelector('script[data-eco-script-id="${scriptId}"]');if(a){window.__ECO_PAGES__=window.__ECO_PAGES__||{};window.__ECO_PAGES__.react=window.__ECO_PAGES__.react||{};window.__ECO_PAGES__.react.pageRoot=window.__ECO_PAGES__.react.pageRoot||null;let root=window.__ECO_PAGES__.react.pageRoot;${getProdPageRootCleanupScript()}${getProdRouterBootstrapRegistrationScript()}${getProdReuseExistingRouterRootScript()}const gd=()=>{const e=document.getElementById("__ECO_PAGE_DATA__");if(e?.textContent){try{return JSON.parse(e.textContent)}catch{}}return{}};const ct=(C,p)=>ce(R,${getRouterProps("C", "p")},ce(PC));const m=()=>{const pr=gd();window.__ECO_PAGES__.page={module:u,props:pr};if(sr()){root=window.__ECO_PAGES__.react.pageRoot;return}if(window.__ECO_PAGES__.react?.pageRoot){root=window.__ECO_PAGES__.react.pageRoot;return}root=hr(document.body,ct(P,pr),{onRecoverableError:(e)=>console.warn("[ecopages] Hydration error:",e)});window.__ECO_PAGES__.react.pageRoot=root};${getProdRerunRegistrationScript(scriptId)}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",m):m()}`;
|
|
192
268
|
}
|
|
193
|
-
return `import{hydrateRoot as hr}from"${reactDomClientImportPath}";import{createElement as ce}from"${reactImportPath}";import{${components.router} as R,${components.pageContent} as PC}from"${routerImportPath}";import P from"${importPath}";window.__ECO_PAGES__=window.__ECO_PAGES__||{};window.__ECO_PAGES__.react=window.__ECO_PAGES__.react||{};window.__ECO_PAGES__.react.pageRoot=window.__ECO_PAGES__.react.pageRoot||null;let root=window.__ECO_PAGES__.react.pageRoot;${getProdPageRootCleanupScript()}${getProdRouterBootstrapRegistrationScript()}const gd=()=>{const e=document.getElementById("__ECO_PAGE_DATA__");if(e?.textContent){try{return JSON.parse(e.textContent)}catch{}}return{}};const
|
|
269
|
+
return `import{hydrateRoot as hr}from"${reactDomClientImportPath}";import{createElement as ce}from"${reactImportPath}";import{${components.router} as R,${components.pageContent} as PC}from"${routerImportPath}";import P from"${importPath}";const u=${pageModuleUrlExpression};export default P;export const config=P.config;const a=!!document.querySelector('script[data-eco-script-id="${scriptId}"]');if(a){window.__ECO_PAGES__=window.__ECO_PAGES__||{};window.__ECO_PAGES__.react=window.__ECO_PAGES__.react||{};window.__ECO_PAGES__.react.pageRoot=window.__ECO_PAGES__.react.pageRoot||null;let root=window.__ECO_PAGES__.react.pageRoot;${getProdPageRootCleanupScript()}${getProdRouterBootstrapRegistrationScript()}${getProdReuseExistingRouterRootScript()}const gd=()=>{const e=document.getElementById("__ECO_PAGE_DATA__");if(e?.textContent){try{return JSON.parse(e.textContent)}catch{}}return{}};const ct=(C,p)=>ce(R,${getRouterProps("C", "p")},ce(PC));const m=()=>{const pr=gd();window.__ECO_PAGES__.page={module:u,props:pr};if(sr()){root=window.__ECO_PAGES__.react.pageRoot;return}if(window.__ECO_PAGES__.react?.pageRoot){root=window.__ECO_PAGES__.react.pageRoot;return}root=hr(document.body,ct(P,pr),{onRecoverableError:(e)=>console.warn("[ecopages] Hydration error:",e)});window.__ECO_PAGES__.react.pageRoot=root};${getProdRerunRegistrationScript(scriptId)}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",m):m()}`;
|
|
194
270
|
}
|
|
195
271
|
function createProdScriptWithoutRouter(options) {
|
|
196
|
-
const { importPath, isMdx, reactImportPath, reactDomClientImportPath } = options;
|
|
272
|
+
const { importPath, isMdx, reactImportPath, reactDomClientImportPath, scriptId } = options;
|
|
273
|
+
const pageModuleUrlExpression = options.pageModuleUrlExpression ?? "import.meta.url";
|
|
197
274
|
if (isMdx) {
|
|
198
|
-
return `import{hydrateRoot as hr}from"${reactDomClientImportPath}";import{createElement as ce}from"${reactImportPath}";import*as M from"${importPath}";const P=M.default;if(M.config)P.config=M.config;window.__ECO_PAGES__=window.__ECO_PAGES__||{};window.__ECO_PAGES__.react=window.__ECO_PAGES__.react||{};window.__ECO_PAGES__.react.pageRoot=window.__ECO_PAGES__.react.pageRoot||null;let root=window.__ECO_PAGES__.react.pageRoot;${getProdPageRootCleanupScript()}const gd=()=>{const e=document.getElementById("__ECO_PAGE_DATA__");if(e?.textContent){try{return JSON.parse(e.textContent)}catch{}}return{}};const
|
|
275
|
+
return `import{hydrateRoot as hr}from"${reactDomClientImportPath}";import{createElement as ce}from"${reactImportPath}";import*as M from"${importPath}";const P=M.default;if(M.config)P.config=M.config;const u=${pageModuleUrlExpression};export default P;export const config=P.config;const a=!!document.querySelector('script[data-eco-script-id="${scriptId}"]');if(a){window.__ECO_PAGES__=window.__ECO_PAGES__||{};window.__ECO_PAGES__.react=window.__ECO_PAGES__.react||{};window.__ECO_PAGES__.react.pageRoot=window.__ECO_PAGES__.react.pageRoot||null;let root=window.__ECO_PAGES__.react.pageRoot;${getProdPageRootCleanupScript()}const gd=()=>{const e=document.getElementById("__ECO_PAGE_DATA__");if(e?.textContent){try{return JSON.parse(e.textContent)}catch{}}return{}};const ct=(C,p)=>{const L=C.config?.layout;const pe=ce(C,p);const lp=p?.locals?{locals:p.locals}:null;return L?ce(L,lp,pe):pe};const m=()=>{const pr=gd();window.__ECO_PAGES__.page={module:u,props:pr};if(window.__ECO_PAGES__.react?.pageRoot){root=window.__ECO_PAGES__.react.pageRoot;root.render(ct(P,pr));return}root=hr(document.body,ct(P,pr),{onRecoverableError:(e)=>console.warn("[ecopages] Hydration error:",e)});window.__ECO_PAGES__.react.pageRoot=root};${getProdRerunRegistrationScript(scriptId)}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",m):m()}`;
|
|
199
276
|
}
|
|
200
|
-
return `import{hydrateRoot as hr}from"${reactDomClientImportPath}";import{createElement as ce}from"${reactImportPath}";import P from"${importPath}";window.__ECO_PAGES__=window.__ECO_PAGES__||{};window.__ECO_PAGES__.react=window.__ECO_PAGES__.react||{};window.__ECO_PAGES__.react.pageRoot=window.__ECO_PAGES__.react.pageRoot||null;let root=window.__ECO_PAGES__.react.pageRoot;${getProdPageRootCleanupScript()}const gd=()=>{const e=document.getElementById("__ECO_PAGE_DATA__");if(e?.textContent){try{return JSON.parse(e.textContent)}catch{}}return{}};const
|
|
277
|
+
return `import{hydrateRoot as hr}from"${reactDomClientImportPath}";import{createElement as ce}from"${reactImportPath}";import P from"${importPath}";const u=${pageModuleUrlExpression};export default P;export const config=P.config;const a=!!document.querySelector('script[data-eco-script-id="${scriptId}"]');if(a){window.__ECO_PAGES__=window.__ECO_PAGES__||{};window.__ECO_PAGES__.react=window.__ECO_PAGES__.react||{};window.__ECO_PAGES__.react.pageRoot=window.__ECO_PAGES__.react.pageRoot||null;let root=window.__ECO_PAGES__.react.pageRoot;${getProdPageRootCleanupScript()}const gd=()=>{const e=document.getElementById("__ECO_PAGE_DATA__");if(e?.textContent){try{return JSON.parse(e.textContent)}catch{}}return{}};const ct=(C,p)=>{const L=C.config?.layout;const pe=ce(C,p);const lp=p?.locals?{locals:p.locals}:null;return L?ce(L,lp,pe):pe};const m=()=>{const pr=gd();window.__ECO_PAGES__.page={module:u,props:pr};if(window.__ECO_PAGES__.react?.pageRoot){root=window.__ECO_PAGES__.react.pageRoot;root.render(ct(P,pr));return}root=hr(document.body,ct(P,pr),{onRecoverableError:(e)=>console.warn("[ecopages] Hydration error:",e)});window.__ECO_PAGES__.react.pageRoot=root};${getProdRerunRegistrationScript(scriptId)}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",m):m()}`;
|
|
201
278
|
}
|
|
202
279
|
function createHydrationScript(options) {
|
|
203
280
|
const { isDevelopment, router } = options;
|
|
@@ -210,6 +287,7 @@ function createIslandHydrationScript(options) {
|
|
|
210
287
|
const targetSelector = JSON.stringify(options.targetSelector);
|
|
211
288
|
const componentRef = JSON.stringify(options.componentRef ?? "");
|
|
212
289
|
const componentFile = JSON.stringify(options.componentFile ?? "");
|
|
290
|
+
const scriptId = options.scriptId;
|
|
213
291
|
if (options.isDevelopment) {
|
|
214
292
|
return `
|
|
215
293
|
import { createRoot } from "${options.reactDomClientImportPath}";
|
|
@@ -245,19 +323,26 @@ const resolveComponent = () => {
|
|
|
245
323
|
};
|
|
246
324
|
|
|
247
325
|
const mount = () => {
|
|
248
|
-
const
|
|
326
|
+
const targets = document.querySelectorAll(${targetSelector});
|
|
249
327
|
const Component = resolveComponent();
|
|
250
|
-
if (!
|
|
328
|
+
if (!Component || targets.length === 0) {
|
|
251
329
|
return;
|
|
252
330
|
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
331
|
+
targets.forEach((target) => {
|
|
332
|
+
if (!(target instanceof HTMLElement)) {
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
const props = JSON.parse(atob(target.getAttribute("data-eco-props") || "e30="));
|
|
336
|
+
const container = document.createElement("eco-island");
|
|
337
|
+
container.style.display = "block";
|
|
338
|
+
target.replaceWith(container);
|
|
339
|
+
const root = createRoot(container);
|
|
340
|
+
root.render(createElement(Component, props));
|
|
341
|
+
});
|
|
259
342
|
};
|
|
260
343
|
|
|
344
|
+
${getDevRerunRegistrationScript(scriptId)}
|
|
345
|
+
|
|
261
346
|
if (document.readyState === "loading") {
|
|
262
347
|
document.addEventListener("DOMContentLoaded", mount, { once: true });
|
|
263
348
|
} else {
|
|
@@ -265,7 +350,7 @@ if (document.readyState === "loading") {
|
|
|
265
350
|
}
|
|
266
351
|
`.trim();
|
|
267
352
|
}
|
|
268
|
-
return `import{createRoot as cr}from"${options.reactDomClientImportPath}";import{createElement as ce}from"${options.reactImportPath}";import*as M from"${options.importPath}";const r=${componentRef};const f=${componentFile};const mv=Object.values(M);const c=mv.find((e)=>{if(typeof e!=="function")return false;const ec=e.config?.__eco;if(!ec)return false;if(r&&ec.id===r)return true;if(f&&ec.file===f)return true;return false;})??(typeof M.default==="function"?M.default:mv.find((e)=>typeof e==="function")??null);const m=()=>{const
|
|
353
|
+
return `import{createRoot as cr}from"${options.reactDomClientImportPath}";import{createElement as ce}from"${options.reactImportPath}";import*as M from"${options.importPath}";const r=${componentRef};const f=${componentFile};const mv=Object.values(M);const c=mv.find((e)=>{if(typeof e!=="function")return false;const ec=e.config?.__eco;if(!ec)return false;if(r&&ec.id===r)return true;if(f&&ec.file===f)return true;return false;})??(typeof M.default==="function"?M.default:mv.find((e)=>typeof e==="function")??null);const m=()=>{const ts=document.querySelectorAll(${targetSelector});if(!c||ts.length===0)return;ts.forEach((t)=>{if(!(t instanceof HTMLElement))return;const p=JSON.parse(atob(t.getAttribute("data-eco-props")||"e30="));const ct=document.createElement("eco-island");ct.style.display="block";t.replaceWith(ct);cr(ct).render(ce(c,p))})};${getProdRerunRegistrationScript(scriptId)}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",m,{once:true}):m()`;
|
|
269
354
|
}
|
|
270
355
|
export {
|
|
271
356
|
createHydrationScript,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it } from "vitest";
|
|
2
|
+
import { createHydrationScript } from "./hydration-scripts.js";
|
|
3
|
+
const routerAdapter = {
|
|
4
|
+
name: "eco-router",
|
|
5
|
+
bundle: {
|
|
6
|
+
importPath: "/assets/router.js",
|
|
7
|
+
outputName: "router",
|
|
8
|
+
externals: []
|
|
9
|
+
},
|
|
10
|
+
components: {
|
|
11
|
+
router: "EcoRouter",
|
|
12
|
+
pageContent: "PageContent"
|
|
13
|
+
},
|
|
14
|
+
getRouterProps: (page, props) => `{ page: ${page}, pageProps: ${props} }`
|
|
15
|
+
};
|
|
16
|
+
function createModuleUrl(source) {
|
|
17
|
+
return `data:text/javascript;base64,${btoa(source)}`;
|
|
18
|
+
}
|
|
19
|
+
async function importModule(moduleUrl, scriptId) {
|
|
20
|
+
let marker;
|
|
21
|
+
if (scriptId) {
|
|
22
|
+
marker = document.createElement("script");
|
|
23
|
+
marker.setAttribute("data-eco-script-id", scriptId);
|
|
24
|
+
document.head.appendChild(marker);
|
|
25
|
+
}
|
|
26
|
+
await import(
|
|
27
|
+
/* @vite-ignore */
|
|
28
|
+
moduleUrl
|
|
29
|
+
);
|
|
30
|
+
marker?.remove();
|
|
31
|
+
}
|
|
32
|
+
function createRuntimeModules() {
|
|
33
|
+
const reactImportPath = createModuleUrl("export const createElement = (...args) => ({ args });");
|
|
34
|
+
const reactDomClientImportPath = createModuleUrl(`
|
|
35
|
+
export const hydrateRoot = (container, tree, options) => {
|
|
36
|
+
const runtime = window.__ECO_REACT_HYDRATION_TEST__;
|
|
37
|
+
runtime.hydrateCalls.push({
|
|
38
|
+
containerTag: container.tagName,
|
|
39
|
+
hasRecoverableErrorHandler: typeof options?.onRecoverableError === "function",
|
|
40
|
+
tree,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
render() {},
|
|
45
|
+
unmount() {
|
|
46
|
+
runtime.unmountCount += 1;
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
`);
|
|
51
|
+
const importPath = createModuleUrl("export default function Page() { return null; }");
|
|
52
|
+
const routerImportPath = createModuleUrl(`
|
|
53
|
+
export function EcoRouter(props) {
|
|
54
|
+
return props;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function PageContent() {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
`);
|
|
61
|
+
return {
|
|
62
|
+
importPath,
|
|
63
|
+
reactImportPath,
|
|
64
|
+
reactDomClientImportPath,
|
|
65
|
+
routerImportPath
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
describe("createHydrationScript browser execution", () => {
|
|
69
|
+
afterEach(() => {
|
|
70
|
+
document.body.innerHTML = "";
|
|
71
|
+
const testWindow = window;
|
|
72
|
+
delete testWindow.__ECO_PAGES__;
|
|
73
|
+
delete testWindow.__ECO_REACT_HYDRATION_TEST__;
|
|
74
|
+
});
|
|
75
|
+
it("registers router ownership and cleanup when the browser hydration bootstrap runs", async () => {
|
|
76
|
+
const runtimeModules = createRuntimeModules();
|
|
77
|
+
const testWindow = window;
|
|
78
|
+
testWindow.__ECO_REACT_HYDRATION_TEST__ = {
|
|
79
|
+
hydrateCalls: [],
|
|
80
|
+
renderCalls: [],
|
|
81
|
+
claimedOwners: [],
|
|
82
|
+
releasedOwners: [],
|
|
83
|
+
registrations: [],
|
|
84
|
+
unmountCount: 0
|
|
85
|
+
};
|
|
86
|
+
testWindow.__ECO_PAGES__ = {
|
|
87
|
+
navigation: {
|
|
88
|
+
getOwnerState: () => ({
|
|
89
|
+
owner: "html",
|
|
90
|
+
canHandleSpaNavigation: false
|
|
91
|
+
}),
|
|
92
|
+
register: (registration) => {
|
|
93
|
+
testWindow.__ECO_REACT_HYDRATION_TEST__?.registrations.push(registration);
|
|
94
|
+
},
|
|
95
|
+
claimOwnership: (owner) => {
|
|
96
|
+
testWindow.__ECO_REACT_HYDRATION_TEST__?.claimedOwners.push(owner);
|
|
97
|
+
},
|
|
98
|
+
releaseOwnership: (owner) => {
|
|
99
|
+
testWindow.__ECO_REACT_HYDRATION_TEST__?.releasedOwners.push(owner);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
document.body.innerHTML = `<script id="__ECO_PAGE_DATA__" type="application/json">${JSON.stringify({
|
|
104
|
+
title: "Hello React",
|
|
105
|
+
locals: { theme: "dark" }
|
|
106
|
+
})}<\/script>`;
|
|
107
|
+
const script = createHydrationScript({
|
|
108
|
+
...runtimeModules,
|
|
109
|
+
scriptId: "ecopages-react-page",
|
|
110
|
+
isDevelopment: true,
|
|
111
|
+
isMdx: false,
|
|
112
|
+
router: routerAdapter
|
|
113
|
+
});
|
|
114
|
+
const moduleUrl = createModuleUrl(script);
|
|
115
|
+
await importModule(moduleUrl, "ecopages-react-page");
|
|
116
|
+
expect(testWindow.__ECO_REACT_HYDRATION_TEST__?.hydrateCalls).toHaveLength(1);
|
|
117
|
+
expect(testWindow.__ECO_REACT_HYDRATION_TEST__?.hydrateCalls[0]?.containerTag).toBe("BODY");
|
|
118
|
+
expect(testWindow.__ECO_REACT_HYDRATION_TEST__?.hydrateCalls[0]?.hasRecoverableErrorHandler).toBe(true);
|
|
119
|
+
expect(testWindow.__ECO_REACT_HYDRATION_TEST__?.claimedOwners).toEqual(["react-router"]);
|
|
120
|
+
expect(testWindow.__ECO_REACT_HYDRATION_TEST__?.registrations).toHaveLength(1);
|
|
121
|
+
expect(typeof testWindow.__ECO_PAGES__?.react?.cleanupPageRoot).toBe("function");
|
|
122
|
+
expect(testWindow.__ECO_PAGES__?.page).toEqual({
|
|
123
|
+
module: moduleUrl,
|
|
124
|
+
props: {
|
|
125
|
+
title: "Hello React",
|
|
126
|
+
locals: { theme: "dark" }
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
await testWindow.__ECO_PAGES__?.react?.cleanupPageRoot?.();
|
|
130
|
+
expect(testWindow.__ECO_REACT_HYDRATION_TEST__?.unmountCount).toBe(1);
|
|
131
|
+
expect(testWindow.__ECO_REACT_HYDRATION_TEST__?.releasedOwners).toEqual(["react-router"]);
|
|
132
|
+
expect(testWindow.__ECO_PAGES__?.page).toBeUndefined();
|
|
133
|
+
expect(testWindow.__ECO_PAGES__?.react?.pageRoot).toBeNull();
|
|
134
|
+
});
|
|
135
|
+
it("reuses an existing router-owned page root during rerun bootstrap execution", async () => {
|
|
136
|
+
const runtimeModules = createRuntimeModules();
|
|
137
|
+
const testWindow = window;
|
|
138
|
+
testWindow.__ECO_REACT_HYDRATION_TEST__ = {
|
|
139
|
+
hydrateCalls: [],
|
|
140
|
+
renderCalls: [],
|
|
141
|
+
claimedOwners: [],
|
|
142
|
+
releasedOwners: [],
|
|
143
|
+
registrations: [],
|
|
144
|
+
unmountCount: 0
|
|
145
|
+
};
|
|
146
|
+
const existingRoot = {
|
|
147
|
+
render: (tree) => {
|
|
148
|
+
testWindow.__ECO_REACT_HYDRATION_TEST__?.renderCalls.push(tree);
|
|
149
|
+
},
|
|
150
|
+
unmount: () => {
|
|
151
|
+
testWindow.__ECO_REACT_HYDRATION_TEST__.unmountCount += 1;
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
testWindow.__ECO_PAGES__ = {
|
|
155
|
+
navigation: {
|
|
156
|
+
getOwnerState: () => ({
|
|
157
|
+
owner: "react-router",
|
|
158
|
+
canHandleSpaNavigation: true
|
|
159
|
+
}),
|
|
160
|
+
register: (registration) => {
|
|
161
|
+
testWindow.__ECO_REACT_HYDRATION_TEST__?.registrations.push(registration);
|
|
162
|
+
},
|
|
163
|
+
claimOwnership: (owner) => {
|
|
164
|
+
testWindow.__ECO_REACT_HYDRATION_TEST__?.claimedOwners.push(owner);
|
|
165
|
+
},
|
|
166
|
+
releaseOwnership: (owner) => {
|
|
167
|
+
testWindow.__ECO_REACT_HYDRATION_TEST__?.releasedOwners.push(owner);
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
react: {
|
|
171
|
+
pageRoot: existingRoot
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
document.body.innerHTML = `<script id="__ECO_PAGE_DATA__" type="application/json">${JSON.stringify({
|
|
175
|
+
title: "Rerun"
|
|
176
|
+
})}<\/script>`;
|
|
177
|
+
const script = createHydrationScript({
|
|
178
|
+
...runtimeModules,
|
|
179
|
+
scriptId: "ecopages-react-page-rerun",
|
|
180
|
+
isDevelopment: true,
|
|
181
|
+
isMdx: false,
|
|
182
|
+
router: routerAdapter
|
|
183
|
+
});
|
|
184
|
+
const moduleUrl = createModuleUrl(script);
|
|
185
|
+
await importModule(moduleUrl, "ecopages-react-page-rerun");
|
|
186
|
+
expect(testWindow.__ECO_REACT_HYDRATION_TEST__?.hydrateCalls).toHaveLength(0);
|
|
187
|
+
expect(testWindow.__ECO_REACT_HYDRATION_TEST__?.renderCalls).toHaveLength(0);
|
|
188
|
+
expect(testWindow.__ECO_REACT_HYDRATION_TEST__?.claimedOwners).toHaveLength(0);
|
|
189
|
+
expect(testWindow.__ECO_REACT_HYDRATION_TEST__?.registrations).toHaveLength(0);
|
|
190
|
+
expect(testWindow.__ECO_PAGES__?.react?.pageRoot).toBe(existingRoot);
|
|
191
|
+
expect(testWindow.__ECO_PAGES__?.page).toEqual({
|
|
192
|
+
module: moduleUrl,
|
|
193
|
+
props: {
|
|
194
|
+
title: "Rerun"
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
});
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
function escapeRegExp(value) {
|
|
4
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
5
|
+
}
|
|
3
6
|
function createReactDomRuntimeInteropPlugin(options) {
|
|
4
7
|
const reactDomFileFilter = /[\\/]react-dom[\\/].*\.js$/;
|
|
5
8
|
const reactRequirePattern = /\brequire\((['"])react\1\)/g;
|
|
@@ -7,6 +10,12 @@ function createReactDomRuntimeInteropPlugin(options) {
|
|
|
7
10
|
return {
|
|
8
11
|
name: options?.name ?? "react-dom-runtime-interop",
|
|
9
12
|
setup(build) {
|
|
13
|
+
if (reactSpecifier.startsWith("/")) {
|
|
14
|
+
build.onResolve({ filter: new RegExp(`^${escapeRegExp(reactSpecifier)}$`) }, (args) => ({
|
|
15
|
+
path: args.path,
|
|
16
|
+
external: true
|
|
17
|
+
}));
|
|
18
|
+
}
|
|
10
19
|
build.onLoad({ filter: reactDomFileFilter }, (args) => {
|
|
11
20
|
const content = fs.readFileSync(args.path, "utf-8");
|
|
12
21
|
if (!reactRequirePattern.test(content)) {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type { EcoBuildPlugin } from '@ecopages/core/
|
|
1
|
+
import type { EcoBuildPlugin } from '@ecopages/core/plugins/integration-plugin';
|
|
2
2
|
import { type CompileOptions } from '@mdx-js/mdx';
|
|
3
3
|
export declare function createReactMdxLoaderPlugin(compilerOptions?: CompileOptions): EcoBuildPlugin;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { ReactRouterAdapter } from '../router-adapter.js';
|
|
2
2
|
import type { ReactRuntimeImports } from '../services/react-runtime-bundle.service.js';
|
|
3
|
+
import { type BrowserRuntimeManifest } from '@ecopages/core/build/browser-runtime-manifest';
|
|
3
4
|
export declare const REACT_RUNTIME_SPECIFIERS: readonly ["react", "react-dom", "react/jsx-runtime", "react/jsx-dev-runtime", "react-dom/client"];
|
|
4
|
-
export declare function
|
|
5
|
+
export declare function buildReactRuntimeAliasMap(runtimeImports: ReactRuntimeImports): Record<string, string>;
|
|
6
|
+
export declare function buildReactRuntimeManifest(runtimeImports: ReactRuntimeImports): BrowserRuntimeManifest;
|
|
5
7
|
export declare function getReactRuntimeExternalSpecifiers(): string[];
|
|
6
8
|
export declare function getReactClientGraphAllowSpecifiers(runtimeSpecifiers: Iterable<string>, routerAdapter?: ReactRouterAdapter): string[];
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createBrowserRuntimeManifest,
|
|
3
|
+
getBrowserRuntimeSpecifierMap
|
|
4
|
+
} from "@ecopages/core/build/browser-runtime-manifest";
|
|
5
|
+
const REACT_RUNTIME_SPECIFIERS = [
|
|
6
|
+
"react",
|
|
7
|
+
"react-dom",
|
|
8
|
+
"react/jsx-runtime",
|
|
9
|
+
"react/jsx-dev-runtime",
|
|
10
|
+
"react-dom/client"
|
|
11
|
+
];
|
|
12
|
+
function buildReactRuntimeAliasMap(runtimeImports) {
|
|
13
|
+
return Object.fromEntries(getBrowserRuntimeSpecifierMap(buildReactRuntimeManifest(runtimeImports)));
|
|
14
|
+
}
|
|
15
|
+
function buildReactRuntimeManifest(runtimeImports) {
|
|
16
|
+
return createBrowserRuntimeManifest([
|
|
17
|
+
{
|
|
18
|
+
specifier: "react",
|
|
19
|
+
owner: "@ecopages/react",
|
|
20
|
+
importPath: "react",
|
|
21
|
+
publicPath: runtimeImports.react
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
specifier: "react/jsx-runtime",
|
|
25
|
+
owner: "@ecopages/react",
|
|
26
|
+
importPath: "react/jsx-runtime",
|
|
27
|
+
publicPath: runtimeImports.reactJsxRuntime
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
specifier: "react/jsx-dev-runtime",
|
|
31
|
+
owner: "@ecopages/react",
|
|
32
|
+
importPath: "react/jsx-dev-runtime",
|
|
33
|
+
publicPath: runtimeImports.reactJsxDevRuntime
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
specifier: "react-dom",
|
|
37
|
+
owner: "@ecopages/react",
|
|
38
|
+
importPath: "react-dom",
|
|
39
|
+
publicPath: runtimeImports.reactDom
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
specifier: "react-dom/client",
|
|
43
|
+
owner: "@ecopages/react",
|
|
44
|
+
importPath: "react-dom/client",
|
|
45
|
+
publicPath: runtimeImports.reactDomClient
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
specifier: "use-sync-external-store/shim",
|
|
49
|
+
owner: "@ecopages/react",
|
|
50
|
+
importPath: "use-sync-external-store/shim",
|
|
51
|
+
publicPath: runtimeImports.react
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
specifier: "use-sync-external-store/shim/index.js",
|
|
55
|
+
owner: "@ecopages/react",
|
|
56
|
+
importPath: "use-sync-external-store/shim/index.js",
|
|
57
|
+
publicPath: runtimeImports.react
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
specifier: "use-sync-external-store/shim/with-selector",
|
|
61
|
+
owner: "@ecopages/react",
|
|
62
|
+
importPath: "use-sync-external-store/shim/with-selector",
|
|
63
|
+
publicPath: runtimeImports.useSyncExternalStoreWithSelector
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
specifier: "use-sync-external-store/shim/with-selector.js",
|
|
67
|
+
owner: "@ecopages/react",
|
|
68
|
+
importPath: "use-sync-external-store/shim/with-selector.js",
|
|
69
|
+
publicPath: runtimeImports.useSyncExternalStoreWithSelector
|
|
70
|
+
}
|
|
71
|
+
]);
|
|
72
|
+
}
|
|
73
|
+
function getReactRuntimeExternalSpecifiers() {
|
|
74
|
+
return [...REACT_RUNTIME_SPECIFIERS];
|
|
75
|
+
}
|
|
76
|
+
function getReactClientGraphAllowSpecifiers(runtimeSpecifiers, routerAdapter) {
|
|
77
|
+
return [
|
|
78
|
+
"@ecopages/core",
|
|
79
|
+
...REACT_RUNTIME_SPECIFIERS,
|
|
80
|
+
...routerAdapter ? [routerAdapter.bundle.importPath] : [],
|
|
81
|
+
...Array.from(runtimeSpecifiers)
|
|
82
|
+
];
|
|
83
|
+
}
|
|
84
|
+
export {
|
|
85
|
+
REACT_RUNTIME_SPECIFIERS,
|
|
86
|
+
buildReactRuntimeAliasMap,
|
|
87
|
+
buildReactRuntimeManifest,
|
|
88
|
+
getReactClientGraphAllowSpecifiers,
|
|
89
|
+
getReactRuntimeExternalSpecifiers
|
|
90
|
+
};
|