@ecopages/ecopages-jsx 0.2.0-alpha.37 → 0.2.0-alpha.39

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ecopages/ecopages-jsx",
3
- "version": "0.2.0-alpha.37",
3
+ "version": "0.2.0-alpha.39",
4
4
  "description": "JSX integration plugin for Ecopages",
5
5
  "keywords": [
6
6
  "ecopages",
@@ -11,6 +11,20 @@
11
11
  "main": "./src/ecopages-jsx.plugin.js",
12
12
  "types": "./src/ecopages-jsx.plugin.d.ts",
13
13
  "type": "module",
14
+ "exports": {
15
+ ".": {
16
+ "default": "./src/ecopages-jsx.plugin.js",
17
+ "types": "./src/ecopages-jsx.plugin.d.ts"
18
+ },
19
+ "./eco-embed": {
20
+ "default": "./src/eco-embed.js",
21
+ "types": "./src/eco-embed.d.ts"
22
+ },
23
+ "./eco-embed.ts": {
24
+ "default": "./src/eco-embed.js",
25
+ "types": "./src/eco-embed.d.ts"
26
+ }
27
+ },
14
28
  "repository": {
15
29
  "type": "git",
16
30
  "url": "https://github.com/ecopages/ecopages.git",
@@ -21,8 +35,8 @@
21
35
  "vfile": "^6.0.3"
22
36
  },
23
37
  "peerDependencies": {
24
- "@ecopages/core": "0.2.0-alpha.34",
25
- "@ecopages/jsx": "0.3.0-alpha.24",
26
- "@ecopages/radiant": "0.3.0-alpha.24"
38
+ "@ecopages/core": "0.2.0-alpha.39",
39
+ "@ecopages/jsx": "0.3.0-alpha.25",
40
+ "@ecopages/radiant": "0.3.0-alpha.25"
27
41
  }
28
42
  }
@@ -0,0 +1,11 @@
1
+ import type { EcoComponent, EcoEmbedProps as CoreEcoEmbedProps } from '@ecopages/core';
2
+ import type { JsxRenderable } from '@ecopages/jsx';
3
+ /**
4
+ * Props for the Ecopages JSX-owned `EcoEmbed` adapter.
5
+ */
6
+ export type EcoEmbedProps<TComponent extends EcoComponent> = CoreEcoEmbedProps<TComponent>;
7
+ /**
8
+ * Renders a foreign or same-integration eco component from an Ecopages JSX
9
+ * file without forcing inline mixed-JSX authoring.
10
+ */
11
+ export declare function EcoEmbed<TComponent extends EcoComponent>({ component, props, children, }: EcoEmbedProps<TComponent>): JsxRenderable;
@@ -0,0 +1,11 @@
1
+ import { eco } from "@ecopages/core";
2
+ function EcoEmbed({
3
+ component,
4
+ props,
5
+ children
6
+ }) {
7
+ return eco.embed(component, props, children);
8
+ }
9
+ export {
10
+ EcoEmbed
11
+ };
@@ -21,7 +21,6 @@ export declare class EcopagesJsxRadiantSsrPolicy {
21
21
  * Runs one render inside Radiant's server runtime when the policy is enabled.
22
22
  */
23
23
  withRuntime<T>(render: () => T): Promise<T>;
24
- withPreparedRuntime<T>(render: () => T): T;
25
24
  /**
26
25
  * Converts one Radiant custom-element instance into trusted SSR markup.
27
26
  *
@@ -1,7 +1,6 @@
1
1
  import { createMarkupNodeLike } from "@ecopages/jsx";
2
2
  import {
3
3
  createServerHydrationBindingState,
4
- isServerRenderHydrationActive,
5
4
  withServerHydrationBindingState
6
5
  } from "@ecopages/jsx/server";
7
6
  class EcopagesJsxRadiantSsrPolicy {
@@ -33,16 +32,6 @@ class EcopagesJsxRadiantSsrPolicy {
33
32
  }
34
33
  return runtimeModules.withServerRadiantElementSsrRuntime(render);
35
34
  }
36
- withPreparedRuntime(render) {
37
- if (!this.enabled) {
38
- return render();
39
- }
40
- const runtimeModules = EcopagesJsxRadiantSsrPolicy.runtimeModules;
41
- if (!runtimeModules) {
42
- return render();
43
- }
44
- return runtimeModules.withServerRadiantElementSsrRuntime(render);
45
- }
46
35
  /**
47
36
  * Converts one Radiant custom-element instance into trusted SSR markup.
48
37
  *
@@ -59,7 +48,7 @@ class EcopagesJsxRadiantSsrPolicy {
59
48
  withServerHydrationBindingState(
60
49
  createServerHydrationBindingState(),
61
50
  () => renderBridge.renderHostToString({
62
- mode: isServerRenderHydrationActive() ? "hydrate" : "plain"
51
+ mode: "hydrate"
63
52
  })
64
53
  )
65
54
  );
@@ -42,5 +42,6 @@ export declare class EcopagesJsxRenderer extends IntegrationRenderer<JsxRenderab
42
42
  renderToResponse<P = any>(view: EcoComponent<P>, props: P, ctx: RenderToResponseContext): Promise<Response>;
43
43
  private renderJsx;
44
44
  private withCustomElementRenderHook;
45
+ private withPreparedRadiantRuntime;
45
46
  private createIntrinsicCustomElementRenderHook;
46
47
  }
@@ -116,118 +116,120 @@ class EcopagesJsxRenderer extends IntegrationRenderer {
116
116
  return isMdxFile(filePath, this.mdxExtensions);
117
117
  }
118
118
  async importPageFile(file, options) {
119
- await this.radiantSsrPolicy.prepareRuntime();
120
- const module = await super.importPageFile(file, options);
121
- return this.isMdxFile(file) ? normalizeMdxPageModule(file, module) : module;
119
+ return await this.withPreparedRadiantRuntime(async () => {
120
+ const module = await super.importPageFile(file, options);
121
+ return this.isMdxFile(file) ? normalizeMdxPageModule(file, module) : module;
122
+ });
122
123
  }
123
124
  async render(options) {
124
- await this.radiantSsrPolicy.prepareRuntime();
125
- return await this.renderSession.withActiveScope(async () => {
126
- try {
127
- return await this.renderPageWithDocumentShell({
128
- page: {
129
- component: options.Page,
130
- props: {
131
- ...options.pageProps,
132
- locals: options.pageLocals
133
- }
134
- },
135
- layout: options.Layout ? {
136
- component: options.Layout,
137
- props: {
138
- ...options.pageProps,
139
- locals: options.locals
140
- }
141
- } : void 0,
142
- htmlTemplate: options.HtmlTemplate,
143
- metadata: options.metadata,
144
- pageProps: options.pageProps ?? {}
145
- });
146
- } catch (error) {
147
- throw this.createRenderError("Error rendering page", error);
148
- }
149
- });
125
+ return await this.withPreparedRadiantRuntime(
126
+ () => this.renderSession.withActiveScope(async () => {
127
+ try {
128
+ return await this.renderPageWithDocumentShell({
129
+ page: {
130
+ component: options.Page,
131
+ props: {
132
+ ...options.pageProps,
133
+ locals: options.pageLocals
134
+ }
135
+ },
136
+ layout: options.Layout ? {
137
+ component: options.Layout,
138
+ props: {
139
+ ...options.pageProps,
140
+ locals: options.locals
141
+ }
142
+ } : void 0,
143
+ htmlTemplate: options.HtmlTemplate,
144
+ metadata: options.metadata,
145
+ pageProps: options.pageProps ?? {}
146
+ });
147
+ } catch (error) {
148
+ throw this.createRenderError("Error rendering page", error);
149
+ }
150
+ })
151
+ );
150
152
  }
151
153
  async renderComponent(input) {
152
- await this.radiantSsrPolicy.prepareRuntime();
153
- return await this.renderSession.withActiveScope(async () => {
154
- const assetFrame = this.renderSession.beginCollectedAssetFrame();
155
- try {
156
- if (typeof input.component !== "function") {
157
- throw new TypeError("JSX renderer expected a callable component.");
154
+ return await this.withPreparedRadiantRuntime(
155
+ () => this.renderSession.withActiveScope(async () => {
156
+ const assetFrame = this.renderSession.beginCollectedAssetFrame();
157
+ try {
158
+ if (typeof input.component !== "function") {
159
+ throw new TypeError("JSX renderer expected a callable component.");
160
+ }
161
+ const component = input.component;
162
+ const componentProps = input.children === void 0 ? input.props : {
163
+ ...input.props,
164
+ children: typeof input.children === "string" ? createMarkupNodeLike(input.children) : input.children
165
+ };
166
+ const content = await this.withCustomElementRenderHook(() => component(componentProps));
167
+ const rendered = await this.renderJsx(content);
168
+ const queuedForeignSubtreeResolution = await this.resolveOwnedForeignSubtreeHtml(
169
+ rendered.html,
170
+ this.getQueuedForeignSubtreeResolutionContext(
171
+ input
172
+ )
173
+ );
174
+ const componentAssets = input.component.config?.dependencies && typeof this.assetProcessingService?.processDependencies === "function" ? await this.processComponentDependencies([input.component]) : [];
175
+ const assets = this.htmlTransformer.dedupeProcessedAssets([
176
+ ...this.renderSession.endCollectedAssetFrame(assetFrame),
177
+ ...queuedForeignSubtreeResolution.assets,
178
+ ...componentAssets
179
+ ]);
180
+ return {
181
+ html: queuedForeignSubtreeResolution.html,
182
+ canAttachAttributes: true,
183
+ rootTag: this.getRootTagName(queuedForeignSubtreeResolution.html),
184
+ integrationName: this.name,
185
+ assets
186
+ };
187
+ } catch (error) {
188
+ this.renderSession.endCollectedAssetFrame(assetFrame);
189
+ throw this.createRenderError("Error rendering component", error);
158
190
  }
159
- const component = input.component;
160
- const componentProps = input.children === void 0 ? input.props : {
161
- ...input.props,
162
- children: typeof input.children === "string" ? createMarkupNodeLike(input.children) : input.children
163
- };
164
- const componentAssetsFromRender = [];
165
- const content = await this.withCustomElementRenderHook(
166
- componentAssetsFromRender,
167
- () => component(componentProps)
168
- );
169
- this.renderSession.recordCollectedAssets(componentAssetsFromRender);
170
- const rendered = await this.renderJsx(content);
171
- const queuedForeignSubtreeResolution = await this.resolveOwnedForeignSubtreeHtml(
172
- rendered.html,
173
- this.getQueuedForeignSubtreeResolutionContext(input)
174
- );
175
- const componentAssets = input.component.config?.dependencies && typeof this.assetProcessingService?.processDependencies === "function" ? await this.processComponentDependencies([input.component]) : [];
176
- const assets = this.htmlTransformer.dedupeProcessedAssets([
177
- ...this.renderSession.endCollectedAssetFrame(assetFrame),
178
- ...queuedForeignSubtreeResolution.assets,
179
- ...componentAssets
180
- ]);
181
- return {
182
- html: queuedForeignSubtreeResolution.html,
183
- canAttachAttributes: true,
184
- rootTag: this.getRootTagName(queuedForeignSubtreeResolution.html),
185
- integrationName: this.name,
186
- assets
187
- };
188
- } catch (error) {
189
- this.renderSession.endCollectedAssetFrame(assetFrame);
190
- throw this.createRenderError("Error rendering component", error);
191
- }
192
- });
191
+ })
192
+ );
193
193
  }
194
194
  async renderToResponse(view, props, ctx) {
195
- await this.radiantSsrPolicy.prepareRuntime();
196
- return await this.renderSession.withActiveScope(async () => {
197
- try {
198
- if (typeof view !== "function") {
199
- throw new TypeError("JSX renderer expected a callable view component.");
195
+ return await this.withPreparedRadiantRuntime(
196
+ () => this.renderSession.withActiveScope(async () => {
197
+ try {
198
+ if (typeof view !== "function") {
199
+ throw new TypeError("JSX renderer expected a callable view component.");
200
+ }
201
+ const viewComponent = view;
202
+ return await this.renderViewWithDocumentShell({
203
+ view: viewComponent,
204
+ props,
205
+ ctx,
206
+ layout: viewComponent.config?.layout
207
+ });
208
+ } catch (error) {
209
+ throw this.createRenderError("Error rendering view", error);
200
210
  }
201
- const viewComponent = view;
202
- return await this.renderViewWithDocumentShell({
203
- view: viewComponent,
204
- props,
205
- ctx,
206
- layout: viewComponent.config?.layout
207
- });
208
- } catch (error) {
209
- throw this.createRenderError("Error rendering view", error);
210
- }
211
- });
211
+ })
212
+ );
212
213
  }
213
214
  async renderJsx(value) {
214
215
  const collectedAssets = [];
215
- const html = await this.renderSession.withHydrationBindingScope(
216
- () => this.withCustomElementRenderHook(collectedAssets, () => renderToString(value, { mode: "hydrate" }))
217
- );
216
+ const html = await this.withCustomElementRenderHook(() => renderToString(value));
218
217
  const dedupedAssets = this.renderSession.recordCollectedAssets(collectedAssets);
219
218
  return {
220
219
  assets: dedupedAssets,
221
220
  html
222
221
  };
223
222
  }
224
- async withCustomElementRenderHook(target, render) {
225
- await this.radiantSsrPolicy.prepareRuntime();
223
+ async withCustomElementRenderHook(render) {
226
224
  return await this.radiantSsrPolicy.withRuntime(
227
- () => withServerCustomElementRenderHook(this.createIntrinsicCustomElementRenderHook(target), render)
225
+ () => withServerCustomElementRenderHook(this.createIntrinsicCustomElementRenderHook(), render)
228
226
  );
229
227
  }
230
- createIntrinsicCustomElementRenderHook(_target) {
228
+ async withPreparedRadiantRuntime(render) {
229
+ await this.radiantSsrPolicy.prepareRuntime();
230
+ return await render();
231
+ }
232
+ createIntrinsicCustomElementRenderHook() {
231
233
  return ({ instance }) => {
232
234
  return instance ? this.radiantSsrPolicy.renderIntrinsicElementMarkup(instance) : void 0;
233
235
  };
@@ -18,6 +18,7 @@ export declare class EcopagesJsxPlugin extends IntegrationPlugin<JsxRenderable>
18
18
  rendererModules?: unknown;
19
19
  }): EcopagesJsxRenderer;
20
20
  constructor(options?: EcopagesJsxPluginOptions);
21
+ private getDependencies;
21
22
  /** Ensures MDX build hooks are ready before Ecopages collects contributions. */
22
23
  prepareBuildContributions(): Promise<void>;
23
24
  /**
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  IntegrationPlugin
3
3
  } from "@ecopages/core/plugins/integration-plugin";
4
+ import { AssetFactory } from "@ecopages/core/services/asset-processing-service";
4
5
  import { ECOPAGES_JSX_PLUGIN_NAME } from "./ecopages-jsx.constants.js";
5
6
  import {
6
7
  appendMdxExtensions,
@@ -9,6 +10,7 @@ import {
9
10
  resolveMdxCompilerOptions
10
11
  } from "./ecopages-jsx-mdx.js";
11
12
  import { EcopagesJsxRenderer } from "./ecopages-jsx-renderer.js";
13
+ const RADIANT_HYDRATOR_SCRIPT_ID = "ecopages-jsx-radiant-hydrator";
12
14
  const resolvePluginOptions = (options) => {
13
15
  const { extensions: userExtensions, radiant, mdx, ...baseConfig } = options ?? {};
14
16
  const extensions = [...userExtensions ?? [".tsx"]];
@@ -62,6 +64,21 @@ class EcopagesJsxPlugin extends IntegrationPlugin {
62
64
  this.mdxEnabled = mdxEnabled;
63
65
  this.mdxExtensions = mdxExtensions;
64
66
  this.mdxCompilerOptions = mdxCompilerOptions;
67
+ if (this.includeRadiant) {
68
+ this.integrationDependencies.unshift(...this.getDependencies());
69
+ }
70
+ }
71
+ getDependencies() {
72
+ return [
73
+ AssetFactory.createNodeModuleScript({
74
+ position: "head",
75
+ importPath: "@ecopages/radiant/client/install-hydrator",
76
+ bundle: false,
77
+ attributes: {
78
+ "data-eco-script-id": RADIANT_HYDRATOR_SCRIPT_ID
79
+ }
80
+ })
81
+ ];
65
82
  }
66
83
  /** Ensures MDX build hooks are ready before Ecopages collects contributions. */
67
84
  async prepareBuildContributions() {