@ecopages/ecopages-jsx 0.2.1 → 0.3.1
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 +69 -23
- package/package.json +25 -6
- package/src/dev-transform/ecopages-jsx-dev-transform-contributor.d.ts +17 -0
- package/src/dev-transform/ecopages-jsx-dev-transform-contributor.js +21 -0
- package/src/eco-embed.d.ts +11 -0
- package/src/eco-embed.js +9 -0
- package/src/ecopages-jsx-hmr-ownership.d.ts +43 -0
- package/src/ecopages-jsx-hmr-ownership.js +91 -0
- package/src/ecopages-jsx-hmr-strategy.d.ts +19 -0
- package/src/ecopages-jsx-hmr-strategy.js +67 -0
- package/src/ecopages-jsx-mdx.d.ts +32 -0
- package/src/ecopages-jsx-mdx.js +48 -0
- package/src/ecopages-jsx-radiant-ssr-policy.d.ts +39 -0
- package/src/ecopages-jsx-radiant-ssr-policy.js +122 -0
- package/src/ecopages-jsx-renderer.d.ts +10 -52
- package/src/ecopages-jsx-renderer.js +143 -251
- package/src/ecopages-jsx.constants.d.ts +7 -0
- package/src/ecopages-jsx.constants.js +7 -0
- package/src/ecopages-jsx.plugin.d.ts +21 -93
- package/src/ecopages-jsx.plugin.js +135 -237
- package/src/ecopages-jsx.types.d.ts +32 -0
- package/src/ecopages-jsx.types.js +1 -0
- package/src/page-owned-content-script-grouping.d.ts +11 -0
- package/src/page-owned-content-script-grouping.js +57 -0
- package/src/radiant-registered-script-ssr-invalidation.d.ts +19 -0
- package/src/radiant-registered-script-ssr-invalidation.js +49 -0
- package/src/resolve-radiant-install-hydrator.d.ts +2 -0
- package/src/resolve-radiant-install-hydrator.js +3 -0
- package/CHANGELOG.md +0 -15
- package/src/services/jsx-runtime-bundle.service.d.ts +0 -51
- package/src/services/jsx-runtime-bundle.service.js +0 -206
|
@@ -1,108 +1,36 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import type
|
|
3
|
-
import { IntegrationPlugin, type IntegrationPluginConfig } from '@ecopages/core/plugins/integration-plugin';
|
|
1
|
+
import { IntegrationPlugin, type IntegrationRendererBase, type IntegrationRuntimeContext, type EcoBuildPlugin } from '@ecopages/core/integration';
|
|
2
|
+
import { type AssetDefinition } from '@ecopages/core/integration';
|
|
4
3
|
import type { JsxRenderable } from '@ecopages/jsx';
|
|
5
4
|
import { EcopagesJsxRenderer } from './ecopages-jsx-renderer.js';
|
|
6
|
-
type
|
|
7
|
-
type
|
|
8
|
-
remarkPlugins?: MdxPluginList;
|
|
9
|
-
rehypePlugins?: MdxPluginList;
|
|
10
|
-
recmaPlugins?: MdxPluginList;
|
|
11
|
-
};
|
|
12
|
-
/**
|
|
13
|
-
* Stable integration name shared by the JSX plugin and renderer.
|
|
14
|
-
*
|
|
15
|
-
* Ecopages uses this identifier to match route files, renderer instances, and
|
|
16
|
-
* cross-integration component boundaries.
|
|
17
|
-
*/
|
|
18
|
-
export declare const ECOPAGES_JSX_PLUGIN_NAME = "ecopages-jsx";
|
|
19
|
-
/**
|
|
20
|
-
* MDX configuration for the JSX integration.
|
|
21
|
-
*
|
|
22
|
-
* Mirrors Ecopages' built-in combined integration pattern where a single
|
|
23
|
-
* JSX-capable plugin can own both `.tsx` and `.mdx` route files.
|
|
24
|
-
*/
|
|
25
|
-
export type EcopagesJsxMdxOptions = {
|
|
26
|
-
/** Enables MDX file handling inside the JSX integration. */
|
|
27
|
-
enabled: boolean;
|
|
28
|
-
/** Additional MDX compiler options. JSX runtime fields are managed by the integration. */
|
|
29
|
-
compilerOptions?: MdxCompileOptions;
|
|
30
|
-
/** Extra remark plugins appended to `compilerOptions.remarkPlugins`. */
|
|
31
|
-
remarkPlugins?: MdxPluginList;
|
|
32
|
-
/** Extra rehype plugins appended to `compilerOptions.rehypePlugins`. */
|
|
33
|
-
rehypePlugins?: MdxPluginList;
|
|
34
|
-
/** Extra recma plugins appended to `compilerOptions.recmaPlugins`. */
|
|
35
|
-
recmaPlugins?: MdxPluginList;
|
|
36
|
-
/** Custom file extensions to treat as MDX. */
|
|
37
|
-
extensions?: string[];
|
|
38
|
-
};
|
|
39
|
-
/** Options for the JSX integration plugin. */
|
|
40
|
-
export type EcopagesJsxPluginOptions = Omit<IntegrationPluginConfig, 'name' | 'extensions'> & {
|
|
41
|
-
/** Optional JSX route extensions. Defaults to `.tsx`. */
|
|
42
|
-
extensions?: string[];
|
|
43
|
-
/**
|
|
44
|
-
* Whether to include the `@ecopages/radiant` and `@ecopages/signals` vendor
|
|
45
|
-
* bundles and bare-specifier mappings.
|
|
46
|
-
*
|
|
47
|
-
* Set to `false` when pages do not use Radiant web components.
|
|
48
|
-
* @default true
|
|
49
|
-
*/
|
|
50
|
-
radiant?: boolean;
|
|
51
|
-
/** Optional MDX integration configuration. */
|
|
52
|
-
mdx?: EcopagesJsxMdxOptions;
|
|
53
|
-
};
|
|
5
|
+
import type { EcopagesJsxPluginOptions } from './ecopages-jsx.types.js';
|
|
6
|
+
export type { EcopagesJsxMdxOptions, EcopagesJsxPluginOptions, EcopagesJsxRendererConfig, } from './ecopages-jsx.types.js';
|
|
54
7
|
/** JSX integration plugin for Ecopages, supporting `.tsx` templates and optional Radiant web components. */
|
|
55
8
|
export declare class EcopagesJsxPlugin extends IntegrationPlugin<JsxRenderable> {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
9
|
+
renderer: new (options: import("@ecopages/core/integration").IntegrationRendererOptions) => import("@ecopages/core/integration").IntegrationRenderer<JsxRenderable> & {
|
|
10
|
+
name: string;
|
|
11
|
+
};
|
|
12
|
+
readonly bundlesPageDependencies = true;
|
|
59
13
|
private includeRadiant;
|
|
60
|
-
private mdxEnabled;
|
|
61
14
|
private mdxCompilerOptions?;
|
|
62
15
|
private mdxExtensions;
|
|
63
|
-
private mdxLoaderPlugin?;
|
|
64
|
-
private runtimeBundleService;
|
|
65
|
-
private runtimeSpecifierMap;
|
|
66
|
-
private runtimeDepsInitialized;
|
|
67
|
-
/** Returns the build plugins required by the JSX integration. */
|
|
68
|
-
get plugins(): EcoBuildPlugin[];
|
|
69
|
-
/** Returns the browser-only build plugins required by the JSX integration. */
|
|
70
|
-
get browserBuildPlugins(): EcoBuildPlugin[];
|
|
71
16
|
/**
|
|
72
|
-
*
|
|
17
|
+
* Returns the build plugins required by the JSX integration.
|
|
73
18
|
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
|
|
77
|
-
getRuntimeSpecifierMap(): Record<string, string>;
|
|
78
|
-
/**
|
|
79
|
-
* Creates the renderer instance and attaches the discovered intrinsic custom
|
|
80
|
-
* element assets before the renderer handles any requests.
|
|
81
|
-
*/
|
|
82
|
-
initializeRenderer(): EcopagesJsxRenderer;
|
|
83
|
-
/**
|
|
84
|
-
* Creates a JSX integration plugin.
|
|
85
|
-
*
|
|
86
|
-
* When MDX is enabled, the plugin also claims the configured MDX extensions
|
|
87
|
-
* and prepares compiler options around the shared `@ecopages/jsx` runtime.
|
|
19
|
+
* @remarks
|
|
20
|
+
* Returns a new loader declaration without registering or initializing it. The build manifest owns the
|
|
21
|
+
* resulting instance for the app runtime.
|
|
88
22
|
*/
|
|
23
|
+
plugins(app: IntegrationRuntimeContext['appConfig']): EcoBuildPlugin[];
|
|
24
|
+
/** Creates the renderer instance with the resolved JSX integration runtime options. */
|
|
25
|
+
createRenderer(base: IntegrationRendererBase): EcopagesJsxRenderer;
|
|
89
26
|
constructor(options?: EcopagesJsxPluginOptions);
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
*/
|
|
96
|
-
setup(): Promise<void>;
|
|
97
|
-
private ensureMdxLoaderPlugin;
|
|
98
|
-
private setupMdxBunPlugin;
|
|
99
|
-
private buildIntrinsicCustomElementAssetRegistry;
|
|
100
|
-
private collectScriptEntryFiles;
|
|
101
|
-
private resolveIntrinsicCustomElementAsset;
|
|
102
|
-
private extractIntrinsicCustomElementTagNames;
|
|
27
|
+
private getDependencies;
|
|
28
|
+
/** Assigns grouped-build metadata for page-owned JSX content scripts. */
|
|
29
|
+
prepareAssetDependencies(dependencies: AssetDefinition[]): AssetDefinition[];
|
|
30
|
+
/** Registers JSX HMR strategy, dev-transform plugins, and Radiant SSR invalidation hooks. */
|
|
31
|
+
hmr(context: IntegrationRuntimeContext): void;
|
|
103
32
|
}
|
|
104
33
|
/**
|
|
105
|
-
* Creates the JSX integration plugin.
|
|
34
|
+
* Creates the JSX integration plugin with resolved defaults.
|
|
106
35
|
*/
|
|
107
36
|
export declare const ecopagesJsxPlugin: (options?: EcopagesJsxPluginOptions) => EcopagesJsxPlugin;
|
|
108
|
-
export {};
|
|
@@ -1,248 +1,146 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
};
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
});
|
|
1
|
+
import { IntegrationPlugin, } from '@ecopages/core/integration';
|
|
2
|
+
import { AssetFactory } from '@ecopages/core/integration';
|
|
3
|
+
import { requireAppRuntime } from '@ecopages/core/integration';
|
|
4
|
+
import { ECOPAGES_JSX_PLUGIN_NAME } from './ecopages-jsx.constants.js';
|
|
5
|
+
import { RADIANT_INSTALL_HYDRATOR_FILEPATH } from './resolve-radiant-install-hydrator.js';
|
|
6
|
+
import { appendMdxExtensions, createMdxLoaderPlugin, resolveMdxCompilerOptions, } from './ecopages-jsx-mdx.js';
|
|
7
|
+
import { createEcopagesJsxRenderer, createEcopagesJsxRendererHookFactory, EcopagesJsxRenderer, } from './ecopages-jsx-renderer.js';
|
|
8
|
+
import { EcopagesJsxHmrStrategy } from './ecopages-jsx-hmr-strategy.js';
|
|
9
|
+
import { EcopagesJsxDevTransformContributor } from './dev-transform/ecopages-jsx-dev-transform-contributor.js';
|
|
10
|
+
import { assignPageOwnedContentScriptGroupedBundles } from './page-owned-content-script-grouping.js';
|
|
11
|
+
import { invalidateRadiantRegisteredScriptSsrRegistration } from './radiant-registered-script-ssr-invalidation.js';
|
|
12
|
+
const RADIANT_HYDRATOR_SCRIPT_ID = 'ecopages-jsx-radiant-hydrator';
|
|
13
|
+
/**
|
|
14
|
+
* Resolves user-facing plugin options into a fully-defaulted internal config.
|
|
15
|
+
*
|
|
16
|
+
* Defaults:
|
|
17
|
+
* - `extensions`: `['.tsx']`
|
|
18
|
+
* - `radiant`: `true`
|
|
19
|
+
* - MDX is disabled when `mdx` is omitted
|
|
20
|
+
* - `mdx.extensions`: `['.mdx']`
|
|
21
|
+
*/
|
|
22
|
+
const resolvePluginOptions = (options) => {
|
|
23
|
+
const { extensions: userExtensions, radiant, mdx, ...baseConfig } = options ?? {};
|
|
24
|
+
const extensions = [...(userExtensions ?? ['.tsx'])];
|
|
25
|
+
const mdxExtensions = mdx?.extensions ?? ['.mdx'];
|
|
26
|
+
const mdxEnabled = mdx !== undefined;
|
|
27
|
+
if (mdxEnabled) {
|
|
28
|
+
appendMdxExtensions(extensions, mdxExtensions);
|
|
30
29
|
}
|
|
31
|
-
|
|
30
|
+
return {
|
|
31
|
+
...baseConfig,
|
|
32
|
+
extensions,
|
|
33
|
+
includeRadiant: radiant ?? true,
|
|
34
|
+
mdxExtensions,
|
|
35
|
+
mdxCompilerOptions: mdxEnabled && mdx ? resolveMdxCompilerOptions(mdx) : undefined,
|
|
36
|
+
};
|
|
32
37
|
};
|
|
33
|
-
|
|
34
|
-
class EcopagesJsxPlugin extends IntegrationPlugin {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
/** Returns the browser-only build plugins required by the JSX integration. */
|
|
51
|
-
get browserBuildPlugins() {
|
|
52
|
-
return [this.runtimeBundleService.getBuildPlugin()].filter(
|
|
53
|
-
(plugin) => plugin !== void 0
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Exposes the bare-module specifier map used by the import map.
|
|
58
|
-
*
|
|
59
|
-
* Client bundles keep these imports external so the browser can load the
|
|
60
|
-
* shared runtime packages from the generated vendor assets.
|
|
61
|
-
*/
|
|
62
|
-
getRuntimeSpecifierMap() {
|
|
63
|
-
return this.runtimeSpecifierMap;
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Creates the renderer instance and attaches the discovered intrinsic custom
|
|
67
|
-
* element assets before the renderer handles any requests.
|
|
68
|
-
*/
|
|
69
|
-
initializeRenderer() {
|
|
70
|
-
const renderer = super.initializeRenderer();
|
|
71
|
-
renderer.setIntrinsicCustomElementAssets(this.intrinsicCustomElementAssets);
|
|
72
|
-
renderer.setRadiantSsrEnabled(this.includeRadiant);
|
|
73
|
-
return renderer;
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Creates a JSX integration plugin.
|
|
77
|
-
*
|
|
78
|
-
* When MDX is enabled, the plugin also claims the configured MDX extensions
|
|
79
|
-
* and prepares compiler options around the shared `@ecopages/jsx` runtime.
|
|
80
|
-
*/
|
|
81
|
-
constructor(options) {
|
|
82
|
-
const { extensions: _ignoredExtensions, ...restOptions } = options ?? {};
|
|
83
|
-
const extensions = [...options?.extensions ?? [".tsx"]];
|
|
84
|
-
const mdxExtensions = options?.mdx?.extensions ?? [".mdx"];
|
|
85
|
-
const includeRadiant = options?.radiant ?? true;
|
|
86
|
-
if (options?.mdx?.enabled) {
|
|
87
|
-
for (const extension of mdxExtensions) {
|
|
88
|
-
if (!extensions.includes(extension)) {
|
|
89
|
-
extensions.push(extension);
|
|
38
|
+
/** JSX integration plugin for Ecopages, supporting `.tsx` templates and optional Radiant web components. */
|
|
39
|
+
export class EcopagesJsxPlugin extends IntegrationPlugin {
|
|
40
|
+
renderer = EcopagesJsxRenderer;
|
|
41
|
+
bundlesPageDependencies = true;
|
|
42
|
+
includeRadiant;
|
|
43
|
+
mdxCompilerOptions;
|
|
44
|
+
mdxExtensions;
|
|
45
|
+
/**
|
|
46
|
+
* Returns the build plugins required by the JSX integration.
|
|
47
|
+
*
|
|
48
|
+
* @remarks
|
|
49
|
+
* Returns a new loader declaration without registering or initializing it. The build manifest owns the
|
|
50
|
+
* resulting instance for the app runtime.
|
|
51
|
+
*/
|
|
52
|
+
plugins(app) {
|
|
53
|
+
if (!this.mdxCompilerOptions) {
|
|
54
|
+
return [];
|
|
90
55
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
this.includeRadiant = includeRadiant;
|
|
100
|
-
this.runtimeBundleService = new JsxRuntimeBundleService({ radiant: includeRadiant });
|
|
101
|
-
this.mdxEnabled = options?.mdx?.enabled ?? false;
|
|
102
|
-
this.mdxExtensions = mdxExtensions;
|
|
103
|
-
EcopagesJsxRenderer.mdxExtensions = this.mdxExtensions;
|
|
104
|
-
if (this.mdxEnabled) {
|
|
105
|
-
const { compilerOptions, remarkPlugins, rehypePlugins, recmaPlugins } = options?.mdx ?? {};
|
|
106
|
-
const resolvedCompilerOptions = {
|
|
107
|
-
format: "detect",
|
|
108
|
-
outputFormat: "program",
|
|
109
|
-
...compilerOptions,
|
|
110
|
-
jsxImportSource: "@ecopages/jsx",
|
|
111
|
-
jsxRuntime: "automatic",
|
|
112
|
-
development: process.env.NODE_ENV === "development"
|
|
113
|
-
};
|
|
114
|
-
const mergedRemarkPlugins = mergePluginLists(compilerOptions?.remarkPlugins, remarkPlugins);
|
|
115
|
-
const mergedRehypePlugins = mergePluginLists(compilerOptions?.rehypePlugins, rehypePlugins);
|
|
116
|
-
const mergedRecmaPlugins = mergePluginLists(compilerOptions?.recmaPlugins, recmaPlugins);
|
|
117
|
-
if (mergedRemarkPlugins) {
|
|
118
|
-
resolvedCompilerOptions.remarkPlugins = mergedRemarkPlugins;
|
|
119
|
-
}
|
|
120
|
-
if (mergedRehypePlugins) {
|
|
121
|
-
resolvedCompilerOptions.rehypePlugins = mergedRehypePlugins;
|
|
122
|
-
}
|
|
123
|
-
if (mergedRecmaPlugins) {
|
|
124
|
-
resolvedCompilerOptions.recmaPlugins = mergedRecmaPlugins;
|
|
125
|
-
}
|
|
126
|
-
this.mdxCompilerOptions = resolvedCompilerOptions;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
/** Ensures MDX build hooks are ready before Ecopages collects contributions. */
|
|
130
|
-
async prepareBuildContributions() {
|
|
131
|
-
if (!this.runtimeDepsInitialized) {
|
|
132
|
-
this.runtimeDepsInitialized = true;
|
|
133
|
-
this.runtimeBundleService.setRootDir(this.appConfig?.rootDir);
|
|
134
|
-
this.runtimeSpecifierMap = await this.runtimeBundleService.getSpecifierMap();
|
|
135
|
-
const vendorDeps = await this.runtimeBundleService.getDependencies();
|
|
136
|
-
this.integrationDependencies.unshift(...vendorDeps);
|
|
56
|
+
return [
|
|
57
|
+
createMdxLoaderPlugin({
|
|
58
|
+
compilerOptions: this.mdxCompilerOptions,
|
|
59
|
+
extensions: this.mdxExtensions,
|
|
60
|
+
projectRoot: app.rootDir,
|
|
61
|
+
requestPipelineMetrics: requireAppRuntime(app).requestPipelineMetrics,
|
|
62
|
+
}),
|
|
63
|
+
];
|
|
137
64
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
if (!this.mdxEnabled || !this.mdxCompilerOptions || this.mdxLoaderPlugin) {
|
|
154
|
-
return;
|
|
155
|
-
}
|
|
156
|
-
this.mdxLoaderPlugin = createMdxLoaderPlugin(this.mdxCompilerOptions, this.mdxExtensions);
|
|
157
|
-
}
|
|
158
|
-
async setupMdxBunPlugin() {
|
|
159
|
-
if (typeof Bun === "undefined" || !this.mdxEnabled || !this.mdxCompilerOptions) {
|
|
160
|
-
return;
|
|
65
|
+
/** Creates the renderer instance with the resolved JSX integration runtime options. */
|
|
66
|
+
createRenderer(base) {
|
|
67
|
+
const jsxConfig = {
|
|
68
|
+
mdxExtensions: this.mdxExtensions,
|
|
69
|
+
radiantSsrEnabled: this.includeRadiant,
|
|
70
|
+
};
|
|
71
|
+
const customRendererOptions = { ...base, jsxConfig };
|
|
72
|
+
const renderer = this.renderer === EcopagesJsxRenderer
|
|
73
|
+
? new (createEcopagesJsxRenderer(jsxConfig))(base)
|
|
74
|
+
: new this.renderer({
|
|
75
|
+
...customRendererOptions,
|
|
76
|
+
hooks: createEcopagesJsxRendererHookFactory(jsxConfig),
|
|
77
|
+
});
|
|
78
|
+
renderer.name ||= this.name;
|
|
79
|
+
return renderer;
|
|
161
80
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
const source = await readFile(args.path, "utf-8");
|
|
171
|
-
const compiled = await compile(new VFile({ value: source, path: args.path }), compilerOptions);
|
|
172
|
-
return { contents: String(compiled.value), loader: "js" };
|
|
81
|
+
constructor(options) {
|
|
82
|
+
const config = resolvePluginOptions(options);
|
|
83
|
+
const { extensions, includeRadiant, mdxExtensions, mdxCompilerOptions, ...baseConfig } = config;
|
|
84
|
+
super({
|
|
85
|
+
name: ECOPAGES_JSX_PLUGIN_NAME,
|
|
86
|
+
extensions,
|
|
87
|
+
jsxImportSource: '@ecopages/jsx',
|
|
88
|
+
...baseConfig,
|
|
173
89
|
});
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
}
|
|
181
|
-
this.intrinsicCustomElementAssets.clear();
|
|
182
|
-
const scriptFiles = await this.collectScriptEntryFiles(this.appConfig.absolutePaths.srcDir);
|
|
183
|
-
for (const scriptFile of scriptFiles) {
|
|
184
|
-
const tagNames = await this.extractIntrinsicCustomElementTagNames(scriptFile);
|
|
185
|
-
if (tagNames.length === 0) {
|
|
186
|
-
continue;
|
|
187
|
-
}
|
|
188
|
-
const processedAsset = await this.resolveIntrinsicCustomElementAsset(scriptFile);
|
|
189
|
-
if (!processedAsset) {
|
|
190
|
-
continue;
|
|
191
|
-
}
|
|
192
|
-
for (const tagName of tagNames) {
|
|
193
|
-
this.intrinsicCustomElementAssets.set(tagName, [processedAsset]);
|
|
194
|
-
}
|
|
90
|
+
this.includeRadiant = includeRadiant;
|
|
91
|
+
this.mdxExtensions = mdxExtensions;
|
|
92
|
+
this.mdxCompilerOptions = mdxCompilerOptions;
|
|
93
|
+
if (this.includeRadiant) {
|
|
94
|
+
this.integrationDependencies.unshift(...this.getDependencies());
|
|
95
|
+
}
|
|
195
96
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
scriptFiles.push(entryPath);
|
|
208
|
-
}
|
|
97
|
+
getDependencies() {
|
|
98
|
+
return [
|
|
99
|
+
AssetFactory.createNodeModuleScript({
|
|
100
|
+
position: 'head',
|
|
101
|
+
importPath: RADIANT_INSTALL_HYDRATOR_FILEPATH,
|
|
102
|
+
bundle: false,
|
|
103
|
+
attributes: {
|
|
104
|
+
'data-eco-script-id': RADIANT_HYDRATOR_SCRIPT_ID,
|
|
105
|
+
},
|
|
106
|
+
}),
|
|
107
|
+
];
|
|
209
108
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
if (!this.assetProcessingService) {
|
|
214
|
-
return void 0;
|
|
109
|
+
/** Assigns grouped-build metadata for page-owned JSX content scripts. */
|
|
110
|
+
prepareAssetDependencies(dependencies) {
|
|
111
|
+
return assignPageOwnedContentScriptGroupedBundles(dependencies);
|
|
215
112
|
}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
113
|
+
/** Registers JSX HMR strategy, dev-transform plugins, and Radiant SSR invalidation hooks. */
|
|
114
|
+
hmr(context) {
|
|
115
|
+
super.hmr(context);
|
|
116
|
+
const manager = context.runtime.hmr;
|
|
117
|
+
if (!manager)
|
|
118
|
+
return;
|
|
119
|
+
const preloadScopes = context.runtime.customElementSsrPreloadScopes;
|
|
120
|
+
const hmrContext = manager.getDefaultContext();
|
|
121
|
+
const absolutePaths = context.appConfig.absolutePaths;
|
|
122
|
+
const strategy = new EcopagesJsxHmrStrategy({
|
|
123
|
+
getRegisteredEntrypoints: hmrContext.getRegisteredEntrypoints,
|
|
124
|
+
getSrcDir: hmrContext.getSrcDir,
|
|
125
|
+
getPagesDir: hmrContext.getPagesDir,
|
|
126
|
+
getLayoutsDir: hmrContext.getLayoutsDir,
|
|
127
|
+
getIncludesDir: () => absolutePaths.includesDir,
|
|
128
|
+
getTemplateExtensions: () => this.extensions,
|
|
129
|
+
});
|
|
130
|
+
manager.registerStrategy(strategy);
|
|
131
|
+
manager.registerDevTransformContributor(new EcopagesJsxDevTransformContributor({
|
|
132
|
+
strategy,
|
|
133
|
+
getMdxLoaderPlugin: () => context.runtime.buildManifest.server.find((plugin) => plugin.name === 'ecopages-jsx-mdx-loader'),
|
|
134
|
+
}));
|
|
135
|
+
if (!this.includeRadiant) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
if (preloadScopes) {
|
|
139
|
+
manager.onScriptEntrypointChanged?.((scriptPath) => invalidateRadiantRegisteredScriptSsrRegistration(preloadScopes, scriptPath));
|
|
140
|
+
}
|
|
239
141
|
}
|
|
240
|
-
return [...tagNames];
|
|
241
|
-
}
|
|
242
142
|
}
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
ecopagesJsxPlugin
|
|
248
|
-
};
|
|
143
|
+
/**
|
|
144
|
+
* Creates the JSX integration plugin with resolved defaults.
|
|
145
|
+
*/
|
|
146
|
+
export const ecopagesJsxPlugin = (options) => new EcopagesJsxPlugin(options);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { MdxCompilerOptionsInput } from '@ecopages/mdx/core';
|
|
2
|
+
import type { IntegrationPluginConfig } from '@ecopages/core/integration';
|
|
3
|
+
import type { AssetDefinition } from '@ecopages/core/integration';
|
|
4
|
+
/**
|
|
5
|
+
* MDX configuration for the JSX integration.
|
|
6
|
+
*
|
|
7
|
+
* Mirrors Ecopages' built-in combined integration pattern where a single
|
|
8
|
+
* JSX-capable plugin can own both `.tsx` and `.mdx` route files.
|
|
9
|
+
*/
|
|
10
|
+
export type EcopagesJsxMdxOptions = MdxCompilerOptionsInput;
|
|
11
|
+
/** Options for the JSX integration plugin. */
|
|
12
|
+
export type EcopagesJsxPluginOptions = Omit<IntegrationPluginConfig, 'name' | 'extensions'> & {
|
|
13
|
+
/** Optional JSX route extensions. Defaults to `.tsx`. */
|
|
14
|
+
extensions?: string[];
|
|
15
|
+
/**
|
|
16
|
+
* Whether to enable the Radiant SSR contract for JSX apps.
|
|
17
|
+
*
|
|
18
|
+
* When enabled, Ecopages JSX installs the Radiant server SSR runtime so
|
|
19
|
+
* intrinsic custom elements can render specialized host markup during SSR.
|
|
20
|
+
*
|
|
21
|
+
* Set to `false` when pages do not use Radiant web components.
|
|
22
|
+
* @default true
|
|
23
|
+
*/
|
|
24
|
+
radiant?: boolean;
|
|
25
|
+
/** Optional MDX integration configuration. */
|
|
26
|
+
mdx?: EcopagesJsxMdxOptions;
|
|
27
|
+
};
|
|
28
|
+
export type EcopagesJsxRendererConfig = {
|
|
29
|
+
mdxExtensions?: string[];
|
|
30
|
+
radiantSsrEnabled?: boolean;
|
|
31
|
+
};
|
|
32
|
+
export type { AssetDefinition };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type AssetDefinition } from '@ecopages/core/integration';
|
|
2
|
+
/** Returns the app-wide grouped-build id used for page-owned content scripts. */
|
|
3
|
+
export declare function createPageOwnedContentScriptBundleId(_integrationName?: string): string;
|
|
4
|
+
/**
|
|
5
|
+
* Tags page-owned content scripts in one dependency batch with the app-wide client bundle id.
|
|
6
|
+
*
|
|
7
|
+
* @remarks
|
|
8
|
+
* Component file scripts and integration runtime assets stay ungrouped. Entries that
|
|
9
|
+
* already assign a grouped id are left unchanged.
|
|
10
|
+
*/
|
|
11
|
+
export declare function assignPageOwnedContentScriptGroupedBundles(dependencies: AssetDefinition[]): AssetDefinition[];
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { APP_BROWSER_CLIENT_BUNDLE_ID, } from '@ecopages/core/integration';
|
|
2
|
+
import { contentHash } from '@ecopages/core/build';
|
|
3
|
+
/** Returns the app-wide grouped-build id used for page-owned content scripts. */
|
|
4
|
+
export function createPageOwnedContentScriptBundleId(_integrationName) {
|
|
5
|
+
return APP_BROWSER_CLIENT_BUNDLE_ID;
|
|
6
|
+
}
|
|
7
|
+
function isPageOwnedGroupableContentScript(dep) {
|
|
8
|
+
if (dep.kind !== 'script' || dep.source !== 'content' || dep.inline) {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
if (dep.groupedBundle?.id) {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
if (dep.packageRole === 'keep-separate' || dep.packageRole === 'runtime' || dep.packageRole === 'dynamic-chunk') {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
function createPageOwnedGroupedEntryName(dep, usedEntryNames) {
|
|
20
|
+
const baseName = dep.name ?? `script-${contentHash(dep.content, 16)}`;
|
|
21
|
+
if (!usedEntryNames.has(baseName)) {
|
|
22
|
+
usedEntryNames.add(baseName);
|
|
23
|
+
return baseName;
|
|
24
|
+
}
|
|
25
|
+
let suffix = 2;
|
|
26
|
+
let candidate = `${baseName}-${suffix}`;
|
|
27
|
+
while (usedEntryNames.has(candidate)) {
|
|
28
|
+
suffix += 1;
|
|
29
|
+
candidate = `${baseName}-${suffix}`;
|
|
30
|
+
}
|
|
31
|
+
usedEntryNames.add(candidate);
|
|
32
|
+
return candidate;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Tags page-owned content scripts in one dependency batch with the app-wide client bundle id.
|
|
36
|
+
*
|
|
37
|
+
* @remarks
|
|
38
|
+
* Component file scripts and integration runtime assets stay ungrouped. Entries that
|
|
39
|
+
* already assign a grouped id are left unchanged.
|
|
40
|
+
*/
|
|
41
|
+
export function assignPageOwnedContentScriptGroupedBundles(dependencies) {
|
|
42
|
+
const bundleId = APP_BROWSER_CLIENT_BUNDLE_ID;
|
|
43
|
+
const usedEntryNames = new Set();
|
|
44
|
+
for (const dependency of dependencies) {
|
|
45
|
+
if (!isPageOwnedGroupableContentScript(dependency)) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
dependency.groupedBundle = {
|
|
49
|
+
id: bundleId,
|
|
50
|
+
entryName: createPageOwnedGroupedEntryName(dependency, usedEntryNames),
|
|
51
|
+
};
|
|
52
|
+
if (dependency.bundle === false) {
|
|
53
|
+
dependency.bundle = true;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return dependencies;
|
|
57
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { CustomElementScriptPreloadScopeState } from '@ecopages/core/integration';
|
|
2
|
+
/**
|
|
3
|
+
* Reads the custom-element tag name from a registered script module source file.
|
|
4
|
+
*/
|
|
5
|
+
export declare function resolveRadiantCustomElementTag(scriptPath: string): string | undefined;
|
|
6
|
+
/**
|
|
7
|
+
* Removes one custom-element definition from the active runtime registry.
|
|
8
|
+
*
|
|
9
|
+
* @remarks
|
|
10
|
+
* Radiant's `@customElement` decorator and the SSR light-DOM shim both skip
|
|
11
|
+
* re-registration when a tag is already defined. During dev, server requests
|
|
12
|
+
* reuse the same process-global registry, so script edits would otherwise keep
|
|
13
|
+
* serving stale SSR markup until a full dev-server restart.
|
|
14
|
+
*/
|
|
15
|
+
export declare function clearRadiantCustomElementDefinition(tagName: string): void;
|
|
16
|
+
/**
|
|
17
|
+
* Clears the SSR custom-element registry entry for one registered Radiant script module.
|
|
18
|
+
*/
|
|
19
|
+
export declare function invalidateRadiantRegisteredScriptSsrRegistration(preloadScopes: Map<string, CustomElementScriptPreloadScopeState>, scriptPath: string): boolean;
|