@ecopages/ecopages-jsx 0.2.0-beta.30 → 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.
- package/package.json +3 -3
- 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.js +8 -10
- package/src/ecopages-jsx-hmr-ownership.js +76 -52
- package/src/ecopages-jsx-hmr-strategy.d.ts +4 -21
- package/src/ecopages-jsx-hmr-strategy.js +60 -56
- package/src/ecopages-jsx-mdx.js +63 -75
- package/src/ecopages-jsx-radiant-ssr-policy.js +104 -97
- package/src/ecopages-jsx-render-session.js +75 -71
- package/src/ecopages-jsx-renderer.js +270 -273
- package/src/ecopages-jsx.constants.js +7 -4
- package/src/ecopages-jsx.plugin.d.ts +1 -1
- package/src/ecopages-jsx.plugin.js +160 -152
- package/src/ecopages-jsx.types.js +1 -0
- package/src/page-owned-content-script-grouping.js +56 -50
- package/src/radiant-registered-script-ssr-invalidation.d.ts +1 -1
- package/src/radiant-registered-script-ssr-invalidation.js +43 -32
- package/src/resolve-radiant-install-hydrator.js +3 -7
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.32",
|
|
4
4
|
"description": "JSX integration plugin for Ecopages",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ecopages",
|
|
@@ -31,12 +31,12 @@
|
|
|
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.32",
|
|
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.
|
|
39
|
+
"@ecopages/core": "0.2.0-beta.32",
|
|
40
40
|
"@ecopages/jsx": "0.3.0-beta.3",
|
|
41
41
|
"@ecopages/radiant": "0.3.0-beta.3"
|
|
42
42
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { EcoBuildPlugin } from '@ecopages/core/plugins/integration-plugin';
|
|
2
|
+
import type { DevTransformBundleContributor } from '@ecopages/core/dev/transform-server';
|
|
3
|
+
import type { EcopagesJsxHmrStrategy } from '../ecopages-jsx-hmr-strategy.js';
|
|
4
|
+
export type EcopagesJsxDevTransformContributorOptions = {
|
|
5
|
+
strategy: EcopagesJsxHmrStrategy;
|
|
6
|
+
getMdxLoaderPlugin: () => EcoBuildPlugin | undefined;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Supplies Ecopages JSX module plugins for the core dev transform bundler.
|
|
10
|
+
*/
|
|
11
|
+
export declare class EcopagesJsxDevTransformContributor implements DevTransformBundleContributor {
|
|
12
|
+
private readonly strategy;
|
|
13
|
+
private readonly getMdxLoaderPlugin;
|
|
14
|
+
constructor(options: EcopagesJsxDevTransformContributorOptions);
|
|
15
|
+
ownsModule(sourcePath: string): boolean;
|
|
16
|
+
getModulePlugins(sourcePath: string): Promise<readonly EcoBuildPlugin[]>;
|
|
17
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Supplies Ecopages JSX module plugins for the core dev transform bundler.
|
|
3
|
+
*/
|
|
4
|
+
export class EcopagesJsxDevTransformContributor {
|
|
5
|
+
strategy;
|
|
6
|
+
getMdxLoaderPlugin;
|
|
7
|
+
constructor(options) {
|
|
8
|
+
this.strategy = options.strategy;
|
|
9
|
+
this.getMdxLoaderPlugin = options.getMdxLoaderPlugin;
|
|
10
|
+
}
|
|
11
|
+
ownsModule(sourcePath) {
|
|
12
|
+
return this.strategy.ownsDevTransformEntrypoint(sourcePath);
|
|
13
|
+
}
|
|
14
|
+
async getModulePlugins(sourcePath) {
|
|
15
|
+
if (!sourcePath.endsWith('.mdx')) {
|
|
16
|
+
return [];
|
|
17
|
+
}
|
|
18
|
+
const mdxLoader = this.getMdxLoaderPlugin();
|
|
19
|
+
return mdxLoader ? [mdxLoader] : [];
|
|
20
|
+
}
|
|
21
|
+
}
|
package/src/eco-embed.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
/** @jsxImportSource @ecopages/jsx */
|
|
2
|
+
import { eco } from '@ecopages/core';
|
|
3
|
+
/**
|
|
4
|
+
* Renders a foreign or same-integration eco component from an Ecopages JSX
|
|
5
|
+
* file without forcing inline mixed-JSX authoring.
|
|
6
|
+
*/
|
|
7
|
+
export function EcoEmbed({ component, props, children, }) {
|
|
8
|
+
return eco.embed(component, props, children);
|
|
8
9
|
}
|
|
9
|
-
export {
|
|
10
|
-
EcoEmbed
|
|
11
|
-
};
|
|
@@ -1,63 +1,87 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
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 path from 'node:path';
|
|
16
|
+
import { rapidhash } from '@ecopages/core/hash';
|
|
3
17
|
const EMPTY_STATE = {
|
|
4
|
-
|
|
5
|
-
|
|
18
|
+
fileOwners: new Set(),
|
|
19
|
+
hash: '',
|
|
6
20
|
};
|
|
7
21
|
let currentState = EMPTY_STATE;
|
|
8
|
-
|
|
9
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Returns the most recently recorded active render tree.
|
|
24
|
+
*/
|
|
25
|
+
export function getEjsxHmrOwnership() {
|
|
26
|
+
return currentState;
|
|
10
27
|
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Updates the active render tree from one or more root components.
|
|
30
|
+
*
|
|
31
|
+
* @remarks
|
|
32
|
+
* Walks each root's `config.__eco.file`, `config.dependencies.components[*].config`,
|
|
33
|
+
* and `config.layouts[*].config` recursively, collecting every file path. The
|
|
34
|
+
* state is replaced only when the resulting file set has a different hash, so
|
|
35
|
+
* the renderer's per-render hook is free in the steady state.
|
|
36
|
+
*/
|
|
37
|
+
export function updateEjsxHmrOwnership(components) {
|
|
38
|
+
const files = collectFileOwners(components);
|
|
39
|
+
const hash = hashFileSet(files);
|
|
40
|
+
if (hash === currentState.hash) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
currentState = {
|
|
44
|
+
fileOwners: files,
|
|
45
|
+
hash,
|
|
46
|
+
};
|
|
21
47
|
}
|
|
22
|
-
|
|
23
|
-
|
|
48
|
+
/**
|
|
49
|
+
* Resets the state to empty. Used by tests and by HMR manager teardown.
|
|
50
|
+
*/
|
|
51
|
+
export function resetEjsxHmrOwnership() {
|
|
52
|
+
currentState = EMPTY_STATE;
|
|
24
53
|
}
|
|
25
54
|
function collectFileOwners(components) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
55
|
+
const files = new Set();
|
|
56
|
+
const visited = new Set();
|
|
57
|
+
const visit = (config) => {
|
|
58
|
+
const file = config?.__eco?.file;
|
|
59
|
+
if (!file) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const resolved = path.resolve(file);
|
|
63
|
+
if (visited.has(resolved)) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
visited.add(resolved);
|
|
67
|
+
files.add(resolved);
|
|
68
|
+
for (const dependency of config?.dependencies?.components ?? []) {
|
|
69
|
+
visit(dependency?.config);
|
|
70
|
+
}
|
|
71
|
+
for (const layout of config?.layouts ?? []) {
|
|
72
|
+
visit(layout?.config);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
for (const component of components) {
|
|
76
|
+
visit(component?.config);
|
|
41
77
|
}
|
|
42
|
-
|
|
43
|
-
visit(layout?.config);
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
for (const component of components) {
|
|
47
|
-
visit(component?.config);
|
|
48
|
-
}
|
|
49
|
-
return files;
|
|
78
|
+
return files;
|
|
50
79
|
}
|
|
51
80
|
function hashFileSet(files) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
81
|
+
if (files.size === 0) {
|
|
82
|
+
return '';
|
|
83
|
+
}
|
|
84
|
+
const sorted = Array.from(files).sort();
|
|
85
|
+
const joined = sorted.join('\n');
|
|
86
|
+
return rapidhash(joined).toString(36);
|
|
58
87
|
}
|
|
59
|
-
export {
|
|
60
|
-
getEjsxHmrOwnership,
|
|
61
|
-
resetEjsxHmrOwnership,
|
|
62
|
-
updateEjsxHmrOwnership
|
|
63
|
-
};
|
|
@@ -1,35 +1,18 @@
|
|
|
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
1
|
import { HmrStrategy, type HmrAction } from '@ecopages/core/hmr/hmr-strategy';
|
|
20
|
-
|
|
21
|
-
|
|
2
|
+
import type { HmrRegisteredEntrypointsContext } from '@ecopages/core/hmr/hmr-registered-entrypoints-context';
|
|
3
|
+
export type EcopagesJsxHmrStrategyContext = HmrRegisteredEntrypointsContext & {
|
|
22
4
|
getSrcDir(): string;
|
|
23
5
|
getPagesDir(): string;
|
|
24
6
|
getLayoutsDir(): string;
|
|
25
7
|
getIncludesDir(): string;
|
|
26
8
|
getTemplateExtensions(): ReadonlyArray<string>;
|
|
27
|
-
}
|
|
9
|
+
};
|
|
28
10
|
export declare class EcopagesJsxHmrStrategy extends HmrStrategy {
|
|
29
11
|
readonly type: 100;
|
|
30
12
|
private readonly context;
|
|
31
13
|
constructor(context: EcopagesJsxHmrStrategyContext);
|
|
32
14
|
matches(filePath: string): boolean;
|
|
15
|
+
ownsDevTransformEntrypoint(filePath: string): boolean;
|
|
33
16
|
process(filePath: string): Promise<HmrAction>;
|
|
34
17
|
private isPageOrLayoutSource;
|
|
35
18
|
private hasJsxTemplateExtension;
|
|
@@ -1,63 +1,67 @@
|
|
|
1
|
-
import path from
|
|
2
|
-
import { HmrStrategy, HmrStrategyType } from
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
matches(filePath) {
|
|
12
|
-
const resolvedPath = path.resolve(filePath);
|
|
13
|
-
const watchedFiles = this.context.getWatchedFiles();
|
|
14
|
-
if (watchedFiles.has(resolvedPath) || [...watchedFiles.keys()].some((key) => path.resolve(key) === resolvedPath)) {
|
|
15
|
-
return false;
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { HmrStrategy, HmrStrategyType } from '@ecopages/core/hmr/hmr-strategy';
|
|
3
|
+
import { isRegisteredDevTransformEntrypoint } from '@ecopages/core/hmr/hmr-entrypoint-output';
|
|
4
|
+
import { getEjsxHmrOwnership } from './ecopages-jsx-hmr-ownership.js';
|
|
5
|
+
export class EcopagesJsxHmrStrategy extends HmrStrategy {
|
|
6
|
+
type = HmrStrategyType.INTEGRATION;
|
|
7
|
+
context;
|
|
8
|
+
constructor(context) {
|
|
9
|
+
super();
|
|
10
|
+
this.context = context;
|
|
16
11
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
12
|
+
matches(filePath) {
|
|
13
|
+
const resolvedPath = path.resolve(filePath);
|
|
14
|
+
if (isRegisteredDevTransformEntrypoint(this.context.getRegisteredEntrypoints(), resolvedPath)) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
const srcDir = path.resolve(this.context.getSrcDir());
|
|
18
|
+
if (!resolvedPath.startsWith(`${srcDir}${path.sep}`) && resolvedPath !== srcDir) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
const includesDir = path.resolve(this.context.getIncludesDir());
|
|
22
|
+
if (includesDir && (resolvedPath === includesDir || resolvedPath.startsWith(`${includesDir}${path.sep}`))) {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
if (this.isPageOrLayoutSource(resolvedPath)) {
|
|
26
|
+
return this.hasJsxTemplateExtension(resolvedPath);
|
|
27
|
+
}
|
|
28
|
+
const ownership = getEjsxHmrOwnership();
|
|
29
|
+
if (ownership.fileOwners.has(resolvedPath)) {
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
return false;
|
|
24
33
|
}
|
|
25
|
-
|
|
26
|
-
|
|
34
|
+
ownsDevTransformEntrypoint(filePath) {
|
|
35
|
+
const resolvedPath = path.resolve(filePath);
|
|
36
|
+
if (!isRegisteredDevTransformEntrypoint(this.context.getRegisteredEntrypoints(), resolvedPath)) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
return this.isPageOrLayoutSource(resolvedPath) && this.hasJsxTemplateExtension(resolvedPath);
|
|
27
40
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
41
|
+
async process(filePath) {
|
|
42
|
+
return {
|
|
43
|
+
type: 'broadcast',
|
|
44
|
+
events: [
|
|
45
|
+
{
|
|
46
|
+
type: 'layout-update',
|
|
47
|
+
path: filePath,
|
|
48
|
+
timestamp: Date.now(),
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
};
|
|
31
52
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
{
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
]
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
isPageOrLayoutSource(resolvedPath) {
|
|
47
|
-
const pagesDir = path.resolve(this.context.getPagesDir());
|
|
48
|
-
const layoutsDir = path.resolve(this.context.getLayoutsDir());
|
|
49
|
-
if (pagesDir && (resolvedPath === pagesDir || resolvedPath.startsWith(`${pagesDir}${path.sep}`))) {
|
|
50
|
-
return true;
|
|
53
|
+
isPageOrLayoutSource(resolvedPath) {
|
|
54
|
+
const pagesDir = path.resolve(this.context.getPagesDir());
|
|
55
|
+
const layoutsDir = path.resolve(this.context.getLayoutsDir());
|
|
56
|
+
if (pagesDir && (resolvedPath === pagesDir || resolvedPath.startsWith(`${pagesDir}${path.sep}`))) {
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
if (layoutsDir && (resolvedPath === layoutsDir || resolvedPath.startsWith(`${layoutsDir}${path.sep}`))) {
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
return false;
|
|
51
63
|
}
|
|
52
|
-
|
|
53
|
-
|
|
64
|
+
hasJsxTemplateExtension(resolvedPath) {
|
|
65
|
+
return this.context.getTemplateExtensions().some((extension) => resolvedPath.endsWith(extension));
|
|
54
66
|
}
|
|
55
|
-
return false;
|
|
56
|
-
}
|
|
57
|
-
hasJsxTemplateExtension(resolvedPath) {
|
|
58
|
-
return this.context.getTemplateExtensions().some((extension) => resolvedPath.endsWith(extension));
|
|
59
|
-
}
|
|
60
67
|
}
|
|
61
|
-
export {
|
|
62
|
-
EcopagesJsxHmrStrategy
|
|
63
|
-
};
|
package/src/ecopages-jsx-mdx.js
CHANGED
|
@@ -1,82 +1,70 @@
|
|
|
1
|
-
import { readFile } from
|
|
2
|
-
import { ensurePageConfigLayouts } from
|
|
3
|
-
import { rapidhash } from
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
defaults: {
|
|
15
|
-
format: "detect",
|
|
16
|
-
outputFormat: "program"
|
|
17
|
-
}
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { ensurePageConfigLayouts } from '@ecopages/core/eco/page-layout-normalization';
|
|
3
|
+
import { rapidhash } from '@ecopages/core/hash';
|
|
4
|
+
import { appendMdxExtensions, createMdxExtensionFilter, createMdxLoaderPlugin as createMdxLoaderPluginCore, resolveMdxCompilerOptions as resolveMdxCompilerOptionsCore, } from '@ecopages/mdx/core';
|
|
5
|
+
import { VFile } from 'vfile';
|
|
6
|
+
import { ECOPAGES_JSX_PLUGIN_NAME } from './ecopages-jsx.constants.js';
|
|
7
|
+
export { appendMdxExtensions, createMdxExtensionFilter };
|
|
8
|
+
export const resolveMdxCompilerOptions = (mdxOptions) => resolveMdxCompilerOptionsCore(mdxOptions, {
|
|
9
|
+
jsxImportSource: '@ecopages/jsx',
|
|
10
|
+
defaults: {
|
|
11
|
+
format: 'detect',
|
|
12
|
+
outputFormat: 'program',
|
|
13
|
+
},
|
|
18
14
|
});
|
|
19
|
-
const createMdxLoaderPlugin = (compilerOptions, extensions) => createMdxLoaderPluginCore({
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
15
|
+
export const createMdxLoaderPlugin = (compilerOptions, extensions) => createMdxLoaderPluginCore({
|
|
16
|
+
name: 'ecopages-jsx-mdx-loader',
|
|
17
|
+
compilerOptions,
|
|
18
|
+
extensions,
|
|
19
|
+
includeSourceMap: false,
|
|
20
|
+
loader: 'js',
|
|
25
21
|
});
|
|
26
|
-
const registerBunMdxPlugin = async (compilerOptions, extensions) => {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
const filter = createMdxExtensionFilter(extensions);
|
|
31
|
-
Bun.plugin({
|
|
32
|
-
name: "ecopages-jsx-mdx",
|
|
33
|
-
setup(build) {
|
|
34
|
-
build.onLoad({ filter }, async (args) => {
|
|
35
|
-
const { compile } = await import("@mdx-js/mdx");
|
|
36
|
-
const source = await readFile(args.path, "utf-8");
|
|
37
|
-
const compiled = await compile(new VFile({ value: source, path: args.path }), compilerOptions);
|
|
38
|
-
return { contents: String(compiled.value), loader: "js" };
|
|
39
|
-
});
|
|
22
|
+
export const registerBunMdxPlugin = async (compilerOptions, extensions) => {
|
|
23
|
+
if (typeof Bun === 'undefined') {
|
|
24
|
+
return;
|
|
40
25
|
}
|
|
41
|
-
|
|
26
|
+
const filter = createMdxExtensionFilter(extensions);
|
|
27
|
+
Bun.plugin({
|
|
28
|
+
name: 'ecopages-jsx-mdx',
|
|
29
|
+
setup(build) {
|
|
30
|
+
build.onLoad({ filter }, async (args) => {
|
|
31
|
+
const { compile } = await import('@mdx-js/mdx');
|
|
32
|
+
const source = await readFile(args.path, 'utf-8');
|
|
33
|
+
const compiled = await compile(new VFile({ value: source, path: args.path }), compilerOptions);
|
|
34
|
+
return { contents: String(compiled.value), loader: 'js' };
|
|
35
|
+
});
|
|
36
|
+
},
|
|
37
|
+
});
|
|
42
38
|
};
|
|
43
|
-
const isMdxFile = (filePath, extensions) => {
|
|
44
|
-
|
|
39
|
+
export const isMdxFile = (filePath, extensions) => {
|
|
40
|
+
return extensions.some((ext) => filePath.endsWith(ext));
|
|
45
41
|
};
|
|
46
|
-
const normalizeMdxPageModule = (file, module) => {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
const Page = module.default;
|
|
51
|
-
const normalizedConfig = {
|
|
52
|
-
...module.config ?? Page.config ?? {},
|
|
53
|
-
__eco: module.config?.__eco ?? Page.config?.__eco ?? {
|
|
54
|
-
id: String(rapidhash(file)),
|
|
55
|
-
file,
|
|
56
|
-
integration: ECOPAGES_JSX_PLUGIN_NAME
|
|
42
|
+
export const normalizeMdxPageModule = (file, module) => {
|
|
43
|
+
if (typeof module.default !== 'function') {
|
|
44
|
+
throw new TypeError('MDX file must export a callable default component.');
|
|
57
45
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
46
|
+
const Page = module.default;
|
|
47
|
+
const normalizedConfig = {
|
|
48
|
+
...(module.config ?? Page.config ?? {}),
|
|
49
|
+
__eco: module.config?.__eco ??
|
|
50
|
+
Page.config?.__eco ?? {
|
|
51
|
+
id: String(rapidhash(file)),
|
|
52
|
+
file,
|
|
53
|
+
integration: ECOPAGES_JSX_PLUGIN_NAME,
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
if (module.layout && !(normalizedConfig.layouts && normalizedConfig.layouts.length > 0)) {
|
|
57
|
+
normalizedConfig.layout = module.layout;
|
|
58
|
+
}
|
|
59
|
+
ensurePageConfigLayouts(normalizedConfig);
|
|
60
|
+
const wrappedPage = async (props) => await Page(props);
|
|
61
|
+
wrappedPage.config = normalizedConfig;
|
|
62
|
+
if (module.getMetadata ?? Page.metadata) {
|
|
63
|
+
wrappedPage.metadata = module.getMetadata ?? Page.metadata;
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
...module,
|
|
67
|
+
default: wrappedPage,
|
|
68
|
+
config: normalizedConfig,
|
|
69
|
+
};
|
|
82
70
|
};
|