@ecopages/react 0.2.0-alpha.5 → 0.2.0-alpha.7
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/CHANGELOG.md +22 -41
- package/README.md +135 -29
- package/package.json +3 -3
- package/src/react-hmr-strategy.d.ts +22 -30
- package/src/react-hmr-strategy.js +57 -120
- package/src/react-hmr-strategy.ts +76 -145
- package/src/react-renderer.d.ts +130 -11
- package/src/react-renderer.js +368 -64
- package/src/react-renderer.ts +490 -90
- package/src/react.plugin.d.ts +17 -5
- package/src/react.plugin.js +44 -13
- package/src/react.plugin.ts +49 -14
- package/src/router-adapter.d.ts +2 -2
- package/src/router-adapter.ts +2 -2
- package/src/services/react-bundle.service.d.ts +2 -30
- package/src/services/react-bundle.service.js +19 -94
- package/src/services/react-bundle.service.ts +20 -129
- package/src/services/react-hydration-asset.service.js +3 -3
- package/src/services/react-hydration-asset.service.ts +7 -4
- package/src/services/react-page-module.service.d.ts +3 -0
- package/src/services/react-page-module.service.js +20 -16
- package/src/services/react-page-module.service.ts +27 -17
- package/src/services/react-runtime-bundle.service.d.ts +12 -12
- package/src/services/react-runtime-bundle.service.js +98 -180
- package/src/services/react-runtime-bundle.service.ts +112 -211
- package/src/utils/client-graph-boundary-plugin.js +78 -1
- package/src/utils/client-graph-boundary-plugin.ts +122 -1
- package/src/utils/hydration-scripts.d.ts +18 -1
- package/src/utils/hydration-scripts.js +83 -32
- package/src/utils/hydration-scripts.ts +159 -38
- package/src/utils/react-dom-runtime-interop-plugin.d.ts +5 -0
- package/src/utils/react-dom-runtime-interop-plugin.js +29 -0
- package/src/utils/react-dom-runtime-interop-plugin.ts +33 -0
- package/src/utils/react-mdx-loader-plugin.js +13 -5
- package/src/utils/react-mdx-loader-plugin.ts +28 -5
- package/src/utils/react-runtime-specifier-map.d.ts +6 -0
- package/src/utils/react-runtime-specifier-map.js +37 -0
- package/src/utils/react-runtime-specifier-map.ts +45 -0
- package/src/utils/use-sync-external-store-shim-plugin.d.ts +5 -0
- package/src/utils/use-sync-external-store-shim-plugin.js +41 -0
- package/src/utils/use-sync-external-store-shim-plugin.ts +45 -0
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { compile } from "@mdx-js/mdx";
|
|
4
|
-
import
|
|
4
|
+
import sourceMap from "source-map";
|
|
5
5
|
import { VFile } from "vfile";
|
|
6
|
+
function resolveCompileFormat(filePath, compilerOptions) {
|
|
7
|
+
const configuredFormat = compilerOptions?.format;
|
|
8
|
+
if (configuredFormat && configuredFormat !== "detect") {
|
|
9
|
+
return configuredFormat;
|
|
10
|
+
}
|
|
11
|
+
return path.extname(filePath).toLowerCase() === ".md" ? "mdx" : configuredFormat;
|
|
12
|
+
}
|
|
6
13
|
function createReactMdxLoaderPlugin(compilerOptions) {
|
|
7
14
|
const mdxExtensions = compilerOptions?.mdxExtensions ?? [".mdx"];
|
|
8
|
-
const mdExtensions = compilerOptions?.mdExtensions ?? [
|
|
15
|
+
const mdExtensions = compilerOptions?.mdExtensions ?? [];
|
|
9
16
|
const allExtensions = [...mdxExtensions, ...mdExtensions];
|
|
10
17
|
const escapedExts = allExtensions.map((ext) => ext.replace(".", "\\."));
|
|
11
18
|
const filter = new RegExp(`(${escapedExts.join("|")})(\\?.*)?$`);
|
|
@@ -18,13 +25,14 @@ function createReactMdxLoaderPlugin(compilerOptions) {
|
|
|
18
25
|
const file = new VFile({ path: filePath, value: source });
|
|
19
26
|
const compiled = await compile(file, {
|
|
20
27
|
...compilerOptions,
|
|
21
|
-
|
|
28
|
+
format: resolveCompileFormat(filePath, compilerOptions),
|
|
29
|
+
SourceMapGenerator: sourceMap.SourceMapGenerator
|
|
22
30
|
});
|
|
23
|
-
const
|
|
31
|
+
const inlineSourceMap = compiled.map ? `
|
|
24
32
|
//# sourceMappingURL=data:application/json;base64,${Buffer.from(JSON.stringify(compiled.map)).toString("base64")}
|
|
25
33
|
` : "";
|
|
26
34
|
return {
|
|
27
|
-
contents: `${String(compiled.value)}${
|
|
35
|
+
contents: `${String(compiled.value)}${inlineSourceMap}`,
|
|
28
36
|
loader: compilerOptions?.jsx ? "jsx" : "js",
|
|
29
37
|
resolveDir: path.dirname(args.path)
|
|
30
38
|
};
|
|
@@ -2,12 +2,34 @@ import { readFileSync } from 'node:fs';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import type { EcoBuildPlugin } from '@ecopages/core/build/build-types';
|
|
4
4
|
import { type CompileOptions, compile } from '@mdx-js/mdx';
|
|
5
|
-
import
|
|
5
|
+
import sourceMap from 'source-map';
|
|
6
6
|
import { VFile } from 'vfile';
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Resolves the MDX parser mode for a React-backed MDX source file.
|
|
10
|
+
*
|
|
11
|
+
* When `.md` files are explicitly opted into the React MDX loader they still
|
|
12
|
+
* need to compile as MDX, not plain markdown. Otherwise top-level ESM exports
|
|
13
|
+
* like `config` are treated as literal text and the route cannot execute as a
|
|
14
|
+
* page module.
|
|
15
|
+
*
|
|
16
|
+
* @param filePath Absolute or relative source file path.
|
|
17
|
+
* @param compilerOptions User-provided MDX compiler options.
|
|
18
|
+
* @returns The compile format that should be passed to `@mdx-js/mdx`.
|
|
19
|
+
*/
|
|
20
|
+
function resolveCompileFormat(filePath: string, compilerOptions?: CompileOptions): CompileOptions['format'] {
|
|
21
|
+
const configuredFormat = compilerOptions?.format;
|
|
22
|
+
|
|
23
|
+
if (configuredFormat && configuredFormat !== 'detect') {
|
|
24
|
+
return configuredFormat;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return path.extname(filePath).toLowerCase() === '.md' ? 'mdx' : configuredFormat;
|
|
28
|
+
}
|
|
29
|
+
|
|
8
30
|
export function createReactMdxLoaderPlugin(compilerOptions?: CompileOptions): EcoBuildPlugin {
|
|
9
31
|
const mdxExtensions = compilerOptions?.mdxExtensions ?? ['.mdx'];
|
|
10
|
-
const mdExtensions = compilerOptions?.mdExtensions ?? [
|
|
32
|
+
const mdExtensions = compilerOptions?.mdExtensions ?? [];
|
|
11
33
|
const allExtensions = [...mdxExtensions, ...mdExtensions];
|
|
12
34
|
const escapedExts = allExtensions.map((ext) => ext.replace('.', '\\.'));
|
|
13
35
|
const filter = new RegExp(`(${escapedExts.join('|')})(\\?.*)?$`);
|
|
@@ -22,15 +44,16 @@ export function createReactMdxLoaderPlugin(compilerOptions?: CompileOptions): Ec
|
|
|
22
44
|
|
|
23
45
|
const compiled = await compile(file, {
|
|
24
46
|
...compilerOptions,
|
|
25
|
-
|
|
47
|
+
format: resolveCompileFormat(filePath, compilerOptions),
|
|
48
|
+
SourceMapGenerator: sourceMap.SourceMapGenerator,
|
|
26
49
|
});
|
|
27
50
|
|
|
28
|
-
const
|
|
51
|
+
const inlineSourceMap = compiled.map
|
|
29
52
|
? `\n//# sourceMappingURL=data:application/json;base64,${Buffer.from(JSON.stringify(compiled.map)).toString('base64')}\n`
|
|
30
53
|
: '';
|
|
31
54
|
|
|
32
55
|
return {
|
|
33
|
-
contents: `${String(compiled.value)}${
|
|
56
|
+
contents: `${String(compiled.value)}${inlineSourceMap}`,
|
|
34
57
|
loader: compilerOptions?.jsx ? 'jsx' : 'js',
|
|
35
58
|
resolveDir: path.dirname(args.path),
|
|
36
59
|
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ReactRouterAdapter } from '../router-adapter.js';
|
|
2
|
+
import type { ReactRuntimeImports } from '../services/react-runtime-bundle.service.js';
|
|
3
|
+
export declare const REACT_RUNTIME_SPECIFIERS: readonly ["react", "react-dom", "react/jsx-runtime", "react/jsx-dev-runtime", "react-dom/client"];
|
|
4
|
+
export declare function buildReactRuntimeSpecifierMap(runtimeImports: ReactRuntimeImports, routerAdapter?: ReactRouterAdapter): Record<string, string>;
|
|
5
|
+
export declare function getReactRuntimeExternalSpecifiers(): string[];
|
|
6
|
+
export declare function getReactClientGraphAllowSpecifiers(runtimeSpecifiers: Iterable<string>, routerAdapter?: ReactRouterAdapter): string[];
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const REACT_RUNTIME_SPECIFIERS = [
|
|
2
|
+
"react",
|
|
3
|
+
"react-dom",
|
|
4
|
+
"react/jsx-runtime",
|
|
5
|
+
"react/jsx-dev-runtime",
|
|
6
|
+
"react-dom/client"
|
|
7
|
+
];
|
|
8
|
+
function buildReactRuntimeSpecifierMap(runtimeImports, routerAdapter) {
|
|
9
|
+
const map = {
|
|
10
|
+
react: runtimeImports.react,
|
|
11
|
+
"react/jsx-runtime": runtimeImports.reactJsxRuntime,
|
|
12
|
+
"react/jsx-dev-runtime": runtimeImports.reactJsxDevRuntime,
|
|
13
|
+
"react-dom": runtimeImports.reactDom,
|
|
14
|
+
"react-dom/client": runtimeImports.reactDomClient
|
|
15
|
+
};
|
|
16
|
+
if (routerAdapter && runtimeImports.router) {
|
|
17
|
+
map[routerAdapter.importMapKey] = runtimeImports.router;
|
|
18
|
+
}
|
|
19
|
+
return map;
|
|
20
|
+
}
|
|
21
|
+
function getReactRuntimeExternalSpecifiers() {
|
|
22
|
+
return [...REACT_RUNTIME_SPECIFIERS];
|
|
23
|
+
}
|
|
24
|
+
function getReactClientGraphAllowSpecifiers(runtimeSpecifiers, routerAdapter) {
|
|
25
|
+
return [
|
|
26
|
+
"@ecopages/core",
|
|
27
|
+
...REACT_RUNTIME_SPECIFIERS,
|
|
28
|
+
...routerAdapter ? [routerAdapter.importMapKey] : [],
|
|
29
|
+
...Array.from(runtimeSpecifiers)
|
|
30
|
+
];
|
|
31
|
+
}
|
|
32
|
+
export {
|
|
33
|
+
REACT_RUNTIME_SPECIFIERS,
|
|
34
|
+
buildReactRuntimeSpecifierMap,
|
|
35
|
+
getReactClientGraphAllowSpecifiers,
|
|
36
|
+
getReactRuntimeExternalSpecifiers
|
|
37
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { ReactRouterAdapter } from '../router-adapter.ts';
|
|
2
|
+
import type { ReactRuntimeImports } from '../services/react-runtime-bundle.service.ts';
|
|
3
|
+
|
|
4
|
+
export const REACT_RUNTIME_SPECIFIERS = [
|
|
5
|
+
'react',
|
|
6
|
+
'react-dom',
|
|
7
|
+
'react/jsx-runtime',
|
|
8
|
+
'react/jsx-dev-runtime',
|
|
9
|
+
'react-dom/client',
|
|
10
|
+
] as const;
|
|
11
|
+
|
|
12
|
+
export function buildReactRuntimeSpecifierMap(
|
|
13
|
+
runtimeImports: ReactRuntimeImports,
|
|
14
|
+
routerAdapter?: ReactRouterAdapter,
|
|
15
|
+
): Record<string, string> {
|
|
16
|
+
const map: Record<string, string> = {
|
|
17
|
+
react: runtimeImports.react,
|
|
18
|
+
'react/jsx-runtime': runtimeImports.reactJsxRuntime,
|
|
19
|
+
'react/jsx-dev-runtime': runtimeImports.reactJsxDevRuntime,
|
|
20
|
+
'react-dom': runtimeImports.reactDom,
|
|
21
|
+
'react-dom/client': runtimeImports.reactDomClient,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
if (routerAdapter && runtimeImports.router) {
|
|
25
|
+
map[routerAdapter.importMapKey] = runtimeImports.router;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return map;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function getReactRuntimeExternalSpecifiers(): string[] {
|
|
32
|
+
return [...REACT_RUNTIME_SPECIFIERS];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function getReactClientGraphAllowSpecifiers(
|
|
36
|
+
runtimeSpecifiers: Iterable<string>,
|
|
37
|
+
routerAdapter?: ReactRouterAdapter,
|
|
38
|
+
): string[] {
|
|
39
|
+
return [
|
|
40
|
+
'@ecopages/core',
|
|
41
|
+
...REACT_RUNTIME_SPECIFIERS,
|
|
42
|
+
...(routerAdapter ? [routerAdapter.importMapKey] : []),
|
|
43
|
+
...Array.from(runtimeSpecifiers),
|
|
44
|
+
];
|
|
45
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
function createUseSyncExternalStoreShimPlugin(options) {
|
|
2
|
+
const namespace = options?.namespace ?? "ecopages-react-use-sync-external-store-shim";
|
|
3
|
+
return {
|
|
4
|
+
name: options?.name ?? "react-use-sync-external-store-shim",
|
|
5
|
+
setup(build) {
|
|
6
|
+
build.onResolve({ filter: /^use-sync-external-store\/shim(?:\/index\.js)?$/ }, () => ({
|
|
7
|
+
path: "use-sync-external-store/shim",
|
|
8
|
+
namespace
|
|
9
|
+
}));
|
|
10
|
+
build.onLoad({ filter: /^use-sync-external-store\/shim$/, namespace }, () => ({
|
|
11
|
+
contents: "export { useSyncExternalStore } from 'react';",
|
|
12
|
+
loader: "js"
|
|
13
|
+
}));
|
|
14
|
+
build.onLoad({ filter: /[\\/]use-sync-external-store[\\/]shim[\\/]index\.js$/ }, () => ({
|
|
15
|
+
contents: "export { useSyncExternalStore } from 'react';",
|
|
16
|
+
loader: "js"
|
|
17
|
+
}));
|
|
18
|
+
build.onLoad(
|
|
19
|
+
{
|
|
20
|
+
filter: /[\\/]use-sync-external-store[\\/]cjs[\\/]use-sync-external-store-shim\.development\.js$/
|
|
21
|
+
},
|
|
22
|
+
() => ({
|
|
23
|
+
contents: "export { useSyncExternalStore } from 'react';",
|
|
24
|
+
loader: "js"
|
|
25
|
+
})
|
|
26
|
+
);
|
|
27
|
+
build.onLoad(
|
|
28
|
+
{
|
|
29
|
+
filter: /[\\/]use-sync-external-store[\\/]cjs[\\/]use-sync-external-store-shim\.production\.js$/
|
|
30
|
+
},
|
|
31
|
+
() => ({
|
|
32
|
+
contents: "export { useSyncExternalStore } from 'react';",
|
|
33
|
+
loader: "js"
|
|
34
|
+
})
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export {
|
|
40
|
+
createUseSyncExternalStoreShimPlugin
|
|
41
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { EcoBuildPlugin } from '@ecopages/core/build/build-types';
|
|
2
|
+
|
|
3
|
+
export function createUseSyncExternalStoreShimPlugin(options?: { name?: string; namespace?: string }): EcoBuildPlugin {
|
|
4
|
+
const namespace = options?.namespace ?? 'ecopages-react-use-sync-external-store-shim';
|
|
5
|
+
|
|
6
|
+
return {
|
|
7
|
+
name: options?.name ?? 'react-use-sync-external-store-shim',
|
|
8
|
+
setup(build) {
|
|
9
|
+
build.onResolve({ filter: /^use-sync-external-store\/shim(?:\/index\.js)?$/ }, () => ({
|
|
10
|
+
path: 'use-sync-external-store/shim',
|
|
11
|
+
namespace,
|
|
12
|
+
}));
|
|
13
|
+
|
|
14
|
+
build.onLoad({ filter: /^use-sync-external-store\/shim$/, namespace }, () => ({
|
|
15
|
+
contents: "export { useSyncExternalStore } from 'react';",
|
|
16
|
+
loader: 'js',
|
|
17
|
+
}));
|
|
18
|
+
|
|
19
|
+
build.onLoad({ filter: /[\\/]use-sync-external-store[\\/]shim[\\/]index\.js$/ }, () => ({
|
|
20
|
+
contents: "export { useSyncExternalStore } from 'react';",
|
|
21
|
+
loader: 'js',
|
|
22
|
+
}));
|
|
23
|
+
|
|
24
|
+
build.onLoad(
|
|
25
|
+
{
|
|
26
|
+
filter: /[\\/]use-sync-external-store[\\/]cjs[\\/]use-sync-external-store-shim\.development\.js$/,
|
|
27
|
+
},
|
|
28
|
+
() => ({
|
|
29
|
+
contents: "export { useSyncExternalStore } from 'react';",
|
|
30
|
+
loader: 'js',
|
|
31
|
+
}),
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
build.onLoad(
|
|
35
|
+
{
|
|
36
|
+
filter: /[\\/]use-sync-external-store[\\/]cjs[\\/]use-sync-external-store-shim\.production\.js$/,
|
|
37
|
+
},
|
|
38
|
+
() => ({
|
|
39
|
+
contents: "export { useSyncExternalStore } from 'react';",
|
|
40
|
+
loader: 'js',
|
|
41
|
+
}),
|
|
42
|
+
);
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
}
|