rsbuild-plugin-react-router 0.5.0 → 0.6.0

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.
Files changed (110) hide show
  1. package/README.md +58 -208
  2. package/dist/511.js +370 -331
  3. package/dist/build-output-transforms.d.ts +30 -6
  4. package/dist/classic-mode.d.ts +56 -0
  5. package/dist/config-imports.d.ts +8 -2
  6. package/dist/constants.d.ts +3 -0
  7. package/dist/dev-background-resources.d.ts +3 -1
  8. package/dist/dev-generation.d.ts +2 -3
  9. package/dist/dev-hmr.d.ts +8 -2
  10. package/dist/dev-runtime-controller.d.ts +6 -1
  11. package/dist/dev-source-maps.d.ts +4 -0
  12. package/dist/effect-runtime.d.ts +17 -5
  13. package/dist/entry-paths.d.ts +16 -0
  14. package/dist/environment-output.d.ts +6 -0
  15. package/dist/export-utils.d.ts +2 -1
  16. package/dist/index.cjs +3957 -2208
  17. package/dist/index.d.ts +3 -1
  18. package/dist/index.js +3470 -1793
  19. package/dist/lazy-compilation-prewarm.d.ts +8 -5
  20. package/dist/manifest.d.ts +16 -4
  21. package/dist/mode-plan.d.ts +82 -0
  22. package/dist/modify-browser-manifest.d.ts +8 -4
  23. package/dist/plugin-utils.d.ts +27 -1
  24. package/dist/prerender-build.d.ts +5 -5
  25. package/dist/prerender.d.ts +1 -5
  26. package/dist/react-router-config.d.ts +11 -3
  27. package/dist/route-artifacts.d.ts +4 -2
  28. package/dist/route-chunks.d.ts +2 -1
  29. package/dist/route-component-transform.d.ts +0 -2
  30. package/dist/route-export-pruning.d.ts +4 -1
  31. package/dist/route-imports.d.ts +18 -0
  32. package/dist/route-transform-tasks.d.ts +5 -0
  33. package/dist/route-watch.d.ts +11 -6
  34. package/dist/rsc-dev-server.d.ts +26 -0
  35. package/dist/rsc-prerender.d.ts +54 -0
  36. package/dist/rsc-route-config.d.ts +6 -0
  37. package/dist/rsc-route-exports.d.ts +15 -0
  38. package/dist/rsc-route-transform-loader.cjs +43 -0
  39. package/dist/rsc-route-transform-loader.d.ts +30 -0
  40. package/dist/rsc-route-transform-loader.js +16 -0
  41. package/dist/rsc-route-transform-registration.d.ts +12 -0
  42. package/dist/rsc-route-transforms.d.ts +21 -0
  43. package/dist/rsc-support.d.ts +23 -0
  44. package/dist/rsc-virtual-modules.d.ts +19 -0
  45. package/dist/server-build-plan.d.ts +2 -1
  46. package/dist/server-build-resolution.d.ts +1 -2
  47. package/dist/server-utils.d.ts +4 -5
  48. package/dist/ssr-asset-relocation.d.ts +98 -0
  49. package/dist/templates/entry.rsc.client.d.ts +1 -0
  50. package/dist/templates/entry.rsc.client.js +61 -0
  51. package/dist/templates/entry.rsc.d.ts +9 -0
  52. package/dist/templates/entry.rsc.js +38 -0
  53. package/dist/templates/entry.rsc.ssr.d.ts +4 -0
  54. package/dist/templates/entry.rsc.ssr.js +24 -0
  55. package/dist/typegen.d.ts +4 -2
  56. package/dist/types.d.ts +30 -1
  57. package/package.json +69 -14
  58. package/src/build-output-transforms.ts +155 -21
  59. package/src/classic-mode.ts +253 -0
  60. package/src/config-imports.ts +153 -6
  61. package/src/constants.ts +6 -2
  62. package/src/dev-background-resources.ts +46 -85
  63. package/src/dev-generation.ts +52 -33
  64. package/src/dev-hmr.ts +112 -80
  65. package/src/dev-runtime-artifacts.ts +11 -12
  66. package/src/dev-runtime-controller.ts +75 -85
  67. package/src/dev-runtime-session.ts +14 -18
  68. package/src/dev-server.ts +2 -0
  69. package/src/dev-source-maps.ts +257 -0
  70. package/src/effect-runtime.ts +105 -57
  71. package/src/entry-paths.ts +80 -0
  72. package/src/environment-output.ts +55 -0
  73. package/src/export-utils.ts +15 -11
  74. package/src/index.ts +661 -496
  75. package/src/lazy-compilation-prewarm.ts +20 -4
  76. package/src/manifest.ts +157 -82
  77. package/src/mode-plan.ts +367 -0
  78. package/src/modify-browser-manifest.ts +130 -124
  79. package/src/plugin-utils.ts +103 -39
  80. package/src/prerender-build.ts +82 -104
  81. package/src/prerender.ts +23 -24
  82. package/src/react-router-config.ts +72 -26
  83. package/src/route-artifacts.ts +96 -66
  84. package/src/route-chunks.ts +167 -51
  85. package/src/route-component-transform.ts +14 -21
  86. package/src/route-export-pruning.ts +4 -3
  87. package/src/route-imports.ts +100 -0
  88. package/src/route-transform-tasks.ts +39 -25
  89. package/src/route-watch.ts +166 -188
  90. package/src/rsc-dev-server.ts +112 -0
  91. package/src/rsc-prerender.ts +362 -0
  92. package/src/rsc-route-config.ts +175 -0
  93. package/src/rsc-route-exports.ts +67 -0
  94. package/src/rsc-route-transform-loader.ts +65 -0
  95. package/src/rsc-route-transform-registration.ts +145 -0
  96. package/src/rsc-route-transforms.ts +995 -0
  97. package/src/rsc-runtime.d.ts +143 -0
  98. package/src/rsc-support.ts +116 -0
  99. package/src/rsc-virtual-modules.ts +113 -0
  100. package/src/server-build-plan.ts +14 -3
  101. package/src/server-build-resolution.ts +37 -47
  102. package/src/server-utils.ts +21 -35
  103. package/src/ssr-asset-relocation.ts +183 -0
  104. package/src/ssr-externals.ts +8 -26
  105. package/src/templates/entry.rsc.client.tsx +168 -0
  106. package/src/templates/entry.rsc.ssr.tsx +45 -0
  107. package/src/templates/entry.rsc.tsx +80 -0
  108. package/src/typegen.ts +40 -23
  109. package/src/types.ts +39 -1
  110. package/src/warnings/warn-on-client-source-maps.ts +6 -10
@@ -0,0 +1,143 @@
1
+ interface ImportMeta {
2
+ webpackHot?: {
3
+ accept(): void;
4
+ on(event: string, handler: () => void): void;
5
+ };
6
+ }
7
+
8
+ declare module 'react-server-dom-rspack/client.browser' {
9
+ export function createFromReadableStream<T>(
10
+ stream: ReadableStream<Uint8Array>,
11
+ options?: { temporaryReferences?: unknown }
12
+ ): Promise<T>;
13
+
14
+ export function createTemporaryReferenceSet(): unknown;
15
+
16
+ export function encodeReply(
17
+ value: unknown,
18
+ options?: { temporaryReferences?: unknown }
19
+ ): Promise<BodyInit>;
20
+
21
+ export function setServerCallback(
22
+ fn: (id: string, args: unknown[]) => Promise<unknown>
23
+ ): void;
24
+ }
25
+
26
+ declare module 'react-server-dom-rspack/client.node' {
27
+ export * from 'react-server-dom-rspack/client.browser';
28
+ }
29
+
30
+ declare module 'react-server-dom-rspack/server.node' {
31
+ import type { ReactFormState } from 'react-dom/client';
32
+
33
+ export function createTemporaryReferenceSet(): unknown;
34
+
35
+ export function decodeAction(
36
+ body: FormData,
37
+ serverManifest?: unknown
38
+ ): Promise<() => Promise<unknown>>;
39
+
40
+ export function decodeFormState(
41
+ actionResult: unknown,
42
+ body: FormData,
43
+ serverManifest?: unknown
44
+ ): Promise<ReactFormState | null>;
45
+
46
+ export function decodeReply(
47
+ body: FormData | string,
48
+ options?: { temporaryReferences?: unknown }
49
+ ): Promise<unknown[]>;
50
+
51
+ export function loadServerAction(
52
+ actionId: string
53
+ ): (...args: unknown[]) => unknown;
54
+
55
+ export function renderToReadableStream(
56
+ model: unknown,
57
+ options?: {
58
+ onError?: (error: unknown) => string | undefined;
59
+ temporaryReferences?: unknown;
60
+ }
61
+ ): ReadableStream<Uint8Array>;
62
+ }
63
+
64
+ declare module 'virtual/react-router/unstable_rsc/routes' {
65
+ import type { unstable_RSCRouteConfig as RSCRouteConfig } from 'react-router';
66
+ const routes: RSCRouteConfig;
67
+ export default routes;
68
+ }
69
+
70
+ declare module 'virtual/react-router/unstable_rsc/route-discovery' {
71
+ const routeDiscovery:
72
+ | { mode: 'initial' }
73
+ | { mode: 'lazy'; manifestPath?: string };
74
+ export default routeDiscovery;
75
+ }
76
+
77
+ declare module 'virtual/react-router/unstable_rsc/basename' {
78
+ const basename: string;
79
+ export default basename;
80
+ }
81
+
82
+ declare module 'virtual/react-router/unstable_rsc/allowed-action-origins' {
83
+ const allowedActionOrigins: string[] | undefined;
84
+ export default allowedActionOrigins;
85
+ }
86
+
87
+ declare module 'virtual/react-router/unstable_rsc/client-version' {
88
+ const clientVersion: string | undefined;
89
+ export default clientVersion;
90
+ }
91
+
92
+ declare module 'virtual/react-router/unstable_rsc/react-router-serve-config' {
93
+ const config: {
94
+ assetsBuildDirectory: string;
95
+ publicPath: string;
96
+ };
97
+ export default config;
98
+ }
99
+
100
+ declare module 'virtual/react-router/unstable_rsc/inject-hmr-runtime' {}
101
+
102
+ declare module 'virtual/react-router/unstable_rsc/bootstrap-scripts' {
103
+ const bootstrapScripts: string[];
104
+ export default bootstrapScripts;
105
+ }
106
+
107
+ declare module 'virtual/react-router/unstable_rsc/server-manifest' {
108
+ export default function getServerManifest(): unknown;
109
+ }
110
+
111
+ declare module 'virtual:react-router/unstable_rsc/routes' {
112
+ export { default } from 'virtual/react-router/unstable_rsc/routes';
113
+ }
114
+
115
+ declare module 'virtual:react-router/unstable_rsc/route-discovery' {
116
+ export { default } from 'virtual/react-router/unstable_rsc/route-discovery';
117
+ }
118
+
119
+ declare module 'virtual:react-router/unstable_rsc/basename' {
120
+ export { default } from 'virtual/react-router/unstable_rsc/basename';
121
+ }
122
+
123
+ declare module 'virtual:react-router/unstable_rsc/allowed-action-origins' {
124
+ export { default } from 'virtual/react-router/unstable_rsc/allowed-action-origins';
125
+ }
126
+
127
+ declare module 'virtual:react-router/unstable_rsc/client-version' {
128
+ export { default } from 'virtual/react-router/unstable_rsc/client-version';
129
+ }
130
+
131
+ declare module 'virtual:react-router/unstable_rsc/react-router-serve-config' {
132
+ export { default } from 'virtual/react-router/unstable_rsc/react-router-serve-config';
133
+ }
134
+
135
+ declare module 'virtual:react-router/unstable_rsc/inject-hmr-runtime' {}
136
+
137
+ declare module 'virtual:react-router/unstable_rsc/bootstrap-scripts' {
138
+ export { default } from 'virtual/react-router/unstable_rsc/bootstrap-scripts';
139
+ }
140
+
141
+ declare module 'virtual:react-router/unstable_rsc/server-manifest' {
142
+ export { default } from 'virtual/react-router/unstable_rsc/server-manifest';
143
+ }
@@ -0,0 +1,116 @@
1
+ import type { RsbuildPlugin } from '@rsbuild/core';
2
+ import { getPackageVersion, parseVersionMajorMinor } from './plugin-utils.js';
3
+ import type { Config } from './react-router-config.js';
4
+ import type { PluginOptions } from './types.js';
5
+
6
+ type RscPluginOptions = Exclude<NonNullable<PluginOptions['rsc']>, boolean>;
7
+ type RscUnsupportedConfig = Pick<
8
+ Config,
9
+ 'buildEnd' | 'future' | 'presets' | 'serverBundles' | 'subResourceIntegrity'
10
+ >;
11
+
12
+ // Mirrors upstream @react-router/dev's RSC-mode validateConfig: these
13
+ // options have no effect in RSC framework mode, so reject them loudly
14
+ // instead of silently dropping them.
15
+ export const assertReactRouterRscConfigSupport = ({
16
+ pluginName,
17
+ userConfig,
18
+ }: {
19
+ pluginName: string;
20
+ userConfig: RscUnsupportedConfig;
21
+ }): void => {
22
+ const unsupported: string[] = [];
23
+ if (userConfig.buildEnd) unsupported.push('buildEnd');
24
+ if (userConfig.presets?.length) unsupported.push('presets');
25
+ if (userConfig.serverBundles) unsupported.push('serverBundles');
26
+ if (userConfig.subResourceIntegrity) unsupported.push('subResourceIntegrity');
27
+ if (unsupported.length) {
28
+ throw new Error(
29
+ `[${pluginName}] RSC Framework Mode does not currently support the ` +
30
+ `following React Router config:\n${unsupported
31
+ .map(option => ` - ${option}`)
32
+ .join('\n')}\n`
33
+ );
34
+ }
35
+ };
36
+
37
+ const supportsReactRouterRsc = (version: string | undefined): boolean => {
38
+ const parsed = parseVersionMajorMinor(version);
39
+ if (!parsed) {
40
+ return false;
41
+ }
42
+ return parsed.major >= 8 || (parsed.major === 7 && parsed.minor >= 18);
43
+ };
44
+
45
+ export const assertReactRouterRscSupport = ({
46
+ pluginName,
47
+ resolvePackagePath,
48
+ }: {
49
+ pluginName: string;
50
+ resolvePackagePath: (specifier: string) => string | undefined;
51
+ }): void => {
52
+ const reactRouterVersion = getPackageVersion(
53
+ 'react-router',
54
+ resolvePackagePath
55
+ );
56
+ if (!supportsReactRouterRsc(reactRouterVersion)) {
57
+ throw new Error(
58
+ `[${pluginName}] React Router RSC mode requires react-router >=7.18.0 or >=8.0.0.`
59
+ );
60
+ }
61
+
62
+ for (const specifier of [
63
+ 'react-server-dom-rspack/client.browser',
64
+ 'rsbuild-plugin-rsc',
65
+ ]) {
66
+ if (!resolvePackagePath(specifier)) {
67
+ throw new Error(
68
+ `[${pluginName}] React Router RSC mode requires \`${specifier}\` to be installed.`
69
+ );
70
+ }
71
+ }
72
+ };
73
+
74
+ export const setupReactRouterRscPlugin = async ({
75
+ api,
76
+ entryRscPath,
77
+ entrySsrPath,
78
+ pluginName,
79
+ rsc,
80
+ }: {
81
+ api: Parameters<RsbuildPlugin['setup']>[0];
82
+ entryRscPath: string;
83
+ entrySsrPath: string;
84
+ pluginName: string;
85
+ rsc: RscPluginOptions;
86
+ }): Promise<void> => {
87
+ const { PLUGIN_RSC_NAME } = await import('rsbuild-plugin-rsc');
88
+ if (api.isPluginExists(PLUGIN_RSC_NAME)) {
89
+ throw new Error(
90
+ `[${pluginName}] The "${PLUGIN_RSC_NAME}" plugin is already registered. ` +
91
+ `Remove the separately configured plugin and pass RSC options through ` +
92
+ `"${pluginName}" so the managed node/web environments stay aligned.`
93
+ );
94
+ }
95
+
96
+ const { pluginRSC } = await import('rsbuild-plugin-rsc');
97
+ await pluginRSC({
98
+ ...rsc,
99
+ environments: {
100
+ server: 'node',
101
+ client: 'web',
102
+ },
103
+ layers: {
104
+ rsc: [entryRscPath],
105
+ ssr: [entrySsrPath],
106
+ ...rsc.layers,
107
+ },
108
+ }).setup(api);
109
+ };
110
+
111
+ export { createReactRouterRscDevServerSetup } from './rsc-dev-server.js';
112
+ export { registerReactRouterRscRouteTransforms } from './rsc-route-transform-registration.js';
113
+ export {
114
+ createReactRouterRscResolveAliases,
115
+ createReactRouterRscVirtualModules,
116
+ } from './rsc-virtual-modules.js';
@@ -0,0 +1,113 @@
1
+ import { relative, resolve } from 'pathe';
2
+ import type { Config } from './react-router-config.js';
3
+ import type { Route } from './types.js';
4
+ import { combineURLs, normalizeAssetPrefix } from './plugin-utils.js';
5
+ import { getVirtualModuleFilePath } from './virtual-modules.js';
6
+ import {
7
+ createRscInternalClientModule,
8
+ createRscRouteConfig,
9
+ } from './rsc-route-config.js';
10
+
11
+ const defaultExport = (value: unknown): string =>
12
+ `export default ${JSON.stringify(value)};`;
13
+
14
+ const RSC_VIRTUAL_ALIAS_IDS = [
15
+ 'routes',
16
+ 'route-discovery',
17
+ 'inject-hmr-runtime',
18
+ 'basename',
19
+ 'allowed-action-origins',
20
+ 'client-version',
21
+ 'react-router-serve-config',
22
+ 'bootstrap-scripts',
23
+ 'server-manifest',
24
+ ] as const;
25
+
26
+ type RscVirtualModulesOptions = {
27
+ allowedActionOrigins: string[] | undefined;
28
+ appDirectory: string;
29
+ basename: string;
30
+ buildDirectory: string;
31
+ isBuild: boolean;
32
+ /** Resolved web `output.distPath.js` segment, e.g. `static/js`. */
33
+ jsDistPath: string;
34
+ outputClientPath: string;
35
+ publicPath: string;
36
+ routeDiscovery: Config['routeDiscovery'];
37
+ routes: Record<string, Route>;
38
+ ssr: boolean;
39
+ };
40
+
41
+ export const createReactRouterRscResolveAliases = (
42
+ rootPath: string
43
+ ): Record<string, string> => ({
44
+ ...Object.fromEntries(
45
+ RSC_VIRTUAL_ALIAS_IDS.flatMap(id => {
46
+ const moduleId = `virtual/react-router/unstable_rsc/${id}`;
47
+ const modulePath = resolve(rootPath, getVirtualModuleFilePath(moduleId));
48
+ return [
49
+ [`virtual:react-router/unstable_rsc/${id}`, modulePath],
50
+ [moduleId, modulePath],
51
+ ];
52
+ })
53
+ ),
54
+ 'react-router/internal/react-server-client': resolve(
55
+ rootPath,
56
+ getVirtualModuleFilePath('virtual/react-router/rsc-internal-client')
57
+ ),
58
+ });
59
+
60
+ export const createReactRouterRscVirtualModules = ({
61
+ allowedActionOrigins,
62
+ appDirectory,
63
+ basename,
64
+ buildDirectory,
65
+ isBuild,
66
+ jsDistPath,
67
+ outputClientPath,
68
+ publicPath,
69
+ routeDiscovery,
70
+ routes,
71
+ ssr,
72
+ }: RscVirtualModulesOptions): Record<string, string> => {
73
+ const rscAssetsBuildDirectory = relative(
74
+ resolve(buildDirectory, 'server'),
75
+ outputClientPath
76
+ );
77
+ const bootstrapPublicPath = normalizeAssetPrefix(publicPath);
78
+
79
+ return {
80
+ 'virtual/react-router/unstable_rsc/routes': createRscRouteConfig({
81
+ appDirectory,
82
+ routes,
83
+ }),
84
+ 'virtual/react-router/unstable_rsc/route-discovery': defaultExport(
85
+ ssr === false ? { mode: 'initial' } : (routeDiscovery ?? { mode: 'lazy' })
86
+ ),
87
+ 'virtual/react-router/unstable_rsc/inject-hmr-runtime': !isBuild
88
+ ? `if (import.meta.webpackHot) {
89
+ // The RSC client entry owns update navigation; this boundary only self-accepts.
90
+ import.meta.webpackHot.accept();
91
+ }`
92
+ : '',
93
+ 'virtual/react-router/unstable_rsc/basename': defaultExport(basename),
94
+ 'virtual/react-router/unstable_rsc/allowed-action-origins':
95
+ defaultExport(allowedActionOrigins),
96
+ 'virtual/react-router/unstable_rsc/client-version': isBuild
97
+ ? 'export default __webpack_hash__;'
98
+ : 'export default undefined;',
99
+ 'virtual/react-router/unstable_rsc/react-router-serve-config':
100
+ defaultExport({
101
+ assetsBuildDirectory: rscAssetsBuildDirectory,
102
+ publicPath,
103
+ }),
104
+ 'virtual/react-router/unstable_rsc/bootstrap-scripts': defaultExport([
105
+ combineURLs(bootstrapPublicPath, `${jsDistPath}/index.js`),
106
+ ]),
107
+ 'virtual/react-router/unstable_rsc/server-manifest': `export default function getServerManifest() {
108
+ return __webpack_require__.rscM?.serverManifest;
109
+ }
110
+ `,
111
+ 'virtual/react-router/rsc-internal-client': createRscInternalClientModule(),
112
+ };
113
+ };
@@ -62,6 +62,7 @@ export const createReactRouterNodeEntries = ({
62
62
  isBuild,
63
63
  serverAppPath,
64
64
  entryServerPath,
65
+ serverBuildFile,
65
66
  defaultEntryName,
66
67
  serverBundleEntries,
67
68
  }: {
@@ -69,16 +70,26 @@ export const createReactRouterNodeEntries = ({
69
70
  isBuild: boolean;
70
71
  serverAppPath: string;
71
72
  entryServerPath: string;
73
+ serverBuildFile: string | undefined;
72
74
  defaultEntryName: string;
73
75
  serverBundleEntries: readonly ReactRouterServerBundleEntry[];
74
76
  }): Record<string, string> => {
77
+ const appEntry = hasServerApp
78
+ ? serverAppPath
79
+ : 'virtual/react-router/server-build';
75
80
  const entries: Record<string, string> = {
76
- 'static/js/app': hasServerApp
77
- ? serverAppPath
78
- : 'virtual/react-router/server-build',
81
+ 'static/js/app': appEntry,
79
82
  'static/js/entry.server': entryServerPath,
80
83
  };
81
84
 
85
+ if (isBuild) {
86
+ const configuredEntryName = (serverBuildFile || 'index.js').replace(
87
+ /\.js$/,
88
+ ''
89
+ );
90
+ entries[configuredEntryName] = appEntry;
91
+ }
92
+
82
93
  if (hasServerApp && !isBuild) {
83
94
  entries[defaultEntryName] = 'virtual/react-router/server-build';
84
95
  }
@@ -1,10 +1,7 @@
1
- // Internal module: exposes the Effect-based ServerBuild resolution used by
2
- // dev-runtime code. Not re-exported from the package entry so the public
3
- // declaration graph stays free of `effect` types; external callers go through
4
- // the Promise wrappers in server-utils.ts.
5
- import * as Effect from 'effect/Effect';
1
+ // Internal module: exposes ServerBuild resolution used by dev-runtime code.
2
+ // External callers go through the Promise wrappers in server-utils.ts.
6
3
  import type { ServerBuild } from 'react-router';
7
- import { tryPluginPromise, tryPluginSync } from './effect-runtime.js';
4
+ import { normalizeEffectError } from './effect-runtime.js';
8
5
 
9
6
  const RESOLVABLE_BUILD_EXPORTS = new Set([
10
7
  'allowedActionOrigins',
@@ -40,31 +37,25 @@ function isRouteDiscovery(value: unknown): boolean {
40
37
  );
41
38
  }
42
39
 
43
- function resolveBuildExportsEffect(
40
+ async function resolveBuildExports(
44
41
  build: Record<string, unknown>
45
- ): Effect.Effect<Record<string, unknown>, Error, never> {
42
+ ): Promise<Record<string, unknown>> {
46
43
  const resolved = { ...build };
47
- return Effect.forEach(
48
- Object.keys(build),
49
- key =>
50
- Effect.gen(function* () {
51
- if (!RESOLVABLE_BUILD_EXPORTS.has(key)) {
52
- return;
53
- }
54
- const value = build[key];
55
- if (typeof value === 'function' && value.length === 0) {
56
- const result = yield* tryPluginSync(() => value());
57
- resolved[key] = isPromiseLike(result)
58
- ? yield* tryPluginPromise(() => result)
59
- : result;
60
- return;
61
- }
62
- if (isPromiseLike(value)) {
63
- resolved[key] = yield* tryPluginPromise(() => value);
64
- }
65
- }),
66
- { discard: true }
67
- ).pipe(Effect.as(resolved));
44
+ for (const key of Object.keys(build)) {
45
+ if (!RESOLVABLE_BUILD_EXPORTS.has(key)) {
46
+ continue;
47
+ }
48
+ const value = build[key];
49
+ if (typeof value === 'function' && value.length === 0) {
50
+ const result = value();
51
+ resolved[key] = isPromiseLike(result) ? await result : result;
52
+ continue;
53
+ }
54
+ if (isPromiseLike(value)) {
55
+ resolved[key] = await value;
56
+ }
57
+ }
58
+ return resolved;
68
59
  }
69
60
 
70
61
  function isServerBuild(value: unknown): value is ServerBuild {
@@ -86,26 +77,25 @@ function isServerBuild(value: unknown): value is ServerBuild {
86
77
  );
87
78
  }
88
79
 
89
- function resolveServerBuildCandidateEffect(
80
+ async function resolveServerBuildCandidate(
90
81
  candidate: unknown
91
- ): Effect.Effect<ServerBuild | undefined, Error, never> {
82
+ ): Promise<ServerBuild | undefined> {
92
83
  if (!isRecord(candidate)) {
93
- return Effect.succeed(undefined);
84
+ return undefined;
94
85
  }
95
- return resolveBuildExportsEffect(candidate).pipe(
96
- Effect.map(resolved => (isServerBuild(resolved) ? resolved : undefined))
97
- );
86
+ const resolved = await resolveBuildExports(candidate);
87
+ return isServerBuild(resolved) ? resolved : undefined;
98
88
  }
99
89
 
100
- export function resolveServerBuildModuleEffect(
90
+ export async function resolveServerBuildModule(
101
91
  buildModule: unknown,
102
92
  source: string
103
- ): Effect.Effect<ServerBuild, Error, never> {
104
- return Effect.gen(function* () {
93
+ ): Promise<ServerBuild> {
94
+ try {
105
95
  const moduleValue = isPromiseLike(buildModule)
106
- ? yield* tryPluginPromise(() => buildModule)
96
+ ? await buildModule
107
97
  : buildModule;
108
- const candidates = [() => moduleValue];
98
+ const candidates: Array<() => unknown> = [() => moduleValue];
109
99
  if (isRecord(moduleValue)) {
110
100
  if ('default' in moduleValue) {
111
101
  candidates.push(() => moduleValue.default);
@@ -116,16 +106,16 @@ export function resolveServerBuildModuleEffect(
116
106
  }
117
107
 
118
108
  for (const getCandidate of candidates) {
119
- const candidate = yield* tryPluginPromise(() => getCandidate());
120
- const serverBuild = yield* resolveServerBuildCandidateEffect(candidate);
109
+ const candidate = await getCandidate();
110
+ const serverBuild = await resolveServerBuildCandidate(candidate);
121
111
  if (serverBuild) {
122
112
  return serverBuild;
123
113
  }
124
114
  }
125
- return yield* Effect.fail(
126
- new Error(
127
- `[rsbuild-plugin-react-router] ${source} did not contain a valid React Router ServerBuild.`
128
- )
115
+ throw new Error(
116
+ `[rsbuild-plugin-react-router] ${source} did not contain a valid React Router ServerBuild.`
129
117
  );
130
- });
118
+ } catch (cause) {
119
+ throw normalizeEffectError(cause);
120
+ }
131
121
  }
@@ -1,7 +1,6 @@
1
1
  import { resolve } from 'pathe';
2
2
  import type { ServerBuild } from 'react-router';
3
- import { runPluginEffect } from './effect-runtime.js';
4
- import { resolveServerBuildModuleEffect } from './server-build-resolution.js';
3
+ import { resolveServerBuildModule } from './server-build-resolution.js';
5
4
  import type { Route } from './types.js';
6
5
 
7
6
  /**
@@ -17,6 +16,7 @@ interface ServerBuildOptions {
17
16
  basename: string;
18
17
  appDirectory: string;
19
18
  ssr: boolean;
19
+ isSpaMode: boolean;
20
20
  future?: unknown;
21
21
  allowedActionOrigins?: string[];
22
22
  prerender?: string[];
@@ -33,19 +33,28 @@ interface ServerBuildOptions {
33
33
  | undefined;
34
34
  }
35
35
 
36
- function generateStaticTemplate(
36
+ /**
37
+ * Generates the server build module content
38
+ * @param routes The route manifest
39
+ * @param options Build options
40
+ * @returns The generated module content as a string
41
+ */
42
+ export function generateServerBuild(
37
43
  routes: Record<string, Route>,
38
44
  options: ServerBuildOptions
39
45
  ): string {
40
46
  const manifestId =
41
47
  options.serverManifestId ?? 'virtual/react-router/server-manifest';
48
+ const routeEntries = Object.entries(routes);
42
49
  return `
43
50
  import * as entryServer from ${JSON.stringify(options.entryServerPath)};
44
- ${Object.keys(routes)
45
- .map((key, index) => {
46
- const route = routes[key];
51
+ ${routeEntries
52
+ .map(([, route], index) => {
53
+ if (options.isSpaMode && route.id !== 'root') {
54
+ return `const route${index} = { default: () => null };`;
55
+ }
47
56
  return `import * as route${index} from ${JSON.stringify(
48
- `${resolve(options.appDirectory, route.file)}?react-router-route`
57
+ resolve(options.appDirectory, route.file)
49
58
  )};`;
50
59
  })
51
60
  .join('\n')}
@@ -56,7 +65,7 @@ function generateStaticTemplate(
56
65
  )};
57
66
  export const basename = ${JSON.stringify(options.basename)};
58
67
  export const future = ${JSON.stringify(options.future ?? {})};
59
- export const isSpaMode = ${!options.ssr};
68
+ export const isSpaMode = ${options.isSpaMode};
60
69
  export const ssr = ${options.ssr};
61
70
  export const routeDiscovery = ${JSON.stringify(options.routeDiscovery)};
62
71
  export const prerender = ${JSON.stringify(options.prerender ?? [])};
@@ -64,9 +73,8 @@ function generateStaticTemplate(
64
73
  export const entry = { module: entryServer };
65
74
  export const allowedActionOrigins = ${JSON.stringify(options.allowedActionOrigins)};
66
75
  export var routes = {};
67
- ${Object.keys(routes)
68
- .map((key, index) => {
69
- const route = routes[key];
76
+ ${routeEntries
77
+ .map(([key, route], index) => {
70
78
  return `routes[${JSON.stringify(key)}] = {
71
79
  id: ${JSON.stringify(route.id)},
72
80
  parentId: ${JSON.stringify(route.parentId)},
@@ -80,32 +88,10 @@ function generateStaticTemplate(
80
88
  `;
81
89
  }
82
90
 
83
- /**
84
- * Generates the server build module content
85
- * @param routes The route manifest
86
- * @param options Build options
87
- * @returns The generated module content as a string
88
- */
89
- function generateServerBuild(
90
- routes: Record<string, Route>,
91
- options: ServerBuildOptions & { federation?: boolean }
92
- ): string {
93
- return generateStaticTemplate(routes, options);
94
- }
95
-
96
- export function resolveServerBuildModule(
97
- buildModule: unknown,
98
- source: string
99
- ): Promise<ServerBuild> {
100
- return runPluginEffect(resolveServerBuildModuleEffect(buildModule, source));
101
- }
91
+ export { resolveServerBuildModule };
102
92
 
103
93
  export function resolveReactRouterServerBuild(
104
94
  buildModule: unknown
105
95
  ): Promise<ServerBuild> {
106
- return runPluginEffect(
107
- resolveServerBuildModuleEffect(buildModule, 'Imported module')
108
- );
96
+ return resolveServerBuildModule(buildModule, 'Imported module');
109
97
  }
110
-
111
- export { generateServerBuild };