@ecopages/ecopages-jsx 0.2.0-beta.13 → 0.2.0-beta.14
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 +5 -5
- package/src/ecopages-jsx-hmr-ownership.d.ts +37 -0
- package/src/ecopages-jsx-hmr-ownership.js +63 -0
- package/src/ecopages-jsx-hmr-strategy.d.ts +36 -0
- package/src/ecopages-jsx-hmr-strategy.js +62 -0
- package/src/ecopages-jsx-mdx.js +5 -1
- package/src/ecopages-jsx-radiant-ssr-policy.js +33 -7
- package/src/ecopages-jsx-renderer.d.ts +6 -0
- package/src/ecopages-jsx-renderer.js +18 -3
- package/src/ecopages-jsx.plugin.d.ts +11 -0
- package/src/ecopages-jsx.plugin.js +27 -1
- package/src/resolve-radiant-install-hydrator.d.ts +2 -0
- package/src/resolve-radiant-install-hydrator.js +7 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ecopages/ecopages-jsx",
|
|
3
|
-
"version": "0.2.0-beta.
|
|
3
|
+
"version": "0.2.0-beta.14",
|
|
4
4
|
"description": "JSX integration plugin for Ecopages",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ecopages",
|
|
@@ -31,13 +31,13 @@
|
|
|
31
31
|
"directory": "packages/integrations/ecopages-jsx"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@ecopages/mdx": "0.2.0-beta.
|
|
34
|
+
"@ecopages/mdx": "0.2.0-beta.14",
|
|
35
35
|
"@mdx-js/mdx": "^3.1.1",
|
|
36
36
|
"vfile": "^6.0.3"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
|
-
"@ecopages/core": "0.2.0-beta.
|
|
40
|
-
"@ecopages/jsx": "0.3.0-
|
|
41
|
-
"@ecopages/radiant": "0.3.0-
|
|
39
|
+
"@ecopages/core": "0.2.0-beta.14",
|
|
40
|
+
"@ecopages/jsx": "0.3.0-beta.0",
|
|
41
|
+
"@ecopages/radiant": "0.3.0-beta.0"
|
|
42
42
|
}
|
|
43
43
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tracks the source files that participate in the active SSR render tree.
|
|
3
|
+
*
|
|
4
|
+
* @remarks
|
|
5
|
+
* The JSX integration renderer calls {@link updateEjsxHmrOwnership} after each
|
|
6
|
+
* page, component, or view render so the HMR strategy can answer
|
|
7
|
+
* "does this changed file affect SSR HTML?" without re-walking the tree on
|
|
8
|
+
* every watcher event.
|
|
9
|
+
*
|
|
10
|
+
* The state is module-scoped because the HMR strategy and renderer live in
|
|
11
|
+
* different call sites (server strategy vs SSR renderer) and share no other
|
|
12
|
+
* lifecycle anchor. A fresh state is installed only when the source-file set
|
|
13
|
+
* changes, so the renderer's per-render hook stays O(1) in the steady state.
|
|
14
|
+
*/
|
|
15
|
+
import type { EcoComponent } from '@ecopages/core';
|
|
16
|
+
export type EjsxHmrOwnershipState = {
|
|
17
|
+
fileOwners: ReadonlySet<string>;
|
|
18
|
+
hash: string;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Returns the most recently recorded active render tree.
|
|
22
|
+
*/
|
|
23
|
+
export declare function getEjsxHmrOwnership(): EjsxHmrOwnershipState;
|
|
24
|
+
/**
|
|
25
|
+
* Updates the active render tree from one or more root components.
|
|
26
|
+
*
|
|
27
|
+
* @remarks
|
|
28
|
+
* Walks each root's `config.__eco.file`, `config.dependencies.components[*].config`,
|
|
29
|
+
* and `config.layouts[*].config` recursively, collecting every file path. The
|
|
30
|
+
* state is replaced only when the resulting file set has a different hash, so
|
|
31
|
+
* the renderer's per-render hook is free in the steady state.
|
|
32
|
+
*/
|
|
33
|
+
export declare function updateEjsxHmrOwnership(components: ReadonlyArray<EcoComponent | undefined>): void;
|
|
34
|
+
/**
|
|
35
|
+
* Resets the state to empty. Used by tests and by HMR manager teardown.
|
|
36
|
+
*/
|
|
37
|
+
export declare function resetEjsxHmrOwnership(): void;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { rapidhash } from "@ecopages/core/hash";
|
|
3
|
+
const EMPTY_STATE = {
|
|
4
|
+
fileOwners: /* @__PURE__ */ new Set(),
|
|
5
|
+
hash: ""
|
|
6
|
+
};
|
|
7
|
+
let currentState = EMPTY_STATE;
|
|
8
|
+
function getEjsxHmrOwnership() {
|
|
9
|
+
return currentState;
|
|
10
|
+
}
|
|
11
|
+
function updateEjsxHmrOwnership(components) {
|
|
12
|
+
const files = collectFileOwners(components);
|
|
13
|
+
const hash = hashFileSet(files);
|
|
14
|
+
if (hash === currentState.hash) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
currentState = {
|
|
18
|
+
fileOwners: files,
|
|
19
|
+
hash
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function resetEjsxHmrOwnership() {
|
|
23
|
+
currentState = EMPTY_STATE;
|
|
24
|
+
}
|
|
25
|
+
function collectFileOwners(components) {
|
|
26
|
+
const files = /* @__PURE__ */ new Set();
|
|
27
|
+
const visited = /* @__PURE__ */ new Set();
|
|
28
|
+
const visit = (config) => {
|
|
29
|
+
const file = config?.__eco?.file;
|
|
30
|
+
if (!file) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const resolved = path.resolve(file);
|
|
34
|
+
if (visited.has(resolved)) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
visited.add(resolved);
|
|
38
|
+
files.add(resolved);
|
|
39
|
+
for (const dependency of config?.dependencies?.components ?? []) {
|
|
40
|
+
visit(dependency?.config);
|
|
41
|
+
}
|
|
42
|
+
for (const layout of config?.layouts ?? []) {
|
|
43
|
+
visit(layout?.config);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
for (const component of components) {
|
|
47
|
+
visit(component?.config);
|
|
48
|
+
}
|
|
49
|
+
return files;
|
|
50
|
+
}
|
|
51
|
+
function hashFileSet(files) {
|
|
52
|
+
if (files.size === 0) {
|
|
53
|
+
return "";
|
|
54
|
+
}
|
|
55
|
+
const sorted = Array.from(files).sort();
|
|
56
|
+
const joined = sorted.join("\n");
|
|
57
|
+
return rapidhash(joined).toString(36);
|
|
58
|
+
}
|
|
59
|
+
export {
|
|
60
|
+
getEjsxHmrOwnership,
|
|
61
|
+
resetEjsxHmrOwnership,
|
|
62
|
+
updateEjsxHmrOwnership
|
|
63
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HMR strategy for JSX integration-owned SSR source modules.
|
|
3
|
+
*
|
|
4
|
+
* @remarks
|
|
5
|
+
* Edits to files that produce SSR HTML (page sources, layout sources, components
|
|
6
|
+
* that the active render tree depends on) need a soft page refetch so the
|
|
7
|
+
* browser picks up the new markup. Plain `update` events re-import modules on
|
|
8
|
+
* the client but leave the server-rendered DOM stale.
|
|
9
|
+
*
|
|
10
|
+
* The strategy matches a file when any of these hold:
|
|
11
|
+
* - the file lives under `pagesDir` or `layoutsDir` and has a JSX `templatesExt`
|
|
12
|
+
* - the file appears in the active render tree's component dependency graph
|
|
13
|
+
*
|
|
14
|
+
* It defers registered HMR entrypoints to {@link JsHmrStrategy} so script-only
|
|
15
|
+
* edits keep their existing `update`-then-hot-accept path. It also defers
|
|
16
|
+
* include templates and explicit server views to {@link ServerRenderedTemplateHmrStrategy}
|
|
17
|
+
* by returning `false` for those paths.
|
|
18
|
+
*/
|
|
19
|
+
import { HmrStrategy, type HmrAction } from '@ecopages/core/hmr/hmr-strategy';
|
|
20
|
+
export interface EcopagesJsxHmrStrategyContext {
|
|
21
|
+
getWatchedFiles(): Map<string, string>;
|
|
22
|
+
getSrcDir(): string;
|
|
23
|
+
getPagesDir(): string;
|
|
24
|
+
getLayoutsDir(): string;
|
|
25
|
+
getIncludesDir(): string;
|
|
26
|
+
getTemplateExtensions(): ReadonlyArray<string>;
|
|
27
|
+
}
|
|
28
|
+
export declare class EcopagesJsxHmrStrategy extends HmrStrategy {
|
|
29
|
+
readonly type: 100;
|
|
30
|
+
private readonly context;
|
|
31
|
+
constructor(context: EcopagesJsxHmrStrategyContext);
|
|
32
|
+
matches(filePath: string): boolean;
|
|
33
|
+
process(filePath: string): Promise<HmrAction>;
|
|
34
|
+
private isPageOrLayoutSource;
|
|
35
|
+
private hasJsxTemplateExtension;
|
|
36
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { HmrStrategy, HmrStrategyType } from "@ecopages/core/hmr/hmr-strategy";
|
|
3
|
+
import { getEjsxHmrOwnership } from "./ecopages-jsx-hmr-ownership.js";
|
|
4
|
+
class EcopagesJsxHmrStrategy extends HmrStrategy {
|
|
5
|
+
type = HmrStrategyType.INTEGRATION;
|
|
6
|
+
context;
|
|
7
|
+
constructor(context) {
|
|
8
|
+
super();
|
|
9
|
+
this.context = context;
|
|
10
|
+
}
|
|
11
|
+
matches(filePath) {
|
|
12
|
+
if (this.context.getWatchedFiles().has(filePath)) {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
const resolvedPath = path.resolve(filePath);
|
|
16
|
+
const srcDir = path.resolve(this.context.getSrcDir());
|
|
17
|
+
if (!resolvedPath.startsWith(`${srcDir}${path.sep}`) && resolvedPath !== srcDir) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
const includesDir = path.resolve(this.context.getIncludesDir());
|
|
21
|
+
if (includesDir && (resolvedPath === includesDir || resolvedPath.startsWith(`${includesDir}${path.sep}`))) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
if (this.isPageOrLayoutSource(resolvedPath)) {
|
|
25
|
+
return this.hasJsxTemplateExtension(resolvedPath);
|
|
26
|
+
}
|
|
27
|
+
const ownership = getEjsxHmrOwnership();
|
|
28
|
+
if (ownership.fileOwners.has(resolvedPath)) {
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
async process(filePath) {
|
|
34
|
+
return {
|
|
35
|
+
type: "broadcast",
|
|
36
|
+
events: [
|
|
37
|
+
{
|
|
38
|
+
type: "layout-update",
|
|
39
|
+
path: filePath,
|
|
40
|
+
timestamp: Date.now()
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
isPageOrLayoutSource(resolvedPath) {
|
|
46
|
+
const pagesDir = path.resolve(this.context.getPagesDir());
|
|
47
|
+
const layoutsDir = path.resolve(this.context.getLayoutsDir());
|
|
48
|
+
if (pagesDir && (resolvedPath === pagesDir || resolvedPath.startsWith(`${pagesDir}${path.sep}`))) {
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
if (layoutsDir && (resolvedPath === layoutsDir || resolvedPath.startsWith(`${layoutsDir}${path.sep}`))) {
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
hasJsxTemplateExtension(resolvedPath) {
|
|
57
|
+
return this.context.getTemplateExtensions().some((extension) => resolvedPath.endsWith(extension));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
export {
|
|
61
|
+
EcopagesJsxHmrStrategy
|
|
62
|
+
};
|
package/src/ecopages-jsx-mdx.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { ensurePageConfigLayouts } from "@ecopages/core/eco/page-layout-normalization";
|
|
2
3
|
import { rapidhash } from "@ecopages/core/hash";
|
|
3
4
|
import {
|
|
4
5
|
appendMdxExtensions,
|
|
@@ -49,13 +50,16 @@ const normalizeMdxPageModule = (file, module) => {
|
|
|
49
50
|
const Page = module.default;
|
|
50
51
|
const normalizedConfig = {
|
|
51
52
|
...module.config ?? Page.config ?? {},
|
|
52
|
-
...module.layout ? { layout: module.layout } : {},
|
|
53
53
|
__eco: module.config?.__eco ?? Page.config?.__eco ?? {
|
|
54
54
|
id: String(rapidhash(file)),
|
|
55
55
|
file,
|
|
56
56
|
integration: ECOPAGES_JSX_PLUGIN_NAME
|
|
57
57
|
}
|
|
58
58
|
};
|
|
59
|
+
if (module.layout && !(normalizedConfig.layouts && normalizedConfig.layouts.length > 0)) {
|
|
60
|
+
normalizedConfig.layout = module.layout;
|
|
61
|
+
}
|
|
62
|
+
ensurePageConfigLayouts(normalizedConfig);
|
|
59
63
|
const wrappedPage = async (props) => await Page(props);
|
|
60
64
|
wrappedPage.config = normalizedConfig;
|
|
61
65
|
if (module.getMetadata ?? Page.metadata) {
|
|
@@ -57,10 +57,10 @@ class EcopagesJsxRadiantSsrPolicy {
|
|
|
57
57
|
"./radiant-element-ssr-bridge.js",
|
|
58
58
|
radiantLightDomShimEntry
|
|
59
59
|
).href;
|
|
60
|
-
EcopagesJsxRadiantSsrPolicy.runtimeModulesPromise =
|
|
61
|
-
import(
|
|
62
|
-
|
|
63
|
-
|
|
60
|
+
EcopagesJsxRadiantSsrPolicy.runtimeModulesPromise = (async () => {
|
|
61
|
+
const lightDomShimModule2 = await import(radiantLightDomShimEntry);
|
|
62
|
+
ensureRadiantLightDomGlobals(lightDomShimModule2.installLightDomShim);
|
|
63
|
+
const radiantElementSsrRuntimeModule = await import(radiantElementSsrRuntimeModuleUrl);
|
|
64
64
|
const modules = {
|
|
65
65
|
installLightDomShim: lightDomShimModule2.installLightDomShim,
|
|
66
66
|
resolveRadiantElementRenderBridge: radiantElementSsrRuntimeModule.resolveRadiantElementRenderBridge,
|
|
@@ -68,11 +68,37 @@ class EcopagesJsxRadiantSsrPolicy {
|
|
|
68
68
|
};
|
|
69
69
|
EcopagesJsxRadiantSsrPolicy.runtimeModules = modules;
|
|
70
70
|
return modules;
|
|
71
|
-
});
|
|
71
|
+
})();
|
|
72
72
|
}
|
|
73
|
-
|
|
74
|
-
lightDomShimModule.
|
|
73
|
+
await EcopagesJsxRadiantSsrPolicy.runtimeModulesPromise;
|
|
74
|
+
const lightDomShimModule = EcopagesJsxRadiantSsrPolicy.runtimeModules;
|
|
75
|
+
if (lightDomShimModule) {
|
|
76
|
+
ensureRadiantLightDomGlobals(lightDomShimModule.installLightDomShim);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function ensureRadiantLightDomGlobals(installLightDomShim) {
|
|
81
|
+
if (typeof globalThis.HTMLElement !== "undefined") {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const window = installLightDomShim();
|
|
85
|
+
if (!window) {
|
|
86
|
+
return;
|
|
75
87
|
}
|
|
88
|
+
Object.assign(globalThis, {
|
|
89
|
+
CSS: window.CSS,
|
|
90
|
+
CustomEvent: window.CustomEvent,
|
|
91
|
+
Document: window.Document,
|
|
92
|
+
Element: window.Element,
|
|
93
|
+
Event: window.Event,
|
|
94
|
+
EventTarget: window.EventTarget,
|
|
95
|
+
HTMLScriptElement: window.HTMLScriptElement,
|
|
96
|
+
HTMLElement: window.HTMLElement,
|
|
97
|
+
Node: window.Node,
|
|
98
|
+
document: window.document,
|
|
99
|
+
customElements: window.customElements,
|
|
100
|
+
window
|
|
101
|
+
});
|
|
76
102
|
}
|
|
77
103
|
export {
|
|
78
104
|
EcopagesJsxRadiantSsrPolicy
|
|
@@ -37,4 +37,10 @@ export declare class EcopagesJsxRenderer extends IntegrationRenderer<JsxRenderab
|
|
|
37
37
|
private withCustomElementRenderHook;
|
|
38
38
|
private withPreparedRadiantRuntime;
|
|
39
39
|
private createIntrinsicCustomElementRenderHook;
|
|
40
|
+
/**
|
|
41
|
+
* Records the source files that produced the current render so
|
|
42
|
+
* {@link EcopagesJsxHmrStrategy} can match later watcher events without
|
|
43
|
+
* re-walking the component tree.
|
|
44
|
+
*/
|
|
45
|
+
private recordHmrOwnership;
|
|
40
46
|
}
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
} from "./ecopages-jsx-mdx.js";
|
|
11
11
|
import { EcopagesJsxRenderSession } from "./ecopages-jsx-render-session.js";
|
|
12
12
|
import { EcopagesJsxRadiantSsrPolicy } from "./ecopages-jsx-radiant-ssr-policy.js";
|
|
13
|
+
import { updateEjsxHmrOwnership } from "./ecopages-jsx-hmr-ownership.js";
|
|
13
14
|
class EcopagesJsxRenderer extends IntegrationRenderer {
|
|
14
15
|
name = ECOPAGES_JSX_PLUGIN_NAME;
|
|
15
16
|
mdxExtensions;
|
|
@@ -107,7 +108,7 @@ class EcopagesJsxRenderer extends IntegrationRenderer {
|
|
|
107
108
|
return await this.withPreparedRadiantRuntime(
|
|
108
109
|
() => this.renderSession.withActiveScope(async () => {
|
|
109
110
|
try {
|
|
110
|
-
|
|
111
|
+
const result = await this.renderPageWithDocumentShell({
|
|
111
112
|
page: {
|
|
112
113
|
component: options.Page,
|
|
113
114
|
props: {
|
|
@@ -126,6 +127,8 @@ class EcopagesJsxRenderer extends IntegrationRenderer {
|
|
|
126
127
|
metadata: options.metadata,
|
|
127
128
|
pageProps: options.pageProps ?? {}
|
|
128
129
|
});
|
|
130
|
+
this.recordHmrOwnership([options.Page, options.Layout, options.HtmlTemplate]);
|
|
131
|
+
return result;
|
|
129
132
|
} catch (error) {
|
|
130
133
|
throw this.createRenderError("Error rendering page", error);
|
|
131
134
|
}
|
|
@@ -159,6 +162,7 @@ class EcopagesJsxRenderer extends IntegrationRenderer {
|
|
|
159
162
|
...queuedForeignSubtreeResolution.assets,
|
|
160
163
|
...componentAssets
|
|
161
164
|
]);
|
|
165
|
+
this.recordHmrOwnership([input.component]);
|
|
162
166
|
return {
|
|
163
167
|
html: queuedForeignSubtreeResolution.html,
|
|
164
168
|
canAttachAttributes: true,
|
|
@@ -181,12 +185,15 @@ class EcopagesJsxRenderer extends IntegrationRenderer {
|
|
|
181
185
|
throw new TypeError("JSX renderer expected a callable view component.");
|
|
182
186
|
}
|
|
183
187
|
const viewComponent = view;
|
|
184
|
-
|
|
188
|
+
const layouts = viewComponent.config?.layouts;
|
|
189
|
+
const response = await this.renderViewWithDocumentShell({
|
|
185
190
|
view: viewComponent,
|
|
186
191
|
props,
|
|
187
192
|
ctx,
|
|
188
|
-
layout:
|
|
193
|
+
layout: layouts?.[layouts.length - 1]
|
|
189
194
|
});
|
|
195
|
+
this.recordHmrOwnership([view]);
|
|
196
|
+
return response;
|
|
190
197
|
} catch (error) {
|
|
191
198
|
throw this.createRenderError("Error rendering view", error);
|
|
192
199
|
}
|
|
@@ -216,6 +223,14 @@ class EcopagesJsxRenderer extends IntegrationRenderer {
|
|
|
216
223
|
return instance ? this.radiantSsrPolicy.renderIntrinsicElementMarkup(instance) : void 0;
|
|
217
224
|
};
|
|
218
225
|
}
|
|
226
|
+
/**
|
|
227
|
+
* Records the source files that produced the current render so
|
|
228
|
+
* {@link EcopagesJsxHmrStrategy} can match later watcher events without
|
|
229
|
+
* re-walking the component tree.
|
|
230
|
+
*/
|
|
231
|
+
recordHmrOwnership(components) {
|
|
232
|
+
updateEjsxHmrOwnership(components);
|
|
233
|
+
}
|
|
219
234
|
}
|
|
220
235
|
export {
|
|
221
236
|
EcopagesJsxRenderer
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { IntegrationPlugin, type EcoBuildPlugin } from '@ecopages/core/plugins/integration-plugin';
|
|
2
|
+
import type { HmrStrategy } from '@ecopages/core/hmr/hmr-strategy';
|
|
2
3
|
import type { JsxRenderable } from '@ecopages/jsx';
|
|
3
4
|
import { EcopagesJsxRenderer } from './ecopages-jsx-renderer.js';
|
|
4
5
|
import type { EcopagesJsxPluginOptions } from './ecopages-jsx.types.js';
|
|
@@ -21,6 +22,16 @@ export declare class EcopagesJsxPlugin extends IntegrationPlugin<JsxRenderable>
|
|
|
21
22
|
private getDependencies;
|
|
22
23
|
/** Ensures MDX build hooks are ready before Ecopages collects contributions. */
|
|
23
24
|
prepareBuildContributions(): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* Returns the JSX-integration HMR strategy.
|
|
27
|
+
*
|
|
28
|
+
* @remarks
|
|
29
|
+
* The strategy handles `layout-update` broadcasts for page sources, layout
|
|
30
|
+
* sources, and any component file in the active render tree. It defers
|
|
31
|
+
* registered script entrypoints to the generic JS strategy and includes /
|
|
32
|
+
* explicit server views to `ServerRenderedTemplateHmrStrategy`.
|
|
33
|
+
*/
|
|
34
|
+
getHmrStrategy(): HmrStrategy | undefined;
|
|
24
35
|
/**
|
|
25
36
|
* Registers MDX tooling and completes the base integration setup.
|
|
26
37
|
*/
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
} from "@ecopages/core/plugins/integration-plugin";
|
|
4
4
|
import { AssetFactory } from "@ecopages/core/services/asset-processing-service";
|
|
5
5
|
import { ECOPAGES_JSX_PLUGIN_NAME } from "./ecopages-jsx.constants.js";
|
|
6
|
+
import { RADIANT_INSTALL_HYDRATOR_FILEPATH } from "./resolve-radiant-install-hydrator.js";
|
|
6
7
|
import {
|
|
7
8
|
appendMdxExtensions,
|
|
8
9
|
createMdxLoaderPlugin,
|
|
@@ -10,6 +11,7 @@ import {
|
|
|
10
11
|
resolveMdxCompilerOptions
|
|
11
12
|
} from "./ecopages-jsx-mdx.js";
|
|
12
13
|
import { EcopagesJsxRenderer } from "./ecopages-jsx-renderer.js";
|
|
14
|
+
import { EcopagesJsxHmrStrategy } from "./ecopages-jsx-hmr-strategy.js";
|
|
13
15
|
const RADIANT_HYDRATOR_SCRIPT_ID = "ecopages-jsx-radiant-hydrator";
|
|
14
16
|
const resolvePluginOptions = (options) => {
|
|
15
17
|
const { extensions: userExtensions, radiant, mdx, ...baseConfig } = options ?? {};
|
|
@@ -72,7 +74,7 @@ class EcopagesJsxPlugin extends IntegrationPlugin {
|
|
|
72
74
|
return [
|
|
73
75
|
AssetFactory.createNodeModuleScript({
|
|
74
76
|
position: "head",
|
|
75
|
-
importPath:
|
|
77
|
+
importPath: RADIANT_INSTALL_HYDRATOR_FILEPATH,
|
|
76
78
|
bundle: false,
|
|
77
79
|
attributes: {
|
|
78
80
|
"data-eco-script-id": RADIANT_HYDRATOR_SCRIPT_ID
|
|
@@ -84,6 +86,30 @@ class EcopagesJsxPlugin extends IntegrationPlugin {
|
|
|
84
86
|
async prepareBuildContributions() {
|
|
85
87
|
this.ensureMdxLoaderPlugin();
|
|
86
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* Returns the JSX-integration HMR strategy.
|
|
91
|
+
*
|
|
92
|
+
* @remarks
|
|
93
|
+
* The strategy handles `layout-update` broadcasts for page sources, layout
|
|
94
|
+
* sources, and any component file in the active render tree. It defers
|
|
95
|
+
* registered script entrypoints to the generic JS strategy and includes /
|
|
96
|
+
* explicit server views to `ServerRenderedTemplateHmrStrategy`.
|
|
97
|
+
*/
|
|
98
|
+
getHmrStrategy() {
|
|
99
|
+
if (!this.hmrManager || !this.appConfig) {
|
|
100
|
+
return void 0;
|
|
101
|
+
}
|
|
102
|
+
const context = this.hmrManager.getDefaultContext();
|
|
103
|
+
const absolutePaths = this.appConfig.absolutePaths;
|
|
104
|
+
return new EcopagesJsxHmrStrategy({
|
|
105
|
+
getWatchedFiles: context.getWatchedFiles,
|
|
106
|
+
getSrcDir: context.getSrcDir,
|
|
107
|
+
getPagesDir: context.getPagesDir,
|
|
108
|
+
getLayoutsDir: context.getLayoutsDir,
|
|
109
|
+
getIncludesDir: () => absolutePaths.includesDir,
|
|
110
|
+
getTemplateExtensions: () => this.extensions
|
|
111
|
+
});
|
|
112
|
+
}
|
|
87
113
|
/**
|
|
88
114
|
* Registers MDX tooling and completes the base integration setup.
|
|
89
115
|
*/
|