@ecopages/ecopages-jsx 0.2.0-beta.31 → 0.2.0-beta.32

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.
@@ -1,283 +1,280 @@
1
- import {
2
- IntegrationRenderer
3
- } from "@ecopages/core/route-renderer/orchestration/integration-renderer";
4
- import {
5
- getForeignSubtreeResolutionContextKey,
6
- resolveOwningIntegrationRenderer
7
- } from "@ecopages/core/route-renderer/orchestration/foreign-child/owning-renderer-resolution";
8
- import { createMarkupNodeLike } from "@ecopages/jsx";
9
- import { renderToString, withServerCustomElementRenderHook } from "@ecopages/jsx/server";
10
- import { ECOPAGES_JSX_PLUGIN_NAME } from "./ecopages-jsx.constants.js";
11
- import {
12
- isMdxFile,
13
- normalizeMdxPageModule
14
- } from "./ecopages-jsx-mdx.js";
15
- import { EcopagesJsxRenderSession } from "./ecopages-jsx-render-session.js";
16
- import { EcopagesJsxRadiantSsrPolicy } from "./ecopages-jsx-radiant-ssr-policy.js";
17
- import { updateEjsxHmrOwnership } from "./ecopages-jsx-hmr-ownership.js";
18
- class EcopagesJsxRenderer extends IntegrationRenderer {
19
- name = ECOPAGES_JSX_PLUGIN_NAME;
20
- mdxExtensions;
21
- renderSession;
22
- radiantSsrPolicy;
23
- /**
24
- * Serializes foreign-child props for string-first boundaries.
25
- *
26
- * @remarks
27
- * DOM nodes become `outerHTML`. JSX trees, arrays, and template results are
28
- * stringified here. Other values are left for core foreign-child interception,
29
- * which rejects opaque plain objects before queueing. Cross-integration
30
- * children must use `EcoEmbed`.
31
- */
32
- normalizeForeignChildProps(props) {
33
- if (!("children" in props)) {
34
- return props;
1
+ import { IntegrationRenderer, } from '@ecopages/core/route-renderer/orchestration/integration-renderer';
2
+ import { getForeignSubtreeResolutionContextKey, resolveOwningIntegrationRenderer, } from '@ecopages/core/route-renderer/orchestration/foreign-child/owning-renderer-resolution';
3
+ import { createMarkupNodeLike } from '@ecopages/jsx';
4
+ import { renderToString, withServerCustomElementRenderHook } from '@ecopages/jsx/server';
5
+ import { ECOPAGES_JSX_PLUGIN_NAME } from './ecopages-jsx.constants.js';
6
+ import { isMdxFile, normalizeMdxPageModule, } from './ecopages-jsx-mdx.js';
7
+ import { EcopagesJsxRenderSession } from './ecopages-jsx-render-session.js';
8
+ import { EcopagesJsxRadiantSsrPolicy } from './ecopages-jsx-radiant-ssr-policy.js';
9
+ import { updateEjsxHmrOwnership } from './ecopages-jsx-hmr-ownership.js';
10
+ /**
11
+ * Local Ecopages renderer for JSX templates in the docs app.
12
+ *
13
+ * This keeps the integration scoped to the docs package while supporting
14
+ * async page, layout, and html template components on the server.
15
+ */
16
+ export class EcopagesJsxRenderer extends IntegrationRenderer {
17
+ name = ECOPAGES_JSX_PLUGIN_NAME;
18
+ mdxExtensions;
19
+ renderSession;
20
+ radiantSsrPolicy;
21
+ /**
22
+ * Serializes foreign-child props for string-first boundaries.
23
+ *
24
+ * @remarks
25
+ * DOM nodes become `outerHTML`. JSX trees, arrays, and template results are
26
+ * stringified here. Other values are left for core foreign-child interception,
27
+ * which rejects opaque plain objects before queueing. Cross-integration
28
+ * children must use `EcoEmbed`.
29
+ */
30
+ normalizeForeignChildProps(props) {
31
+ if (!('children' in props)) {
32
+ return props;
33
+ }
34
+ const children = props.children;
35
+ if (children === undefined || typeof children === 'string') {
36
+ return props;
37
+ }
38
+ if (typeof children === 'object' &&
39
+ children !== null &&
40
+ 'nodeType' in children &&
41
+ typeof children.nodeType === 'number' &&
42
+ 'outerHTML' in children &&
43
+ typeof children.outerHTML === 'string') {
44
+ return {
45
+ ...props,
46
+ children: children.outerHTML,
47
+ };
48
+ }
49
+ if (this.isJsxSerializableForeignChild(children)) {
50
+ return {
51
+ ...props,
52
+ children: renderToString(children),
53
+ };
54
+ }
55
+ return props;
35
56
  }
36
- const children = props.children;
37
- if (children === void 0 || typeof children === "string") {
38
- return props;
57
+ /**
58
+ * Returns whether children are a JSX/template shape this renderer can
59
+ * serialize before foreign-child queueing.
60
+ */
61
+ isJsxSerializableForeignChild(children) {
62
+ if (Array.isArray(children)) {
63
+ return true;
64
+ }
65
+ if (children === null || typeof children !== 'object') {
66
+ return false;
67
+ }
68
+ if ('$$typeof' in children) {
69
+ return true;
70
+ }
71
+ return 'strings' in children && Array.isArray(children.strings);
39
72
  }
40
- if (typeof children === "object" && children !== null && "nodeType" in children && typeof children.nodeType === "number" && "outerHTML" in children && typeof children.outerHTML === "string") {
41
- return {
42
- ...props,
43
- children: children.outerHTML
44
- };
73
+ /**
74
+ * Re-renders queued JSX children inside the owning renderer so nested custom
75
+ * elements and queued foreign subtrees contribute assets to the same frame.
76
+ */
77
+ async renderQueuedForeignSubtreeChildren(children, queuedResolutionsByToken, resolveToken) {
78
+ if (children === undefined) {
79
+ return { assets: [] };
80
+ }
81
+ let assets = [];
82
+ let html;
83
+ if (typeof children === 'string') {
84
+ html = children;
85
+ }
86
+ else {
87
+ const renderedChildren = await this.renderJsx(children);
88
+ html = renderedChildren.html;
89
+ assets = renderedChildren.assets;
90
+ }
91
+ html = await this.foreignSubtreeExecutionService.resolveQueuedTokens(html, queuedResolutionsByToken, resolveToken);
92
+ return {
93
+ assets,
94
+ html,
95
+ };
45
96
  }
46
- if (this.isJsxSerializableForeignChild(children)) {
47
- return {
48
- ...props,
49
- children: renderToString(children)
50
- };
97
+ createForeignChildRuntime(options) {
98
+ const runtime = super.createForeignChildRuntime(options);
99
+ const interceptForeignChild = runtime.interceptForeignChild;
100
+ const interceptForeignChildSync = runtime.interceptForeignChildSync;
101
+ const wrapInput = (input) => ({
102
+ ...input,
103
+ props: input.targetIntegration && input.targetIntegration !== this.name
104
+ ? this.normalizeForeignChildProps(input.props)
105
+ : input.props,
106
+ });
107
+ return {
108
+ interceptForeignChild: interceptForeignChild
109
+ ? (input) => interceptForeignChild(wrapInput(input))
110
+ : undefined,
111
+ interceptForeignChildSync: interceptForeignChildSync
112
+ ? (input) => interceptForeignChildSync(wrapInput(input))
113
+ : undefined,
114
+ };
51
115
  }
52
- return props;
53
- }
54
- /**
55
- * Returns whether children are a JSX/template shape this renderer can
56
- * serialize before foreign-child queueing.
57
- */
58
- isJsxSerializableForeignChild(children) {
59
- if (Array.isArray(children)) {
60
- return true;
116
+ constructor({ appConfig, assetProcessingService, resolvedIntegrationDependencies, jsxConfig, runtimeOrigin, }) {
117
+ super({
118
+ appConfig,
119
+ assetProcessingService,
120
+ resolvedIntegrationDependencies,
121
+ runtimeOrigin,
122
+ });
123
+ this.mdxExtensions = jsxConfig?.mdxExtensions ?? ['.mdx'];
124
+ this.renderSession = new EcopagesJsxRenderSession((assets) => this.htmlTransformer.dedupeProcessedAssets(assets));
125
+ this.radiantSsrPolicy =
126
+ jsxConfig?.radiantSsrPolicy ?? new EcopagesJsxRadiantSsrPolicy(jsxConfig?.radiantSsrEnabled ?? false);
61
127
  }
62
- if (children === null || typeof children !== "object") {
63
- return false;
128
+ /** Returns whether the requested page file should be treated as MDX. */
129
+ isMdxFile(filePath) {
130
+ return isMdxFile(filePath, this.mdxExtensions);
64
131
  }
65
- if ("$$typeof" in children) {
66
- return true;
132
+ async importPageFile(file, options) {
133
+ return await this.withPreparedRadiantRuntime(async () => {
134
+ const module = (await super.importPageFile(file, options));
135
+ return this.isMdxFile(file) ? normalizeMdxPageModule(file, module) : module;
136
+ });
67
137
  }
68
- return "strings" in children && Array.isArray(children.strings);
69
- }
70
- /**
71
- * Re-renders queued JSX children inside the owning renderer so nested custom
72
- * elements and queued foreign subtrees contribute assets to the same frame.
73
- */
74
- async renderQueuedForeignSubtreeChildren(children, queuedResolutionsByToken, resolveToken) {
75
- if (children === void 0) {
76
- return { assets: [] };
138
+ async render(options) {
139
+ return await this.withPreparedRadiantRuntime(() => this.renderSession.withActiveScope(async () => {
140
+ try {
141
+ const result = await this.renderPageWithDocumentShell({
142
+ page: {
143
+ component: options.Page,
144
+ props: {
145
+ ...options.pageProps,
146
+ locals: options.pageLocals,
147
+ },
148
+ },
149
+ layout: options.Layout
150
+ ? {
151
+ component: options.Layout,
152
+ props: {
153
+ ...options.pageProps,
154
+ locals: options.locals,
155
+ },
156
+ }
157
+ : undefined,
158
+ htmlTemplate: options.HtmlTemplate,
159
+ metadata: options.metadata,
160
+ pageProps: options.pageProps ?? {},
161
+ });
162
+ this.recordHmrOwnership([options.Page, options.Layout, options.HtmlTemplate]);
163
+ return result;
164
+ }
165
+ catch (error) {
166
+ throw this.createRenderError('Error rendering page', error);
167
+ }
168
+ }));
77
169
  }
78
- let assets = [];
79
- let html;
80
- if (typeof children === "string") {
81
- html = children;
82
- } else {
83
- const renderedChildren = await this.renderJsx(children);
84
- html = renderedChildren.html;
85
- assets = renderedChildren.assets;
170
+ async renderComponent(input) {
171
+ return await this.withPreparedRadiantRuntime(() => this.renderSession.withActiveScope(async () => {
172
+ const assetFrame = this.renderSession.beginCollectedAssetFrame();
173
+ try {
174
+ if (typeof input.component !== 'function') {
175
+ throw new TypeError('JSX renderer expected a callable component.');
176
+ }
177
+ const component = input.component;
178
+ const componentProps = input.children === undefined
179
+ ? input.props
180
+ : {
181
+ ...input.props,
182
+ children: typeof input.children === 'string'
183
+ ? createMarkupNodeLike(input.children)
184
+ : input.children,
185
+ };
186
+ const content = await this.withCustomElementRenderHook(() => component(componentProps));
187
+ const rendered = await this.renderJsx(content);
188
+ const queuedForeignSubtreeResolution = await this.foreignSubtreeExecutionService.resolveQueuedHtml({
189
+ currentIntegrationName: this.name,
190
+ html: rendered.html,
191
+ runtimeContext: this.foreignSubtreeExecutionService.getQueuedRuntimeContext(input, getForeignSubtreeResolutionContextKey(this.name)),
192
+ queueLabel: 'Ecopages JSX',
193
+ getOwningRenderer: (integrationName, rendererCache) => resolveOwningIntegrationRenderer({
194
+ appConfig: this.appConfig,
195
+ runtimeOrigin: this.runtimeOrigin,
196
+ currentIntegrationName: this.name,
197
+ currentRenderer: this,
198
+ integrationName,
199
+ cache: rendererCache,
200
+ }),
201
+ applyAttributesToFirstElement: (resolvedHtml, attributes) => this.htmlTransformer.applyAttributesToFirstElement(resolvedHtml, attributes),
202
+ dedupeProcessedAssets: (assets) => this.htmlTransformer.dedupeProcessedAssets(assets),
203
+ renderQueuedChildren: (children, _runtimeContext, queuedResolutionsByToken, resolveToken) => this.renderQueuedForeignSubtreeChildren(children, queuedResolutionsByToken, resolveToken),
204
+ });
205
+ const componentAssets = input.component.config?.dependencies &&
206
+ typeof this.assetProcessingService?.processDependencies === 'function'
207
+ ? await this.processComponentDependencies([input.component])
208
+ : [];
209
+ const assets = this.htmlTransformer.dedupeProcessedAssets([
210
+ ...this.renderSession.endCollectedAssetFrame(assetFrame),
211
+ ...queuedForeignSubtreeResolution.assets,
212
+ ...componentAssets,
213
+ ]);
214
+ this.recordHmrOwnership([input.component]);
215
+ return this.finalizeIslandComponentRender(input, {
216
+ html: queuedForeignSubtreeResolution.html,
217
+ canAttachAttributes: true,
218
+ rootTag: this.getRootTagName(queuedForeignSubtreeResolution.html),
219
+ integrationName: this.name,
220
+ assets,
221
+ });
222
+ }
223
+ catch (error) {
224
+ this.renderSession.endCollectedAssetFrame(assetFrame);
225
+ throw this.createRenderError('Error rendering component', error);
226
+ }
227
+ }));
228
+ }
229
+ async renderToResponse(view, props, ctx) {
230
+ return await this.withPreparedRadiantRuntime(() => this.renderSession.withActiveScope(async () => {
231
+ try {
232
+ if (typeof view !== 'function') {
233
+ throw new TypeError('JSX renderer expected a callable view component.');
234
+ }
235
+ const viewComponent = view;
236
+ const layouts = viewComponent.config?.layouts;
237
+ const response = await this.renderViewWithDocumentShell({
238
+ view: viewComponent,
239
+ props: props,
240
+ ctx,
241
+ layout: layouts?.[layouts.length - 1],
242
+ });
243
+ this.recordHmrOwnership([view]);
244
+ return response;
245
+ }
246
+ catch (error) {
247
+ throw this.createRenderError('Error rendering view', error);
248
+ }
249
+ }));
250
+ }
251
+ async renderJsx(value) {
252
+ const collectedAssets = [];
253
+ const html = await this.withCustomElementRenderHook(() => renderToString(value));
254
+ const dedupedAssets = this.renderSession.recordCollectedAssets(collectedAssets);
255
+ return {
256
+ assets: dedupedAssets,
257
+ html,
258
+ };
259
+ }
260
+ async withCustomElementRenderHook(render) {
261
+ return await this.radiantSsrPolicy.withRuntime(() => withServerCustomElementRenderHook(this.createIntrinsicCustomElementRenderHook(), render));
262
+ }
263
+ async withPreparedRadiantRuntime(render) {
264
+ await this.radiantSsrPolicy.prepareRuntime();
265
+ return await render();
266
+ }
267
+ createIntrinsicCustomElementRenderHook() {
268
+ return ({ instance }) => {
269
+ return instance ? this.radiantSsrPolicy.renderIntrinsicElementMarkup(instance) : undefined;
270
+ };
271
+ }
272
+ /**
273
+ * Records the source files that produced the current render so
274
+ * {@link EcopagesJsxHmrStrategy} can match later watcher events without
275
+ * re-walking the component tree.
276
+ */
277
+ recordHmrOwnership(components) {
278
+ updateEjsxHmrOwnership(components);
86
279
  }
87
- html = await this.foreignSubtreeExecutionService.resolveQueuedTokens(
88
- html,
89
- queuedResolutionsByToken,
90
- resolveToken
91
- );
92
- return {
93
- assets,
94
- html
95
- };
96
- }
97
- createForeignChildRuntime(options) {
98
- const runtime = super.createForeignChildRuntime(options);
99
- const interceptForeignChild = runtime.interceptForeignChild;
100
- const interceptForeignChildSync = runtime.interceptForeignChildSync;
101
- const wrapInput = (input) => ({
102
- ...input,
103
- props: input.targetIntegration && input.targetIntegration !== this.name ? this.normalizeForeignChildProps(input.props) : input.props
104
- });
105
- return {
106
- interceptForeignChild: interceptForeignChild ? (input) => interceptForeignChild(wrapInput(input)) : void 0,
107
- interceptForeignChildSync: interceptForeignChildSync ? (input) => interceptForeignChildSync(wrapInput(input)) : void 0
108
- };
109
- }
110
- constructor({
111
- appConfig,
112
- assetProcessingService,
113
- resolvedIntegrationDependencies,
114
- jsxConfig,
115
- runtimeOrigin
116
- }) {
117
- super({
118
- appConfig,
119
- assetProcessingService,
120
- resolvedIntegrationDependencies,
121
- runtimeOrigin
122
- });
123
- this.mdxExtensions = jsxConfig?.mdxExtensions ?? [".mdx"];
124
- this.renderSession = new EcopagesJsxRenderSession(
125
- (assets) => this.htmlTransformer.dedupeProcessedAssets(assets)
126
- );
127
- this.radiantSsrPolicy = jsxConfig?.radiantSsrPolicy ?? new EcopagesJsxRadiantSsrPolicy(jsxConfig?.radiantSsrEnabled ?? false);
128
- }
129
- /** Returns whether the requested page file should be treated as MDX. */
130
- isMdxFile(filePath) {
131
- return isMdxFile(filePath, this.mdxExtensions);
132
- }
133
- async importPageFile(file, options) {
134
- return await this.withPreparedRadiantRuntime(async () => {
135
- const module = await super.importPageFile(file, options);
136
- return this.isMdxFile(file) ? normalizeMdxPageModule(file, module) : module;
137
- });
138
- }
139
- async render(options) {
140
- return await this.withPreparedRadiantRuntime(
141
- () => this.renderSession.withActiveScope(async () => {
142
- try {
143
- const result = await this.renderPageWithDocumentShell({
144
- page: {
145
- component: options.Page,
146
- props: {
147
- ...options.pageProps,
148
- locals: options.pageLocals
149
- }
150
- },
151
- layout: options.Layout ? {
152
- component: options.Layout,
153
- props: {
154
- ...options.pageProps,
155
- locals: options.locals
156
- }
157
- } : void 0,
158
- htmlTemplate: options.HtmlTemplate,
159
- metadata: options.metadata,
160
- pageProps: options.pageProps ?? {}
161
- });
162
- this.recordHmrOwnership([options.Page, options.Layout, options.HtmlTemplate]);
163
- return result;
164
- } catch (error) {
165
- throw this.createRenderError("Error rendering page", error);
166
- }
167
- })
168
- );
169
- }
170
- async renderComponent(input) {
171
- return await this.withPreparedRadiantRuntime(
172
- () => this.renderSession.withActiveScope(async () => {
173
- const assetFrame = this.renderSession.beginCollectedAssetFrame();
174
- try {
175
- if (typeof input.component !== "function") {
176
- throw new TypeError("JSX renderer expected a callable component.");
177
- }
178
- const component = input.component;
179
- const componentProps = input.children === void 0 ? input.props : {
180
- ...input.props,
181
- children: typeof input.children === "string" ? createMarkupNodeLike(input.children) : input.children
182
- };
183
- const content = await this.withCustomElementRenderHook(() => component(componentProps));
184
- const rendered = await this.renderJsx(content);
185
- const queuedForeignSubtreeResolution = await this.foreignSubtreeExecutionService.resolveQueuedHtml({
186
- currentIntegrationName: this.name,
187
- html: rendered.html,
188
- runtimeContext: this.foreignSubtreeExecutionService.getQueuedRuntimeContext(
189
- input,
190
- getForeignSubtreeResolutionContextKey(this.name)
191
- ),
192
- queueLabel: "Ecopages JSX",
193
- getOwningRenderer: (integrationName, rendererCache) => resolveOwningIntegrationRenderer({
194
- appConfig: this.appConfig,
195
- runtimeOrigin: this.runtimeOrigin,
196
- currentIntegrationName: this.name,
197
- currentRenderer: this,
198
- integrationName,
199
- cache: rendererCache
200
- }),
201
- applyAttributesToFirstElement: (resolvedHtml, attributes) => this.htmlTransformer.applyAttributesToFirstElement(resolvedHtml, attributes),
202
- dedupeProcessedAssets: (assets2) => this.htmlTransformer.dedupeProcessedAssets(assets2),
203
- renderQueuedChildren: (children, _runtimeContext, queuedResolutionsByToken, resolveToken) => this.renderQueuedForeignSubtreeChildren(children, queuedResolutionsByToken, resolveToken)
204
- });
205
- const componentAssets = input.component.config?.dependencies && typeof this.assetProcessingService?.processDependencies === "function" ? await this.processComponentDependencies([input.component]) : [];
206
- const assets = this.htmlTransformer.dedupeProcessedAssets([
207
- ...this.renderSession.endCollectedAssetFrame(assetFrame),
208
- ...queuedForeignSubtreeResolution.assets,
209
- ...componentAssets
210
- ]);
211
- this.recordHmrOwnership([input.component]);
212
- return {
213
- html: queuedForeignSubtreeResolution.html,
214
- canAttachAttributes: true,
215
- rootTag: this.getRootTagName(queuedForeignSubtreeResolution.html),
216
- integrationName: this.name,
217
- assets
218
- };
219
- } catch (error) {
220
- this.renderSession.endCollectedAssetFrame(assetFrame);
221
- throw this.createRenderError("Error rendering component", error);
222
- }
223
- })
224
- );
225
- }
226
- async renderToResponse(view, props, ctx) {
227
- return await this.withPreparedRadiantRuntime(
228
- () => this.renderSession.withActiveScope(async () => {
229
- try {
230
- if (typeof view !== "function") {
231
- throw new TypeError("JSX renderer expected a callable view component.");
232
- }
233
- const viewComponent = view;
234
- const layouts = viewComponent.config?.layouts;
235
- const response = await this.renderViewWithDocumentShell({
236
- view: viewComponent,
237
- props,
238
- ctx,
239
- layout: layouts?.[layouts.length - 1]
240
- });
241
- this.recordHmrOwnership([view]);
242
- return response;
243
- } catch (error) {
244
- throw this.createRenderError("Error rendering view", error);
245
- }
246
- })
247
- );
248
- }
249
- async renderJsx(value) {
250
- const collectedAssets = [];
251
- const html = await this.withCustomElementRenderHook(() => renderToString(value));
252
- const dedupedAssets = this.renderSession.recordCollectedAssets(collectedAssets);
253
- return {
254
- assets: dedupedAssets,
255
- html
256
- };
257
- }
258
- async withCustomElementRenderHook(render) {
259
- return await this.radiantSsrPolicy.withRuntime(
260
- () => withServerCustomElementRenderHook(this.createIntrinsicCustomElementRenderHook(), render)
261
- );
262
- }
263
- async withPreparedRadiantRuntime(render) {
264
- await this.radiantSsrPolicy.prepareRuntime();
265
- return await render();
266
- }
267
- createIntrinsicCustomElementRenderHook() {
268
- return ({ instance }) => {
269
- return instance ? this.radiantSsrPolicy.renderIntrinsicElementMarkup(instance) : void 0;
270
- };
271
- }
272
- /**
273
- * Records the source files that produced the current render so
274
- * {@link EcopagesJsxHmrStrategy} can match later watcher events without
275
- * re-walking the component tree.
276
- */
277
- recordHmrOwnership(components) {
278
- updateEjsxHmrOwnership(components);
279
- }
280
280
  }
281
- export {
282
- EcopagesJsxRenderer
283
- };
@@ -1,4 +1,7 @@
1
- const ECOPAGES_JSX_PLUGIN_NAME = "ecopages-jsx";
2
- export {
3
- ECOPAGES_JSX_PLUGIN_NAME
4
- };
1
+ /**
2
+ * Stable integration name shared by the JSX plugin and renderer.
3
+ *
4
+ * Ecopages uses this identifier to match route files, renderer instances, and
5
+ * cross-integration component boundaries.
6
+ */
7
+ export const ECOPAGES_JSX_PLUGIN_NAME = 'ecopages-jsx';
@@ -26,7 +26,7 @@ export declare class EcopagesJsxPlugin extends IntegrationPlugin<JsxRenderable>
26
26
  prepareBuildContributions(): Promise<void>;
27
27
  /** Assigns grouped-build metadata for page-owned JSX content scripts. */
28
28
  prepareAssetDependencies(dependencies: AssetDefinition[]): AssetDefinition[];
29
- /** Registers JSX HMR strategy and Radiant SSR invalidation hooks. */
29
+ /** Registers JSX HMR strategy, dev-transform plugins, and Radiant SSR invalidation hooks. */
30
30
  setHmrManager(hmrManager: IHmrManager): void;
31
31
  /**
32
32
  * Returns the JSX-integration HMR strategy.