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.
- package/README.md +58 -208
- package/dist/511.js +370 -331
- package/dist/build-output-transforms.d.ts +30 -6
- package/dist/classic-mode.d.ts +56 -0
- package/dist/config-imports.d.ts +8 -2
- package/dist/constants.d.ts +3 -0
- package/dist/dev-background-resources.d.ts +3 -1
- package/dist/dev-generation.d.ts +2 -3
- package/dist/dev-hmr.d.ts +8 -2
- package/dist/dev-runtime-controller.d.ts +6 -1
- package/dist/dev-source-maps.d.ts +4 -0
- package/dist/effect-runtime.d.ts +17 -5
- package/dist/entry-paths.d.ts +16 -0
- package/dist/environment-output.d.ts +6 -0
- package/dist/export-utils.d.ts +2 -1
- package/dist/index.cjs +3957 -2208
- package/dist/index.d.ts +3 -1
- package/dist/index.js +3470 -1793
- package/dist/lazy-compilation-prewarm.d.ts +8 -5
- package/dist/manifest.d.ts +16 -4
- package/dist/mode-plan.d.ts +82 -0
- package/dist/modify-browser-manifest.d.ts +8 -4
- package/dist/plugin-utils.d.ts +27 -1
- package/dist/prerender-build.d.ts +5 -5
- package/dist/prerender.d.ts +1 -5
- package/dist/react-router-config.d.ts +11 -3
- package/dist/route-artifacts.d.ts +4 -2
- package/dist/route-chunks.d.ts +2 -1
- package/dist/route-component-transform.d.ts +0 -2
- package/dist/route-export-pruning.d.ts +4 -1
- package/dist/route-imports.d.ts +18 -0
- package/dist/route-transform-tasks.d.ts +5 -0
- package/dist/route-watch.d.ts +11 -6
- package/dist/rsc-dev-server.d.ts +26 -0
- package/dist/rsc-prerender.d.ts +54 -0
- package/dist/rsc-route-config.d.ts +6 -0
- package/dist/rsc-route-exports.d.ts +15 -0
- package/dist/rsc-route-transform-loader.cjs +43 -0
- package/dist/rsc-route-transform-loader.d.ts +30 -0
- package/dist/rsc-route-transform-loader.js +16 -0
- package/dist/rsc-route-transform-registration.d.ts +12 -0
- package/dist/rsc-route-transforms.d.ts +21 -0
- package/dist/rsc-support.d.ts +23 -0
- package/dist/rsc-virtual-modules.d.ts +19 -0
- package/dist/server-build-plan.d.ts +2 -1
- package/dist/server-build-resolution.d.ts +1 -2
- package/dist/server-utils.d.ts +4 -5
- package/dist/ssr-asset-relocation.d.ts +98 -0
- package/dist/templates/entry.rsc.client.d.ts +1 -0
- package/dist/templates/entry.rsc.client.js +61 -0
- package/dist/templates/entry.rsc.d.ts +9 -0
- package/dist/templates/entry.rsc.js +38 -0
- package/dist/templates/entry.rsc.ssr.d.ts +4 -0
- package/dist/templates/entry.rsc.ssr.js +24 -0
- package/dist/typegen.d.ts +4 -2
- package/dist/types.d.ts +30 -1
- package/package.json +69 -14
- package/src/build-output-transforms.ts +155 -21
- package/src/classic-mode.ts +253 -0
- package/src/config-imports.ts +153 -6
- package/src/constants.ts +6 -2
- package/src/dev-background-resources.ts +46 -85
- package/src/dev-generation.ts +52 -33
- package/src/dev-hmr.ts +112 -80
- package/src/dev-runtime-artifacts.ts +11 -12
- package/src/dev-runtime-controller.ts +75 -85
- package/src/dev-runtime-session.ts +14 -18
- package/src/dev-server.ts +2 -0
- package/src/dev-source-maps.ts +257 -0
- package/src/effect-runtime.ts +105 -57
- package/src/entry-paths.ts +80 -0
- package/src/environment-output.ts +55 -0
- package/src/export-utils.ts +15 -11
- package/src/index.ts +661 -496
- package/src/lazy-compilation-prewarm.ts +20 -4
- package/src/manifest.ts +157 -82
- package/src/mode-plan.ts +367 -0
- package/src/modify-browser-manifest.ts +130 -124
- package/src/plugin-utils.ts +103 -39
- package/src/prerender-build.ts +82 -104
- package/src/prerender.ts +23 -24
- package/src/react-router-config.ts +72 -26
- package/src/route-artifacts.ts +96 -66
- package/src/route-chunks.ts +167 -51
- package/src/route-component-transform.ts +14 -21
- package/src/route-export-pruning.ts +4 -3
- package/src/route-imports.ts +100 -0
- package/src/route-transform-tasks.ts +39 -25
- package/src/route-watch.ts +166 -188
- package/src/rsc-dev-server.ts +112 -0
- package/src/rsc-prerender.ts +362 -0
- package/src/rsc-route-config.ts +175 -0
- package/src/rsc-route-exports.ts +67 -0
- package/src/rsc-route-transform-loader.ts +65 -0
- package/src/rsc-route-transform-registration.ts +145 -0
- package/src/rsc-route-transforms.ts +995 -0
- package/src/rsc-runtime.d.ts +143 -0
- package/src/rsc-support.ts +116 -0
- package/src/rsc-virtual-modules.ts +113 -0
- package/src/server-build-plan.ts +14 -3
- package/src/server-build-resolution.ts +37 -47
- package/src/server-utils.ts +21 -35
- package/src/ssr-asset-relocation.ts +183 -0
- package/src/ssr-externals.ts +8 -26
- package/src/templates/entry.rsc.client.tsx +168 -0
- package/src/templates/entry.rsc.ssr.tsx +45 -0
- package/src/templates/entry.rsc.tsx +80 -0
- package/src/typegen.ts +40 -23
- package/src/types.ts +39 -1
- package/src/warnings/warn-on-client-source-maps.ts +6 -10
package/src/index.ts
CHANGED
|
@@ -2,56 +2,47 @@ import { existsSync, readFileSync } from 'node:fs';
|
|
|
2
2
|
import fsExtra from 'fs-extra';
|
|
3
3
|
import type { Config } from './react-router-config.js';
|
|
4
4
|
import type { RouteConfigEntry } from '@react-router/dev/routes';
|
|
5
|
-
import {
|
|
6
|
-
rspack,
|
|
7
|
-
type RsbuildEntryDescription,
|
|
8
|
-
type RsbuildPlugin,
|
|
9
|
-
type Rspack,
|
|
10
|
-
} from '@rsbuild/core';
|
|
11
|
-
import { createJiti } from 'jiti';
|
|
5
|
+
import { rspack, type RsbuildPlugin, type Rspack } from '@rsbuild/core';
|
|
12
6
|
import { relative, resolve } from 'pathe';
|
|
13
7
|
|
|
14
8
|
import { getDefaultConcurrency } from './concurrency.js';
|
|
15
9
|
import {
|
|
16
|
-
|
|
10
|
+
DEFAULT_JS_DIST_PATH,
|
|
17
11
|
JS_EXTENSIONS,
|
|
18
12
|
PLUGIN_NAME,
|
|
19
13
|
} from './constants.js';
|
|
20
14
|
import { guardReactRouterLazyCompilation } from './lazy-compilation.js';
|
|
21
|
-
import { ensureFederationAsyncStartup } from './federation.js';
|
|
22
|
-
import { createReactRouterDevServerSetup } from './dev-server.js';
|
|
23
15
|
import {
|
|
24
|
-
generateWithProps,
|
|
25
16
|
findEntryFile,
|
|
26
|
-
|
|
17
|
+
resolveAppPackagePath,
|
|
18
|
+
resolveEffectiveAssetPrefix,
|
|
27
19
|
} from './plugin-utils.js';
|
|
28
|
-
import
|
|
29
|
-
import {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
} from './
|
|
33
|
-
import { resolvePrerenderPaths, validatePrerenderConfig } from './prerender.js';
|
|
20
|
+
import { resolveReactRouterEntryPaths } from './entry-paths.js';
|
|
21
|
+
import { registerReactRouterEnvironmentOutput } from './environment-output.js';
|
|
22
|
+
import type { PluginOptions, ReactRouterRSCPluginOptions } from './types.js';
|
|
23
|
+
import { resolveReactRouterServerBuild } from './server-utils.js';
|
|
24
|
+
import { validatePrerenderConfig } from './prerender.js';
|
|
34
25
|
import { runReactRouterPrerenderBuild } from './prerender-build.js';
|
|
26
|
+
import { runReactRouterRscPrerenderBuild } from './rsc-prerender.js';
|
|
35
27
|
import {
|
|
36
|
-
|
|
28
|
+
resolveReactRouterConfigEffect,
|
|
29
|
+
resolveRouteDiscoveryConfig,
|
|
37
30
|
type ResolvedReactRouterConfig,
|
|
38
31
|
} from './react-router-config.js';
|
|
39
32
|
import {
|
|
40
|
-
getReactRouterManifestForDev,
|
|
41
33
|
configRoutesToRouteManifest,
|
|
42
34
|
createReactRouterManifestStats,
|
|
35
|
+
type ReactRouterManifestForDev as ReactRouterManifest,
|
|
43
36
|
type ReactRouterManifestStats,
|
|
44
37
|
type RouteManifestModuleExports,
|
|
45
38
|
} from './manifest.js';
|
|
39
|
+
import type { RouteModuleAnalysis } from './export-utils.js';
|
|
46
40
|
import { registerModifyBrowserManifestAssets } from './modify-browser-manifest.js';
|
|
47
|
-
import { registerBuildOutputTransforms } from './build-output-transforms.js';
|
|
48
41
|
import {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
type RouteChunkConfig,
|
|
54
|
-
} from './route-chunks.js';
|
|
42
|
+
registerBuildOutputTransforms,
|
|
43
|
+
registerSsrAssetRelocation,
|
|
44
|
+
} from './build-output-transforms.js';
|
|
45
|
+
import { type RouteChunkCache } from './route-chunks.js';
|
|
55
46
|
import {
|
|
56
47
|
registerRouteModuleTransformRules,
|
|
57
48
|
shouldUseRouteModuleTransformLoader,
|
|
@@ -62,46 +53,58 @@ import {
|
|
|
62
53
|
} from './route-transform-tasks.js';
|
|
63
54
|
import { getRouteRestartMarkerPath, mergeWatchFiles } from './route-watch.js';
|
|
64
55
|
import { validateRouteConfig } from './route-config.js';
|
|
65
|
-
import {
|
|
66
|
-
getBuildManifest,
|
|
67
|
-
getRoutesByServerBundleId,
|
|
68
|
-
} from './build-manifest.js';
|
|
69
|
-
import {
|
|
70
|
-
createReactRouterNodeEntries,
|
|
71
|
-
createReactRouterServerBuildPlan,
|
|
72
|
-
} from './server-build-plan.js';
|
|
73
56
|
import { warnOnClientSourceMaps } from './warnings/warn-on-client-source-maps.js';
|
|
74
57
|
import { validatePluginOrderFromConfig } from './validation/validate-plugin-order.js';
|
|
75
|
-
import { getSsrExternals } from './ssr-externals.js';
|
|
76
58
|
import {
|
|
77
59
|
createReactRouterPerformanceProfiler,
|
|
78
60
|
roundMs,
|
|
79
61
|
} from './performance.js';
|
|
80
62
|
import { mapVirtualModules } from './virtual-modules.js';
|
|
81
|
-
import { createReactRouterDevRuntimeController } from './dev-runtime-controller.js';
|
|
82
|
-
import { runPluginEffect, tryPluginPromise } from './effect-runtime.js';
|
|
83
|
-
import { registerReactRouterTypegen } from './typegen.js';
|
|
84
|
-
import { importConfigWithWatchPaths } from './config-imports.js';
|
|
85
|
-
import {
|
|
86
|
-
createReactRouterRouteTopology,
|
|
87
|
-
createReactRouterRouteWatchFiles,
|
|
88
|
-
registerReactRouterDevBackgroundResources,
|
|
89
|
-
} from './dev-background-resources.js';
|
|
90
63
|
import {
|
|
91
64
|
createDevHdrRevisionSignal,
|
|
92
65
|
generateDevHmrRuntimeModule,
|
|
93
66
|
getDevHdrRevisionFilePath,
|
|
94
67
|
isRspackSwcReactRefreshEnabled,
|
|
95
68
|
resolveReactRefreshRuntimePath,
|
|
96
|
-
DEV_HMR_RUNTIME_MODULE_ID,
|
|
97
69
|
} from './dev-hmr.js';
|
|
70
|
+
import {
|
|
71
|
+
createPluginEffectRuntime,
|
|
72
|
+
tryPluginPromise,
|
|
73
|
+
} from './effect-runtime.js';
|
|
74
|
+
import { registerReactRouterTypegen } from './typegen.js';
|
|
75
|
+
import {
|
|
76
|
+
createConfigImporter,
|
|
77
|
+
type ConfigImporter,
|
|
78
|
+
importConfigWithWatchPaths,
|
|
79
|
+
} from './config-imports.js';
|
|
80
|
+
import {
|
|
81
|
+
createReactRouterRouteTopology,
|
|
82
|
+
createReactRouterRouteWatchFiles,
|
|
83
|
+
registerReactRouterDevBackgroundResources,
|
|
84
|
+
} from './dev-background-resources.js';
|
|
85
|
+
import {
|
|
86
|
+
assertReactRouterRscConfigSupport,
|
|
87
|
+
assertReactRouterRscSupport,
|
|
88
|
+
registerReactRouterRscRouteTransforms,
|
|
89
|
+
setupReactRouterRscPlugin,
|
|
90
|
+
} from './rsc-support.js';
|
|
91
|
+
import { createReactRouterModePlan } from './mode-plan.js';
|
|
92
|
+
import { createQuerylessRouteImportPlugin } from './route-imports.js';
|
|
93
|
+
import { registerDevServerSourceMaps } from './dev-source-maps.js';
|
|
98
94
|
|
|
99
95
|
export type { Config as ReactRouterRsbuildConfig } from './react-router-config.js';
|
|
100
96
|
export { loadReactRouterServerBuild } from './dev-generation.js';
|
|
101
97
|
export { resolveReactRouterServerBuild };
|
|
98
|
+
export type { PluginOptions, ReactRouterRSCPluginOptions } from './types.js';
|
|
102
99
|
|
|
103
100
|
const MIN_PARALLEL_ENVIRONMENT_BUILD_SPARE_CORES = 4;
|
|
104
101
|
|
|
102
|
+
type ReactRouterPresetResolvedConfig = Parameters<
|
|
103
|
+
NonNullable<
|
|
104
|
+
NonNullable<Config['presets']>[number]['reactRouterConfigResolved']
|
|
105
|
+
>
|
|
106
|
+
>[0]['reactRouterConfig'];
|
|
107
|
+
|
|
105
108
|
export const shouldParallelizeEnvironmentBuilds = ({
|
|
106
109
|
isBuild,
|
|
107
110
|
spareCoreCount = getDefaultConcurrency(),
|
|
@@ -115,6 +118,56 @@ const cssUrlAssetExtensions =
|
|
|
115
118
|
/\.(?:css|less|sass|scss|styl|stylus|pcss|postcss|sss)$/;
|
|
116
119
|
const urlAssetResourceQuery =
|
|
117
120
|
/^(?=.*(?:\?|&)url(?:&|$))(?!.*(?:\?|&)(?:raw|inline)(?:&|$))/;
|
|
121
|
+
const javascriptWhitespace = /\s/u;
|
|
122
|
+
|
|
123
|
+
const hasUseClientDirective = (code: string): boolean => {
|
|
124
|
+
let index = code.charCodeAt(0) === 0xfeff ? 1 : 0;
|
|
125
|
+
if (code.startsWith('#!', index)) {
|
|
126
|
+
const lineEnd = code.indexOf('\n', index + 2);
|
|
127
|
+
if (lineEnd === -1) return false;
|
|
128
|
+
index = lineEnd + 1;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
while (index < code.length) {
|
|
132
|
+
while (
|
|
133
|
+
index < code.length &&
|
|
134
|
+
javascriptWhitespace.test(code.charAt(index))
|
|
135
|
+
) {
|
|
136
|
+
index += 1;
|
|
137
|
+
}
|
|
138
|
+
if (code.startsWith('//', index)) {
|
|
139
|
+
const lineEnd = code.indexOf('\n', index + 2);
|
|
140
|
+
if (lineEnd === -1) return false;
|
|
141
|
+
index = lineEnd + 1;
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
if (code.startsWith('/*', index)) {
|
|
145
|
+
const commentEnd = code.indexOf('*/', index + 2);
|
|
146
|
+
if (commentEnd === -1) return false;
|
|
147
|
+
index = commentEnd + 2;
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const quote = code.charAt(index);
|
|
154
|
+
if (quote !== '"' && quote !== "'") return false;
|
|
155
|
+
const directive = `${quote}use client${quote}`;
|
|
156
|
+
if (!code.startsWith(directive, index)) return false;
|
|
157
|
+
index += directive.length;
|
|
158
|
+
while (index < code.length && javascriptWhitespace.test(code.charAt(index))) {
|
|
159
|
+
index += 1;
|
|
160
|
+
}
|
|
161
|
+
return code.charAt(index) === ';';
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
const isRscClientModule = (filePath: string): boolean => {
|
|
165
|
+
try {
|
|
166
|
+
return hasUseClientDirective(readFileSync(filePath, 'utf8'));
|
|
167
|
+
} catch {
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
};
|
|
118
171
|
|
|
119
172
|
export const pluginReactRouter = (
|
|
120
173
|
options: PluginOptions = {}
|
|
@@ -122,9 +175,15 @@ export const pluginReactRouter = (
|
|
|
122
175
|
name: PLUGIN_NAME,
|
|
123
176
|
|
|
124
177
|
async setup(api) {
|
|
178
|
+
const effectRuntime = createPluginEffectRuntime();
|
|
179
|
+
api.onCloseBuild(effectRuntime.dispose);
|
|
180
|
+
api.onCloseDevServer(effectRuntime.dispose);
|
|
181
|
+
api.onExit(effectRuntime.dispose);
|
|
182
|
+
|
|
125
183
|
const defaultOptions = {
|
|
126
184
|
customServer: false,
|
|
127
185
|
lazyCompilation: true,
|
|
186
|
+
rsc: false,
|
|
128
187
|
serverOutput: 'module' as const,
|
|
129
188
|
};
|
|
130
189
|
|
|
@@ -132,16 +191,13 @@ export const pluginReactRouter = (
|
|
|
132
191
|
...defaultOptions,
|
|
133
192
|
...options,
|
|
134
193
|
};
|
|
194
|
+
const isRscMode = Boolean(pluginOptions.rsc);
|
|
135
195
|
const logPerformance = pluginOptions.logPerformance === true;
|
|
136
196
|
const setupStartMs = logPerformance ? performance.now() : 0;
|
|
137
197
|
const performanceProfiler = createReactRouterPerformanceProfiler({
|
|
138
198
|
enabled: logPerformance,
|
|
139
199
|
log: message => api.logger.info(message),
|
|
140
200
|
});
|
|
141
|
-
const nodeExternals = Array.from(
|
|
142
|
-
new Set(['express', ...getSsrExternals(process.cwd())])
|
|
143
|
-
);
|
|
144
|
-
|
|
145
201
|
let assetPrefix = '/';
|
|
146
202
|
|
|
147
203
|
// Best-effort configuration validation (upstream: validate-plugin-order).
|
|
@@ -157,7 +213,6 @@ export const pluginReactRouter = (
|
|
|
157
213
|
}
|
|
158
214
|
api.logger.warn(issue.message);
|
|
159
215
|
}
|
|
160
|
-
assetPrefix = normalizeAssetPrefix(config.output?.assetPrefix);
|
|
161
216
|
return config;
|
|
162
217
|
},
|
|
163
218
|
});
|
|
@@ -167,6 +222,15 @@ export const pluginReactRouter = (
|
|
|
167
222
|
warnOnClientSourceMaps(normalized, msg => api.logger.warn(msg), 'web');
|
|
168
223
|
});
|
|
169
224
|
|
|
225
|
+
api.onBeforeCreateCompiler(() => {
|
|
226
|
+
const normalized = api.getNormalizedConfig();
|
|
227
|
+
assetPrefix = resolveEffectiveAssetPrefix({
|
|
228
|
+
dev: normalized.dev,
|
|
229
|
+
output: normalized.output,
|
|
230
|
+
isBuild: api.context.action === 'build',
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
|
|
170
234
|
const configPath = findEntryFile(resolve('react-router.config'));
|
|
171
235
|
const configExists = existsSync(configPath);
|
|
172
236
|
let configWatchPaths: string | string[] = configExists
|
|
@@ -199,9 +263,12 @@ export const pluginReactRouter = (
|
|
|
199
263
|
|
|
200
264
|
const {
|
|
201
265
|
resolved: resolvedConfig,
|
|
266
|
+
userAndPresetConfig,
|
|
202
267
|
presets: configPresets,
|
|
203
268
|
hasConfiguredServerModuleFormat,
|
|
204
|
-
} = await
|
|
269
|
+
} = await effectRuntime.runPromise(
|
|
270
|
+
resolveReactRouterConfigEffect(reactRouterUserConfig)
|
|
271
|
+
);
|
|
205
272
|
|
|
206
273
|
const {
|
|
207
274
|
appDirectory,
|
|
@@ -213,12 +280,17 @@ export const pluginReactRouter = (
|
|
|
213
280
|
ssr,
|
|
214
281
|
prerender: prerenderConfig,
|
|
215
282
|
serverBuildFile,
|
|
283
|
+
serverBundles,
|
|
216
284
|
serverModuleFormat,
|
|
217
285
|
splitRouteModules,
|
|
286
|
+
subResourceIntegrity,
|
|
218
287
|
buildEnd,
|
|
219
288
|
} = resolvedConfig;
|
|
220
289
|
|
|
221
|
-
registerReactRouterTypegen(api, {
|
|
290
|
+
await registerReactRouterTypegen(api, {
|
|
291
|
+
runtime: effectRuntime,
|
|
292
|
+
appDirectory,
|
|
293
|
+
});
|
|
222
294
|
|
|
223
295
|
const hasExplicitServerOutput = Object.prototype.hasOwnProperty.call(
|
|
224
296
|
options,
|
|
@@ -259,57 +331,57 @@ export const pluginReactRouter = (
|
|
|
259
331
|
throw new Error(prerenderConfigError);
|
|
260
332
|
}
|
|
261
333
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
if (!userRouteDiscovery) {
|
|
267
|
-
routeDiscovery = ssr
|
|
268
|
-
? ({ mode: 'lazy', manifestPath: '/__manifest' } as const)
|
|
269
|
-
: ({ mode: 'initial' } as const);
|
|
270
|
-
} else if (userRouteDiscovery.mode === 'initial') {
|
|
271
|
-
routeDiscovery = userRouteDiscovery;
|
|
272
|
-
} else if (userRouteDiscovery.mode === 'lazy') {
|
|
273
|
-
if (!ssr) {
|
|
274
|
-
throw new Error(
|
|
275
|
-
'The `routeDiscovery.mode` config cannot be set to "lazy" when setting `ssr:false`'
|
|
276
|
-
);
|
|
277
|
-
}
|
|
278
|
-
const manifestPath = userRouteDiscovery.manifestPath;
|
|
279
|
-
if (manifestPath && !manifestPath.startsWith('/')) {
|
|
280
|
-
throw new Error(
|
|
281
|
-
'The `routeDiscovery.manifestPath` config must be a root-relative pathname beginning with a slash (i.e., "/__manifest")'
|
|
282
|
-
);
|
|
283
|
-
}
|
|
284
|
-
routeDiscovery = userRouteDiscovery;
|
|
285
|
-
}
|
|
334
|
+
const routeDiscovery = resolveRouteDiscoveryConfig({
|
|
335
|
+
ssr,
|
|
336
|
+
userRouteDiscovery,
|
|
337
|
+
});
|
|
286
338
|
|
|
287
339
|
(globalThis as any).__reactRouterAppDirectory = resolve(appDirectory);
|
|
288
340
|
const routesPath = findEntryFile(resolve(appDirectory, 'routes'));
|
|
289
341
|
if (!existsSync(routesPath)) {
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
routesPath
|
|
294
|
-
)}".`
|
|
342
|
+
const missingRoutesPath = relative(
|
|
343
|
+
process.cwd(),
|
|
344
|
+
resolve(appDirectory, 'routes.ts')
|
|
295
345
|
);
|
|
346
|
+
throw new Error(`Route config file not found at "${missingRoutesPath}".`);
|
|
296
347
|
}
|
|
297
348
|
|
|
298
|
-
const
|
|
349
|
+
const routeConfigDefine =
|
|
350
|
+
typeof api.getRsbuildConfig === 'function'
|
|
351
|
+
? api.getRsbuildConfig().source?.define
|
|
352
|
+
: undefined;
|
|
353
|
+
const jiti = createConfigImporter({
|
|
354
|
+
define: routeConfigDefine,
|
|
299
355
|
moduleCache: false,
|
|
300
356
|
});
|
|
301
357
|
const importRouteConfig = async (
|
|
302
|
-
importer:
|
|
358
|
+
importer: ConfigImporter
|
|
303
359
|
): Promise<RouteConfigEntry[]> => {
|
|
304
|
-
const
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
360
|
+
const routeConfigFile = relative(resolve(appDirectory), routesPath);
|
|
361
|
+
let routeConfigValue: RouteConfigEntry[];
|
|
362
|
+
try {
|
|
363
|
+
const routeConfigExport = await importer.import<RouteConfigEntry[]>(
|
|
364
|
+
routesPath,
|
|
365
|
+
{
|
|
366
|
+
default: true,
|
|
367
|
+
}
|
|
368
|
+
);
|
|
369
|
+
routeConfigValue = await routeConfigExport;
|
|
370
|
+
} catch (error) {
|
|
371
|
+
// Match upstream: import/evaluation failures (e.g. syntax errors) are
|
|
372
|
+
// reported as an invalid route config rather than a raw loader error.
|
|
373
|
+
throw new Error(
|
|
374
|
+
[
|
|
375
|
+
`Route config in "${routeConfigFile}" is invalid.`,
|
|
376
|
+
'',
|
|
377
|
+
error instanceof Error
|
|
378
|
+
? (error.stack ?? error.message)
|
|
379
|
+
: String(error),
|
|
380
|
+
].join('\n')
|
|
381
|
+
);
|
|
382
|
+
}
|
|
311
383
|
const validation = validateRouteConfig({
|
|
312
|
-
routeConfigFile
|
|
384
|
+
routeConfigFile,
|
|
313
385
|
routeConfig: routeConfigValue,
|
|
314
386
|
});
|
|
315
387
|
if (!validation.valid) {
|
|
@@ -319,33 +391,41 @@ export const pluginReactRouter = (
|
|
|
319
391
|
};
|
|
320
392
|
const loadRouteConfig = () => importRouteConfig(jiti);
|
|
321
393
|
const { value: routeConfig, watchPaths: routeConfigWatchPaths } =
|
|
322
|
-
await importConfigWithWatchPaths(routesPath, importRouteConfig
|
|
394
|
+
await importConfigWithWatchPaths(routesPath, importRouteConfig, {
|
|
395
|
+
define: routeConfigDefine,
|
|
396
|
+
});
|
|
323
397
|
|
|
324
|
-
const
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
398
|
+
const {
|
|
399
|
+
devServerBuildEntryName,
|
|
400
|
+
finalEntryClientPath,
|
|
401
|
+
finalEntryRscClientPath,
|
|
402
|
+
finalEntryRscPath,
|
|
403
|
+
finalEntryRscSsrPath,
|
|
404
|
+
finalEntryServerPath,
|
|
405
|
+
hasServerApp,
|
|
406
|
+
serverAppPath,
|
|
407
|
+
} = resolveReactRouterEntryPaths({
|
|
408
|
+
appDirectory,
|
|
409
|
+
templatesDirectory: resolve(__dirname, 'templates'),
|
|
410
|
+
});
|
|
330
411
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
: templateServerPath;
|
|
412
|
+
if (isRscMode) {
|
|
413
|
+
assertReactRouterRscSupport({
|
|
414
|
+
pluginName: PLUGIN_NAME,
|
|
415
|
+
resolvePackagePath: resolveAppPackagePath,
|
|
416
|
+
});
|
|
417
|
+
assertReactRouterRscConfigSupport({
|
|
418
|
+
pluginName: PLUGIN_NAME,
|
|
419
|
+
userConfig: resolvedConfig,
|
|
420
|
+
});
|
|
421
|
+
await setupReactRouterRscPlugin({
|
|
422
|
+
api,
|
|
423
|
+
entryRscPath: finalEntryRscPath,
|
|
424
|
+
entrySsrPath: finalEntryRscSsrPath,
|
|
425
|
+
pluginName: PLUGIN_NAME,
|
|
426
|
+
rsc: typeof pluginOptions.rsc === 'object' ? pluginOptions.rsc : {},
|
|
427
|
+
});
|
|
428
|
+
}
|
|
349
429
|
|
|
350
430
|
const getRootRoutePath = () => findEntryFile(resolve(appDirectory, 'root'));
|
|
351
431
|
const rootRoutePath = getRootRoutePath();
|
|
@@ -366,25 +446,45 @@ export const pluginReactRouter = (
|
|
|
366
446
|
};
|
|
367
447
|
|
|
368
448
|
const resolvedConfigWithRoutes: ResolvedReactRouterConfig = {
|
|
369
|
-
...resolvedConfig,
|
|
370
449
|
appDirectory: resolve(appDirectory),
|
|
450
|
+
basename,
|
|
371
451
|
buildDirectory: resolve(buildDirectory),
|
|
372
|
-
|
|
452
|
+
buildEnd,
|
|
453
|
+
future,
|
|
373
454
|
prerender: prerenderConfig,
|
|
374
455
|
routes,
|
|
375
|
-
|
|
456
|
+
routeDiscovery,
|
|
457
|
+
serverBuildFile,
|
|
458
|
+
serverBundles,
|
|
459
|
+
serverModuleFormat,
|
|
460
|
+
ssr,
|
|
461
|
+
splitRouteModules,
|
|
462
|
+
subResourceIntegrity,
|
|
376
463
|
allowedActionOrigins: allowedActionOrigins ?? false,
|
|
464
|
+
unstable_routeConfig: routeConfig,
|
|
377
465
|
};
|
|
378
466
|
|
|
379
467
|
const { buildEnd: _buildEnd, ...resolvedConfigForPreset } =
|
|
380
468
|
resolvedConfigWithRoutes;
|
|
381
469
|
for (const preset of configPresets) {
|
|
382
470
|
await preset.reactRouterConfigResolved?.({
|
|
383
|
-
reactRouterConfig:
|
|
471
|
+
reactRouterConfig:
|
|
472
|
+
resolvedConfigForPreset as ReactRouterPresetResolvedConfig,
|
|
384
473
|
});
|
|
385
474
|
}
|
|
475
|
+
const buildEndReactRouterConfig: ResolvedReactRouterConfig = {
|
|
476
|
+
...resolvedConfigWithRoutes,
|
|
477
|
+
future: userAndPresetConfig.future ?? {},
|
|
478
|
+
} as ResolvedReactRouterConfig;
|
|
386
479
|
|
|
387
480
|
const isBuild = api.context.action === 'build';
|
|
481
|
+
if (!isBuild) {
|
|
482
|
+
api.onAfterEnvironmentCompile(({ environment, stats }) => {
|
|
483
|
+
if (environment.name === 'node' && stats && !stats.hasErrors()) {
|
|
484
|
+
registerDevServerSourceMaps(stats.compilation);
|
|
485
|
+
}
|
|
486
|
+
});
|
|
487
|
+
}
|
|
388
488
|
const shouldDependOnWebCompiler = !shouldParallelizeEnvironmentBuilds({
|
|
389
489
|
isBuild,
|
|
390
490
|
});
|
|
@@ -392,53 +492,216 @@ export const pluginReactRouter = (
|
|
|
392
492
|
prerenderConfig !== undefined && prerenderConfig !== false;
|
|
393
493
|
const isSpaMode = !ssr && !isPrerenderEnabled;
|
|
394
494
|
const routeCount = Object.keys(routes).length;
|
|
395
|
-
const routeChunkConfig: RouteChunkConfig = {
|
|
396
|
-
splitRouteModules,
|
|
397
|
-
appDirectory,
|
|
398
|
-
rootRouteFile,
|
|
399
|
-
};
|
|
400
495
|
const routeChunkCache: RouteChunkCache = new Map();
|
|
401
|
-
const useRouteModuleTransformLoader =
|
|
402
|
-
|
|
403
|
-
|
|
496
|
+
const useRouteModuleTransformLoader =
|
|
497
|
+
!isRscMode &&
|
|
498
|
+
shouldUseRouteModuleTransformLoader(pluginOptions.parallelRouteTransform);
|
|
404
499
|
const routeTransformRunner: RouteTransformRunner = task =>
|
|
405
500
|
executeRouteTransformTask(task, { routeChunkCache });
|
|
406
|
-
const
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
501
|
+
const transformedRouteModuleAnalyses = new Map<
|
|
502
|
+
string,
|
|
503
|
+
RouteModuleAnalysis
|
|
504
|
+
>();
|
|
505
|
+
const rememberRouteModuleAnalysis = (
|
|
506
|
+
resourcePath: string,
|
|
507
|
+
analysis: RouteModuleAnalysis
|
|
508
|
+
) => {
|
|
509
|
+
transformedRouteModuleAnalyses.set(resolve(resourcePath), analysis);
|
|
411
510
|
};
|
|
511
|
+
const routeModuleAnalysis = async (routeFilePath: string) =>
|
|
512
|
+
transformedRouteModuleAnalyses.get(resolve(routeFilePath));
|
|
412
513
|
const outputClientPath = resolve(buildDirectory, 'client');
|
|
413
514
|
const assetsBuildDirectory = relative(process.cwd(), outputClientPath);
|
|
414
515
|
const watchDirectory = resolve(appDirectory);
|
|
415
|
-
const routeRestartMarkerPath = getRouteRestartMarkerPath(
|
|
516
|
+
const routeRestartMarkerPath = getRouteRestartMarkerPath(appDirectory);
|
|
416
517
|
const routeWatchFiles = createReactRouterRouteWatchFiles({
|
|
417
518
|
configWatchPaths,
|
|
418
519
|
routeConfigWatchPaths,
|
|
419
520
|
routeRestartMarkerPath,
|
|
420
521
|
onRouteTopologyChange: pluginOptions.onRouteTopologyChange,
|
|
421
522
|
});
|
|
422
|
-
const devBackgroundResources = registerReactRouterDevBackgroundResources({
|
|
423
|
-
api,
|
|
424
|
-
isBuild,
|
|
425
|
-
lazyCompilationPrewarm: pluginOptions.unstableLazyCompilationPrewarm,
|
|
426
|
-
routeRestartMarkerPath,
|
|
427
|
-
watchDirectory,
|
|
428
|
-
getRouteTopology: routeTopology.getRouteTopology,
|
|
429
|
-
initialRouteTopology: routeTopology.initialRouteTopology,
|
|
430
|
-
onRouteTopologyChange: pluginOptions.onRouteTopologyChange,
|
|
431
|
-
});
|
|
432
|
-
|
|
433
|
-
type ReactRouterManifest = Awaited<
|
|
434
|
-
ReturnType<typeof getReactRouterManifestForDev>
|
|
435
|
-
>;
|
|
436
523
|
let latestBrowserManifest: ReactRouterManifest | null = null;
|
|
437
524
|
let latestBrowserManifestModuleExports: RouteManifestModuleExports = {};
|
|
438
525
|
let latestServerManifest: ReactRouterManifest | null = null;
|
|
439
526
|
const latestServerManifestsByBundleId: Record<string, ReactRouterManifest> =
|
|
440
527
|
{};
|
|
441
528
|
|
|
529
|
+
const routeByFilePath = new Map(
|
|
530
|
+
Object.values(routes).map(route => [
|
|
531
|
+
resolve(appDirectory, route.file),
|
|
532
|
+
route,
|
|
533
|
+
])
|
|
534
|
+
);
|
|
535
|
+
const allowedActionOriginsForBuild =
|
|
536
|
+
allowedActionOrigins === false ? undefined : allowedActionOrigins;
|
|
537
|
+
|
|
538
|
+
const devHmrRefreshRuntimePath =
|
|
539
|
+
isBuild || isRscMode
|
|
540
|
+
? undefined
|
|
541
|
+
: resolveReactRefreshRuntimePath(api.context.rootPath);
|
|
542
|
+
const devHdrSignal = devHmrRefreshRuntimePath
|
|
543
|
+
? createDevHdrRevisionSignal({
|
|
544
|
+
filePath: getDevHdrRevisionFilePath(api.context.rootPath),
|
|
545
|
+
onError: error =>
|
|
546
|
+
api.logger.debug(
|
|
547
|
+
`[${PLUGIN_NAME}] Failed to signal hot data revalidation: ${error.message}`
|
|
548
|
+
),
|
|
549
|
+
})
|
|
550
|
+
: undefined;
|
|
551
|
+
let devHmrEnabled = false;
|
|
552
|
+
if (devHmrRefreshRuntimePath && devHdrSignal) {
|
|
553
|
+
api.modifyEnvironmentConfig(
|
|
554
|
+
async (environmentConfig, { name, mergeEnvironmentConfig }) => {
|
|
555
|
+
if (name !== 'web') return environmentConfig;
|
|
556
|
+
return mergeEnvironmentConfig(environmentConfig, {
|
|
557
|
+
tools: {
|
|
558
|
+
rspack: rspackConfig => {
|
|
559
|
+
devHmrEnabled = isRspackSwcReactRefreshEnabled(rspackConfig);
|
|
560
|
+
if (devHmrEnabled) devHdrSignal.ensure();
|
|
561
|
+
return rspackConfig;
|
|
562
|
+
},
|
|
563
|
+
},
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
const commonModeOptions = {
|
|
570
|
+
api,
|
|
571
|
+
allowedActionOriginsForBuild,
|
|
572
|
+
appDirectory,
|
|
573
|
+
basename,
|
|
574
|
+
customServer: pluginOptions.customServer,
|
|
575
|
+
isBuild,
|
|
576
|
+
isSpaMode,
|
|
577
|
+
prerenderConfig,
|
|
578
|
+
routeConfig,
|
|
579
|
+
routeDiscovery,
|
|
580
|
+
routes,
|
|
581
|
+
rootRouteFile,
|
|
582
|
+
splitRouteModules,
|
|
583
|
+
ssr,
|
|
584
|
+
};
|
|
585
|
+
const modePlan = await (isRscMode
|
|
586
|
+
? createReactRouterModePlan({
|
|
587
|
+
...commonModeOptions,
|
|
588
|
+
isRscMode: true,
|
|
589
|
+
buildDirectory,
|
|
590
|
+
finalEntryRscClientPath,
|
|
591
|
+
finalEntryRscPath,
|
|
592
|
+
outputClientPath,
|
|
593
|
+
pluginName: PLUGIN_NAME,
|
|
594
|
+
serverBuildFile,
|
|
595
|
+
})
|
|
596
|
+
: createReactRouterModePlan({
|
|
597
|
+
...commonModeOptions,
|
|
598
|
+
isRscMode: false,
|
|
599
|
+
assetsBuildDirectory,
|
|
600
|
+
defaultEntryName: devServerBuildEntryName,
|
|
601
|
+
entryServerPath: finalEntryServerPath,
|
|
602
|
+
finalEntryClientPath,
|
|
603
|
+
future,
|
|
604
|
+
hasServerApp,
|
|
605
|
+
reactRouterConfig: resolvedConfigWithRoutes,
|
|
606
|
+
routeChunkCache,
|
|
607
|
+
serverAppPath,
|
|
608
|
+
shouldDependOnWebCompiler,
|
|
609
|
+
devHmr:
|
|
610
|
+
devHmrRefreshRuntimePath && devHdrSignal
|
|
611
|
+
? {
|
|
612
|
+
isEnabled: () => devHmrEnabled,
|
|
613
|
+
runtimeModule: generateDevHmrRuntimeModule({
|
|
614
|
+
reactRefreshRuntimePath: devHmrRefreshRuntimePath,
|
|
615
|
+
hdrRevisionFilePath: devHdrSignal.filePath,
|
|
616
|
+
}),
|
|
617
|
+
onNodeRebuildCommitted: () => {
|
|
618
|
+
if (devHmrEnabled) devHdrSignal.bump();
|
|
619
|
+
},
|
|
620
|
+
}
|
|
621
|
+
: undefined,
|
|
622
|
+
}));
|
|
623
|
+
|
|
624
|
+
const { manifestChunkNames } = modePlan;
|
|
625
|
+
|
|
626
|
+
let sendRscDevUpdate: (() => void) | undefined;
|
|
627
|
+
let scheduledRscDevUpdate: ReturnType<typeof setTimeout> | undefined;
|
|
628
|
+
let hasPendingRscNodeUpdate = false;
|
|
629
|
+
let pendingRscNodeFiles = new Set<string>();
|
|
630
|
+
if (isRscMode && !isBuild) {
|
|
631
|
+
api.onBeforeStartDevServer(({ server }) => {
|
|
632
|
+
sendRscDevUpdate = () =>
|
|
633
|
+
server.sockWrite('custom', {
|
|
634
|
+
event: 'rsc:update',
|
|
635
|
+
data: { revalidate: true },
|
|
636
|
+
});
|
|
637
|
+
});
|
|
638
|
+
api.onCloseDevServer(() => {
|
|
639
|
+
if (scheduledRscDevUpdate) {
|
|
640
|
+
clearTimeout(scheduledRscDevUpdate);
|
|
641
|
+
scheduledRscDevUpdate = undefined;
|
|
642
|
+
}
|
|
643
|
+
hasPendingRscNodeUpdate = false;
|
|
644
|
+
pendingRscNodeFiles.clear();
|
|
645
|
+
sendRscDevUpdate = undefined;
|
|
646
|
+
});
|
|
647
|
+
api.onAfterEnvironmentCompile(({ environment, stats }) => {
|
|
648
|
+
if (
|
|
649
|
+
(environment.name !== 'node' && environment.name !== 'web') ||
|
|
650
|
+
stats?.hasErrors()
|
|
651
|
+
) {
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
if (environment.name === 'node') {
|
|
655
|
+
const compiler = stats?.compilation.compiler;
|
|
656
|
+
const changedFiles = new Set([
|
|
657
|
+
...(compiler?.modifiedFiles ?? []),
|
|
658
|
+
...(compiler?.removedFiles ?? []),
|
|
659
|
+
]);
|
|
660
|
+
// Initial and lazy compilations do not represent source edits. Sending
|
|
661
|
+
// an RSC revalidation for them can race and abort the navigation that
|
|
662
|
+
// requested the lazy module.
|
|
663
|
+
if (changedFiles.size === 0) {
|
|
664
|
+
return;
|
|
665
|
+
}
|
|
666
|
+
hasPendingRscNodeUpdate = true;
|
|
667
|
+
pendingRscNodeFiles = changedFiles;
|
|
668
|
+
}
|
|
669
|
+
if (!hasPendingRscNodeUpdate) {
|
|
670
|
+
return;
|
|
671
|
+
}
|
|
672
|
+
if (scheduledRscDevUpdate) {
|
|
673
|
+
clearTimeout(scheduledRscDevUpdate);
|
|
674
|
+
}
|
|
675
|
+
scheduledRscDevUpdate = setTimeout(() => {
|
|
676
|
+
scheduledRscDevUpdate = undefined;
|
|
677
|
+
hasPendingRscNodeUpdate = false;
|
|
678
|
+
const clientHotUpdateHandlesChange =
|
|
679
|
+
pendingRscNodeFiles.size > 0 &&
|
|
680
|
+
[...pendingRscNodeFiles].every(isRscClientModule);
|
|
681
|
+
const routeHotUpdateHandlesChange = [...pendingRscNodeFiles].some(
|
|
682
|
+
filePath => routeByFilePath.has(resolve(filePath))
|
|
683
|
+
);
|
|
684
|
+
pendingRscNodeFiles.clear();
|
|
685
|
+
if (!clientHotUpdateHandlesChange && !routeHotUpdateHandlesChange) {
|
|
686
|
+
sendRscDevUpdate?.();
|
|
687
|
+
}
|
|
688
|
+
}, 1000);
|
|
689
|
+
});
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
const devBackgroundResources =
|
|
693
|
+
await registerReactRouterDevBackgroundResources({
|
|
694
|
+
api,
|
|
695
|
+
runtime: effectRuntime,
|
|
696
|
+
isBuild,
|
|
697
|
+
lazyCompilationPrewarm: pluginOptions.unstableLazyCompilationPrewarm,
|
|
698
|
+
routeRestartMarkerPath,
|
|
699
|
+
watchDirectory,
|
|
700
|
+
getRouteTopology: routeTopology.getRouteTopology,
|
|
701
|
+
initialRouteTopology: routeTopology.initialRouteTopology,
|
|
702
|
+
onRouteTopologyChange: pluginOptions.onRouteTopologyChange,
|
|
703
|
+
});
|
|
704
|
+
|
|
442
705
|
const stageLatestManifests = (
|
|
443
706
|
manifest: ReactRouterManifest,
|
|
444
707
|
sri: ReactRouterManifest['sri'],
|
|
@@ -462,8 +725,14 @@ export const pluginReactRouter = (
|
|
|
462
725
|
[devServerBuildEntryName]: baseServerManifest,
|
|
463
726
|
};
|
|
464
727
|
|
|
465
|
-
|
|
466
|
-
|
|
728
|
+
if (modePlan.kind !== 'classic') {
|
|
729
|
+
return;
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
for (const { bundleId, entryName } of modePlan.artifacts
|
|
733
|
+
.serverBundleEntries) {
|
|
734
|
+
const bundleRoutes =
|
|
735
|
+
modePlan.artifacts.routesByServerBundleId[bundleId];
|
|
467
736
|
if (!bundleRoutes) {
|
|
468
737
|
continue;
|
|
469
738
|
}
|
|
@@ -483,94 +752,15 @@ export const pluginReactRouter = (
|
|
|
483
752
|
}
|
|
484
753
|
|
|
485
754
|
if (!isBuild) {
|
|
486
|
-
devRuntime.captureWeb(
|
|
755
|
+
modePlan.artifacts.devRuntime.captureWeb(
|
|
756
|
+
compilation,
|
|
757
|
+
manifestsByEntryName
|
|
758
|
+
);
|
|
487
759
|
}
|
|
488
760
|
}
|
|
489
761
|
);
|
|
490
762
|
};
|
|
491
763
|
|
|
492
|
-
const routeByFilePath = new Map(
|
|
493
|
-
Object.values(routes).map(route => [
|
|
494
|
-
resolve(appDirectory, route.file),
|
|
495
|
-
route,
|
|
496
|
-
])
|
|
497
|
-
);
|
|
498
|
-
|
|
499
|
-
const manifestChunkNames = new Set<string>(['entry.client']);
|
|
500
|
-
const webRouteEntries = Object.values(routes).reduce(
|
|
501
|
-
(acc, route) => {
|
|
502
|
-
const entryName = route.file.slice(0, route.file.lastIndexOf('.'));
|
|
503
|
-
const routeFilePath = resolve(appDirectory, route.file);
|
|
504
|
-
manifestChunkNames.add(entryName);
|
|
505
|
-
acc[entryName] = {
|
|
506
|
-
import: `${routeFilePath}${BUILD_CLIENT_ROUTE_QUERY_STRING}`,
|
|
507
|
-
html: false,
|
|
508
|
-
};
|
|
509
|
-
|
|
510
|
-
if (isBuild && splitRouteModules && route.id !== 'root') {
|
|
511
|
-
let source: string;
|
|
512
|
-
try {
|
|
513
|
-
source = readFileSync(routeFilePath, 'utf8');
|
|
514
|
-
} catch (error) {
|
|
515
|
-
if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
|
|
516
|
-
return acc;
|
|
517
|
-
}
|
|
518
|
-
throw error;
|
|
519
|
-
}
|
|
520
|
-
for (const exportName of routeChunkExportNames) {
|
|
521
|
-
if (!source.includes(exportName)) {
|
|
522
|
-
continue;
|
|
523
|
-
}
|
|
524
|
-
const chunkEntryName = getRouteChunkEntryName(route.id, exportName);
|
|
525
|
-
manifestChunkNames.add(chunkEntryName);
|
|
526
|
-
acc[chunkEntryName] = {
|
|
527
|
-
import: getRouteChunkModuleId(routeFilePath, exportName),
|
|
528
|
-
html: false,
|
|
529
|
-
};
|
|
530
|
-
}
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
return acc;
|
|
534
|
-
},
|
|
535
|
-
{} as Record<string, RsbuildEntryDescription>
|
|
536
|
-
);
|
|
537
|
-
const buildManifest = await getBuildManifest({
|
|
538
|
-
reactRouterConfig: resolvedConfigWithRoutes,
|
|
539
|
-
routes,
|
|
540
|
-
rootDirectory: process.cwd(),
|
|
541
|
-
});
|
|
542
|
-
const routesByServerBundleId = getRoutesByServerBundleId(
|
|
543
|
-
buildManifest,
|
|
544
|
-
routes
|
|
545
|
-
);
|
|
546
|
-
const serverBuildPlan = createReactRouterServerBuildPlan({
|
|
547
|
-
routesByServerBundleId,
|
|
548
|
-
serverBuildFile,
|
|
549
|
-
defaultEntryName: devServerBuildEntryName,
|
|
550
|
-
});
|
|
551
|
-
const { serverBundleEntries } = serverBuildPlan;
|
|
552
|
-
|
|
553
|
-
const devHmrRefreshRuntimePath = isBuild
|
|
554
|
-
? undefined
|
|
555
|
-
: resolveReactRefreshRuntimePath(api.context.rootPath);
|
|
556
|
-
const devHdrSignal = devHmrRefreshRuntimePath
|
|
557
|
-
? createDevHdrRevisionSignal({
|
|
558
|
-
filePath: getDevHdrRevisionFilePath(api.context.rootPath),
|
|
559
|
-
onError: error =>
|
|
560
|
-
api.logger.debug(
|
|
561
|
-
`[${PLUGIN_NAME}] Failed to signal hot data revalidation: ${error.message}`
|
|
562
|
-
),
|
|
563
|
-
})
|
|
564
|
-
: undefined;
|
|
565
|
-
let devHmrEnabled = false;
|
|
566
|
-
|
|
567
|
-
const devRuntime = createReactRouterDevRuntimeController({
|
|
568
|
-
api,
|
|
569
|
-
isBuild,
|
|
570
|
-
buildPlan: serverBuildPlan,
|
|
571
|
-
onNodeRebuildCommitted: () => devHdrSignal?.bump(),
|
|
572
|
-
});
|
|
573
|
-
|
|
574
764
|
let clientStats: ReactRouterManifestStats | undefined;
|
|
575
765
|
api.onAfterEnvironmentCompile(({ stats, environment }) => {
|
|
576
766
|
if (environment.name === 'web') {
|
|
@@ -594,121 +784,82 @@ export const pluginReactRouter = (
|
|
|
594
784
|
}
|
|
595
785
|
});
|
|
596
786
|
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
api.onAfterBuild(({ environments }) =>
|
|
608
|
-
runPluginEffect(
|
|
609
|
-
tryPluginPromise(() =>
|
|
610
|
-
runReactRouterPrerenderBuild({
|
|
611
|
-
api,
|
|
612
|
-
hasWebEnvironment: Boolean(environments.web),
|
|
613
|
-
buildDirectory,
|
|
614
|
-
serverBuildFile,
|
|
615
|
-
ssr,
|
|
616
|
-
isPrerenderEnabled,
|
|
617
|
-
prerenderConfig,
|
|
618
|
-
prerenderPaths,
|
|
619
|
-
basename,
|
|
620
|
-
future,
|
|
621
|
-
routes,
|
|
622
|
-
latestBrowserManifest,
|
|
623
|
-
latestBrowserManifestModuleExports,
|
|
624
|
-
clientStats,
|
|
625
|
-
pluginOptions,
|
|
626
|
-
appDirectory,
|
|
627
|
-
assetPrefix,
|
|
628
|
-
routeChunkOptions,
|
|
629
|
-
buildManifest,
|
|
630
|
-
resolvedConfigWithRoutes,
|
|
631
|
-
buildEnd,
|
|
632
|
-
})
|
|
633
|
-
)
|
|
634
|
-
)
|
|
635
|
-
);
|
|
636
|
-
|
|
637
|
-
const allowedActionOriginsForBuild =
|
|
638
|
-
allowedActionOrigins === false ? undefined : allowedActionOrigins;
|
|
639
|
-
|
|
640
|
-
// Public requests stay bare while Rspack resolves seeded virtual files.
|
|
641
|
-
const createVirtualModulePlugin = (publicPath: string) => {
|
|
642
|
-
const bundleVirtualModules = Object.fromEntries(
|
|
643
|
-
Object.entries(routesByServerBundleId).map(
|
|
644
|
-
([bundleId, bundleRoutes]) => [
|
|
645
|
-
`virtual/react-router/server-build-${bundleId}`,
|
|
646
|
-
generateServerBuild(bundleRoutes, {
|
|
647
|
-
entryServerPath: finalEntryServerPath,
|
|
648
|
-
assetsBuildDirectory,
|
|
649
|
-
basename,
|
|
650
|
-
appDirectory,
|
|
787
|
+
if (modePlan.kind === 'classic') {
|
|
788
|
+
api.onAfterBuild(({ environments }) =>
|
|
789
|
+
effectRuntime.runPromise(
|
|
790
|
+
tryPluginPromise(() =>
|
|
791
|
+
runReactRouterPrerenderBuild({
|
|
792
|
+
api,
|
|
793
|
+
hasWebEnvironment: Boolean(environments.web),
|
|
794
|
+
buildDirectory,
|
|
795
|
+
serverBuildFile,
|
|
651
796
|
ssr,
|
|
652
|
-
|
|
797
|
+
isPrerenderEnabled,
|
|
798
|
+
prerenderConfig,
|
|
799
|
+
prerenderPaths: modePlan.artifacts.prerenderPaths,
|
|
800
|
+
basename,
|
|
653
801
|
future,
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
802
|
+
routes,
|
|
803
|
+
latestBrowserManifest,
|
|
804
|
+
latestBrowserManifestModuleExports,
|
|
805
|
+
clientStats,
|
|
806
|
+
pluginOptions,
|
|
807
|
+
appDirectory,
|
|
808
|
+
assetPrefix,
|
|
809
|
+
routeChunkOptions: modePlan.routeChunkOptions,
|
|
810
|
+
routeModuleAnalysis,
|
|
811
|
+
buildManifest: modePlan.artifacts.buildManifest,
|
|
812
|
+
buildEndReactRouterConfig,
|
|
813
|
+
buildEnd,
|
|
814
|
+
})
|
|
815
|
+
)
|
|
661
816
|
)
|
|
662
817
|
);
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
818
|
+
} else {
|
|
819
|
+
api.onAfterBuild(({ environments }) =>
|
|
820
|
+
effectRuntime.runPromise(
|
|
821
|
+
tryPluginPromise(() =>
|
|
822
|
+
runReactRouterRscPrerenderBuild({
|
|
823
|
+
api,
|
|
824
|
+
hasWebEnvironment: Boolean(environments.web),
|
|
825
|
+
buildDirectory,
|
|
826
|
+
serverBuildFile,
|
|
827
|
+
ssr,
|
|
828
|
+
prerenderConfig,
|
|
829
|
+
prerenderPaths: modePlan.prerenderPaths,
|
|
830
|
+
basename,
|
|
831
|
+
})
|
|
668
832
|
)
|
|
669
|
-
|
|
670
|
-
`virtual/react-router/server-manifest-${bundleId}`,
|
|
671
|
-
'export default {};',
|
|
672
|
-
])
|
|
833
|
+
)
|
|
673
834
|
);
|
|
835
|
+
}
|
|
674
836
|
|
|
837
|
+
// Public requests stay bare while Rspack resolves seeded virtual files.
|
|
838
|
+
const createVirtualModulePlugin = (
|
|
839
|
+
publicPath: string,
|
|
840
|
+
jsDistPath: string
|
|
841
|
+
) => {
|
|
675
842
|
return new rspack.experiments.VirtualModulesPlugin(
|
|
676
|
-
mapVirtualModules(
|
|
677
|
-
'virtual/react-router/browser-manifest': 'export default {};',
|
|
678
|
-
'virtual/react-router/server-manifest': 'export default {};',
|
|
679
|
-
'virtual/react-router/server-build': generateServerBuild(routes, {
|
|
680
|
-
entryServerPath: finalEntryServerPath,
|
|
681
|
-
assetsBuildDirectory,
|
|
682
|
-
basename,
|
|
683
|
-
appDirectory,
|
|
684
|
-
ssr,
|
|
685
|
-
federation: options.federation,
|
|
686
|
-
future,
|
|
687
|
-
allowedActionOrigins: allowedActionOriginsForBuild,
|
|
688
|
-
prerender: prerenderPaths,
|
|
689
|
-
routeDiscovery,
|
|
690
|
-
publicPath,
|
|
691
|
-
}),
|
|
692
|
-
...bundleVirtualModules,
|
|
693
|
-
...bundleManifestModules,
|
|
694
|
-
'virtual/react-router/with-props': generateWithProps(),
|
|
695
|
-
...(devHmrRefreshRuntimePath
|
|
696
|
-
? {
|
|
697
|
-
[DEV_HMR_RUNTIME_MODULE_ID]: generateDevHmrRuntimeModule({
|
|
698
|
-
reactRefreshRuntimePath: devHmrRefreshRuntimePath,
|
|
699
|
-
hdrRevisionFilePath: getDevHdrRevisionFilePath(
|
|
700
|
-
api.context.rootPath
|
|
701
|
-
),
|
|
702
|
-
}),
|
|
703
|
-
}
|
|
704
|
-
: {}),
|
|
705
|
-
})
|
|
843
|
+
mapVirtualModules(modePlan.createVirtualModules(publicPath, jsDistPath))
|
|
706
844
|
);
|
|
707
845
|
};
|
|
708
846
|
|
|
709
847
|
api.modifyRsbuildConfig(async (config, { mergeRsbuildConfig }) => {
|
|
710
|
-
|
|
711
|
-
|
|
848
|
+
// The RSC bootstrap script URL must reflect the user's web js distPath;
|
|
849
|
+
// the entry filename itself is deterministic because the plugin forces
|
|
850
|
+
// web `output.filename.js` to '[name].js' below.
|
|
851
|
+
const webDistPath = config.environments?.web?.output?.distPath;
|
|
852
|
+
const rootDistPath = config.output?.distPath;
|
|
853
|
+
const jsDistPath =
|
|
854
|
+
(typeof webDistPath === 'object' ? webDistPath.js : undefined) ??
|
|
855
|
+
(typeof rootDistPath === 'object' ? rootDistPath.js : undefined) ??
|
|
856
|
+
DEFAULT_JS_DIST_PATH;
|
|
857
|
+
const assetPrefix = resolveEffectiveAssetPrefix({
|
|
858
|
+
dev: config.dev,
|
|
859
|
+
output: config.output,
|
|
860
|
+
isBuild,
|
|
861
|
+
});
|
|
862
|
+
const vmodPlugin = createVirtualModulePlugin(assetPrefix, jsDistPath);
|
|
712
863
|
const useAsyncNodeChunkLoading =
|
|
713
864
|
options.federation && resolvedServerOutput === 'commonjs';
|
|
714
865
|
let nodeChunkLoading: 'import' | 'async-node' | 'require' = 'require';
|
|
@@ -717,15 +868,6 @@ export const pluginReactRouter = (
|
|
|
717
868
|
} else if (useAsyncNodeChunkLoading) {
|
|
718
869
|
nodeChunkLoading = 'async-node';
|
|
719
870
|
}
|
|
720
|
-
const nodeEntries = createReactRouterNodeEntries({
|
|
721
|
-
hasServerApp,
|
|
722
|
-
isBuild,
|
|
723
|
-
serverAppPath,
|
|
724
|
-
entryServerPath: finalEntryServerPath,
|
|
725
|
-
defaultEntryName: devServerBuildEntryName,
|
|
726
|
-
serverBundleEntries,
|
|
727
|
-
});
|
|
728
|
-
|
|
729
871
|
const configuredLazyCompilation = Object.prototype.hasOwnProperty.call(
|
|
730
872
|
options,
|
|
731
873
|
'lazyCompilation'
|
|
@@ -734,7 +876,9 @@ export const pluginReactRouter = (
|
|
|
734
876
|
: (config.dev?.lazyCompilation ?? pluginOptions.lazyCompilation);
|
|
735
877
|
const guardedLazyCompilation = guardReactRouterLazyCompilation({
|
|
736
878
|
lazyCompilation: configuredLazyCompilation,
|
|
737
|
-
entryClientPath:
|
|
879
|
+
entryClientPath: isRscMode
|
|
880
|
+
? finalEntryRscClientPath
|
|
881
|
+
: finalEntryClientPath,
|
|
738
882
|
prewarmReactRouterModules: Boolean(
|
|
739
883
|
pluginOptions.unstableLazyCompilationPrewarm
|
|
740
884
|
),
|
|
@@ -748,6 +892,28 @@ export const pluginReactRouter = (
|
|
|
748
892
|
routeCount >= 256 &&
|
|
749
893
|
(config.performance?.printFileSize === undefined ||
|
|
750
894
|
config.performance.printFileSize === true);
|
|
895
|
+
const resolveConfig = modePlan.createResolveConfig(api.context.rootPath);
|
|
896
|
+
|
|
897
|
+
// Browser code (React itself) reads `process.env.NODE_ENV`. Rsbuild only
|
|
898
|
+
// emits the define for its recognized modes; an unrecognized NODE_ENV
|
|
899
|
+
// (e.g. the string "undefined" leaking from a misconfigured shell)
|
|
900
|
+
// resolves mode 'none' and leaves the bare reference in the web bundle,
|
|
901
|
+
// which throws `process is not defined` at runtime. Always define it for
|
|
902
|
+
// the web environment — mirroring the Vite plugin — unless the user
|
|
903
|
+
// supplies their own define.
|
|
904
|
+
const userDefinesNodeEnv =
|
|
905
|
+
config.source?.define?.['process.env.NODE_ENV'] !== undefined ||
|
|
906
|
+
config.environments?.web?.source?.define?.['process.env.NODE_ENV'] !==
|
|
907
|
+
undefined;
|
|
908
|
+
const webNodeEnv =
|
|
909
|
+
process.env.NODE_ENV === 'production' ||
|
|
910
|
+
process.env.NODE_ENV === 'development' ||
|
|
911
|
+
process.env.NODE_ENV === 'test'
|
|
912
|
+
? process.env.NODE_ENV
|
|
913
|
+
: isBuild
|
|
914
|
+
? 'production'
|
|
915
|
+
: 'development';
|
|
916
|
+
|
|
751
917
|
return mergeRsbuildConfig(config, {
|
|
752
918
|
...(shouldCompactFileSizeReport
|
|
753
919
|
? {
|
|
@@ -763,29 +929,20 @@ export const pluginReactRouter = (
|
|
|
763
929
|
output: {
|
|
764
930
|
assetPrefix: config.output?.assetPrefix || '/',
|
|
765
931
|
},
|
|
932
|
+
server: modePlan.server,
|
|
766
933
|
dev: {
|
|
767
934
|
...lazyCompilation,
|
|
768
935
|
watchFiles: mergeWatchFiles(config.dev?.watchFiles, routeWatchFiles),
|
|
769
936
|
},
|
|
770
|
-
// React Router's request handler natively supports `ssr:false`
|
|
771
|
-
// builds (it renders the SPA shell for document requests), so the
|
|
772
|
-
// middleware is registered for SPA mode too — without it, dev
|
|
773
|
-
// requests would 404 because no HTML entry exists.
|
|
774
|
-
...(pluginOptions.customServer
|
|
775
|
-
? {}
|
|
776
|
-
: {
|
|
777
|
-
server: {
|
|
778
|
-
setup: [
|
|
779
|
-
createReactRouterDevServerSetup({
|
|
780
|
-
// Lazy: the dev runtime binding does not exist yet here.
|
|
781
|
-
loadBuild: () => devRuntime.createBuildLoader()(),
|
|
782
|
-
}),
|
|
783
|
-
],
|
|
784
|
-
},
|
|
785
|
-
}),
|
|
786
937
|
tools: {
|
|
787
938
|
rspack: {
|
|
788
|
-
|
|
939
|
+
resolve: resolveConfig,
|
|
940
|
+
plugins: [
|
|
941
|
+
vmodPlugin,
|
|
942
|
+
createQuerylessRouteImportPlugin(routeByFilePath, {
|
|
943
|
+
rsc: isRscMode,
|
|
944
|
+
}),
|
|
945
|
+
],
|
|
789
946
|
},
|
|
790
947
|
},
|
|
791
948
|
environments: {
|
|
@@ -800,15 +957,14 @@ export const pluginReactRouter = (
|
|
|
800
957
|
}
|
|
801
958
|
: {}),
|
|
802
959
|
source: {
|
|
803
|
-
entry:
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
},
|
|
960
|
+
entry: modePlan.webEntries,
|
|
961
|
+
...(userDefinesNodeEnv
|
|
962
|
+
? {}
|
|
963
|
+
: {
|
|
964
|
+
define: {
|
|
965
|
+
'process.env.NODE_ENV': JSON.stringify(webNodeEnv),
|
|
966
|
+
},
|
|
967
|
+
}),
|
|
812
968
|
},
|
|
813
969
|
output: {
|
|
814
970
|
filename: {
|
|
@@ -820,6 +976,7 @@ export const pluginReactRouter = (
|
|
|
820
976
|
},
|
|
821
977
|
tools: {
|
|
822
978
|
rspack: {
|
|
979
|
+
resolve: resolveConfig,
|
|
823
980
|
name: 'web',
|
|
824
981
|
module: {
|
|
825
982
|
rules: [
|
|
@@ -830,26 +987,17 @@ export const pluginReactRouter = (
|
|
|
830
987
|
},
|
|
831
988
|
],
|
|
832
989
|
},
|
|
833
|
-
|
|
834
|
-
? {
|
|
835
|
-
output: {
|
|
836
|
-
chunkLoading: 'import',
|
|
837
|
-
},
|
|
838
|
-
}
|
|
839
|
-
: {}),
|
|
840
|
-
externalsType: 'module',
|
|
990
|
+
externalsType: modePlan.webExternalsType,
|
|
841
991
|
output: {
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
optimization: {
|
|
850
|
-
avoidEntryIife: true,
|
|
851
|
-
runtimeChunk: 'single',
|
|
992
|
+
...modePlan.webOutput,
|
|
993
|
+
publicPath: assetPrefix,
|
|
994
|
+
...(options.federation
|
|
995
|
+
? {
|
|
996
|
+
chunkLoading: 'import',
|
|
997
|
+
}
|
|
998
|
+
: {}),
|
|
852
999
|
},
|
|
1000
|
+
optimization: modePlan.webOptimization,
|
|
853
1001
|
},
|
|
854
1002
|
},
|
|
855
1003
|
},
|
|
@@ -858,7 +1006,7 @@ export const pluginReactRouter = (
|
|
|
858
1006
|
// root route into a hydratable `index.html` at build time.
|
|
859
1007
|
node: {
|
|
860
1008
|
source: {
|
|
861
|
-
entry: nodeEntries,
|
|
1009
|
+
entry: modePlan.nodeEntries,
|
|
862
1010
|
},
|
|
863
1011
|
output: {
|
|
864
1012
|
distPath: {
|
|
@@ -867,6 +1015,15 @@ export const pluginReactRouter = (
|
|
|
867
1015
|
target: config.environments?.node?.output?.target || 'node',
|
|
868
1016
|
filename: {
|
|
869
1017
|
js: '[name].js',
|
|
1018
|
+
css: (pathData: Rspack.PathData) => {
|
|
1019
|
+
const sourceName = pathData.chunk?.name ?? '[name]';
|
|
1020
|
+
if (!isBuild) {
|
|
1021
|
+
return `${sourceName}.css`;
|
|
1022
|
+
}
|
|
1023
|
+
const baseName =
|
|
1024
|
+
sourceName.split(/[\\/]/).pop() || sourceName;
|
|
1025
|
+
return `../assets/${baseName}.[contenthash:10].css`;
|
|
1026
|
+
},
|
|
870
1027
|
},
|
|
871
1028
|
},
|
|
872
1029
|
tools: {
|
|
@@ -881,15 +1038,19 @@ export const pluginReactRouter = (
|
|
|
881
1038
|
},
|
|
882
1039
|
],
|
|
883
1040
|
},
|
|
884
|
-
externals: nodeExternals,
|
|
885
|
-
...
|
|
1041
|
+
externals: modePlan.nodeExternals,
|
|
1042
|
+
...modePlan.nodeDependencies,
|
|
886
1043
|
externalsType: resolvedServerOutput,
|
|
887
1044
|
output: {
|
|
888
1045
|
chunkFormat: resolvedServerOutput,
|
|
889
1046
|
chunkLoading: nodeChunkLoading,
|
|
1047
|
+
devtoolModuleFilenameTemplate: '[absolute-resource-path]',
|
|
1048
|
+
devtoolFallbackModuleFilenameTemplate:
|
|
1049
|
+
'[absolute-resource-path]?[hash]',
|
|
890
1050
|
workerChunkLoading: nodeChunkLoading,
|
|
891
1051
|
wasmLoading: 'fetch',
|
|
892
1052
|
module: resolvedServerOutput === 'module',
|
|
1053
|
+
chunkFilename: 'static/js/async/[name].js',
|
|
893
1054
|
},
|
|
894
1055
|
},
|
|
895
1056
|
},
|
|
@@ -898,24 +1059,30 @@ export const pluginReactRouter = (
|
|
|
898
1059
|
});
|
|
899
1060
|
});
|
|
900
1061
|
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
1062
|
+
registerReactRouterEnvironmentOutput({
|
|
1063
|
+
api,
|
|
1064
|
+
federation: pluginOptions.federation,
|
|
1065
|
+
resolvedServerOutput,
|
|
1066
|
+
});
|
|
1067
|
+
|
|
1068
|
+
if (modePlan.kind === 'classic' && useRouteModuleTransformLoader) {
|
|
1069
|
+
api.modifyEnvironmentConfig(
|
|
1070
|
+
async (config, { name, mergeEnvironmentConfig }) => {
|
|
1071
|
+
if (name !== 'web' && name !== 'node') {
|
|
1072
|
+
return config;
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
return mergeEnvironmentConfig(config, {
|
|
1076
|
+
tools: {
|
|
1077
|
+
rspack: rspackConfig => {
|
|
1078
|
+
const environmentDevHmrEnabled =
|
|
1079
|
+
name === 'web' &&
|
|
1080
|
+
!isBuild &&
|
|
1081
|
+
devHmrRefreshRuntimePath !== undefined &&
|
|
1082
|
+
config.mode === 'development' &&
|
|
1083
|
+
config.dev?.hmr !== false &&
|
|
1084
|
+
isRspackSwcReactRefreshEnabled(rspackConfig);
|
|
906
1085
|
|
|
907
|
-
return mergeEnvironmentConfig(config, {
|
|
908
|
-
tools: {
|
|
909
|
-
rspack: rspackConfig => {
|
|
910
|
-
const environmentDevHmrEnabled =
|
|
911
|
-
name === 'web' &&
|
|
912
|
-
!isBuild &&
|
|
913
|
-
devHmrRefreshRuntimePath !== undefined &&
|
|
914
|
-
config.mode === 'development' &&
|
|
915
|
-
config.dev?.hmr !== false &&
|
|
916
|
-
isRspackSwcReactRefreshEnabled(rspackConfig);
|
|
917
|
-
|
|
918
|
-
if (useRouteModuleTransformLoader) {
|
|
919
1086
|
registerRouteModuleTransformRules(rspackConfig, {
|
|
920
1087
|
environmentName: name,
|
|
921
1088
|
ssr,
|
|
@@ -927,93 +1094,91 @@ export const pluginReactRouter = (
|
|
|
927
1094
|
routeByFilePath,
|
|
928
1095
|
parallelRouteTransform: pluginOptions.parallelRouteTransform,
|
|
929
1096
|
});
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
if (pluginOptions.federation) {
|
|
933
|
-
ensureFederationAsyncStartup(rspackConfig);
|
|
934
|
-
}
|
|
935
|
-
|
|
936
|
-
if (name === 'web') {
|
|
937
|
-
devHmrEnabled = environmentDevHmrEnabled;
|
|
938
|
-
if (devHmrEnabled) {
|
|
939
|
-
devHdrSignal?.ensure();
|
|
940
|
-
}
|
|
941
|
-
}
|
|
942
|
-
|
|
943
|
-
if (name === 'node') {
|
|
944
|
-
const output = rspackConfig.output;
|
|
945
|
-
if (output) {
|
|
946
|
-
const library = output.library;
|
|
947
|
-
const libraryOptions =
|
|
948
|
-
library &&
|
|
949
|
-
typeof library === 'object' &&
|
|
950
|
-
!Array.isArray(library)
|
|
951
|
-
? library
|
|
952
|
-
: {};
|
|
953
|
-
rspackConfig.output = {
|
|
954
|
-
...output,
|
|
955
|
-
library: {
|
|
956
|
-
...libraryOptions,
|
|
957
|
-
type:
|
|
958
|
-
resolvedServerOutput === 'module'
|
|
959
|
-
? 'module'
|
|
960
|
-
: 'commonjs2',
|
|
961
|
-
},
|
|
962
|
-
};
|
|
963
|
-
}
|
|
964
|
-
}
|
|
965
|
-
|
|
966
|
-
return rspackConfig;
|
|
1097
|
+
return rspackConfig;
|
|
1098
|
+
},
|
|
967
1099
|
},
|
|
968
|
-
}
|
|
969
|
-
}
|
|
970
|
-
|
|
971
|
-
|
|
1100
|
+
});
|
|
1101
|
+
}
|
|
1102
|
+
);
|
|
1103
|
+
}
|
|
972
1104
|
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
future,
|
|
983
|
-
manifestChunkNames,
|
|
984
|
-
onManifest: (manifest, sri, moduleExportsByRouteId, context) =>
|
|
985
|
-
stageLatestManifests(
|
|
986
|
-
manifest,
|
|
987
|
-
sri,
|
|
988
|
-
moduleExportsByRouteId,
|
|
989
|
-
context.compilation
|
|
990
|
-
),
|
|
991
|
-
}
|
|
992
|
-
);
|
|
1105
|
+
if (modePlan.kind === 'rsc') {
|
|
1106
|
+
registerReactRouterRscRouteTransforms({
|
|
1107
|
+
api,
|
|
1108
|
+
isBuild,
|
|
1109
|
+
performanceProfiler,
|
|
1110
|
+
routeByFilePath,
|
|
1111
|
+
routeChunkCache,
|
|
1112
|
+
routeChunkConfig: modePlan.routeChunkConfig,
|
|
1113
|
+
});
|
|
993
1114
|
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1115
|
+
// RSC mode has no `registerBuildOutputTransforms` pass, so relocate the
|
|
1116
|
+
// node-emitted `?url`/`.css?url` static assets into the client build here.
|
|
1117
|
+
// Without this the href baked into `links()` (resolved in the node env)
|
|
1118
|
+
// 404s in the browser because the file only exists under `build/server`.
|
|
1119
|
+
registerSsrAssetRelocation({
|
|
1120
|
+
api,
|
|
1121
|
+
outputClientPath,
|
|
1122
|
+
performanceProfiler,
|
|
1123
|
+
});
|
|
1124
|
+
} else {
|
|
1125
|
+
registerModifyBrowserManifestAssets(
|
|
1126
|
+
api,
|
|
1127
|
+
routes,
|
|
1128
|
+
pluginOptions,
|
|
1129
|
+
appDirectory,
|
|
1130
|
+
() => assetPrefix,
|
|
1131
|
+
modePlan.routeChunkOptions,
|
|
1132
|
+
{
|
|
1133
|
+
subResourceIntegrity: resolvedConfigWithRoutes.subResourceIntegrity,
|
|
1134
|
+
future,
|
|
1135
|
+
manifestChunkNames,
|
|
1136
|
+
routeModuleAnalysis,
|
|
1137
|
+
onManifest: (manifest, sri, moduleExportsByRouteId, context) =>
|
|
1138
|
+
stageLatestManifests(
|
|
1139
|
+
manifest,
|
|
1140
|
+
sri,
|
|
1141
|
+
moduleExportsByRouteId,
|
|
1142
|
+
context.compilation
|
|
1143
|
+
),
|
|
1144
|
+
}
|
|
1145
|
+
);
|
|
1146
|
+
|
|
1147
|
+
registerBuildOutputTransforms({
|
|
1148
|
+
api,
|
|
1149
|
+
resolvedServerOutput,
|
|
1150
|
+
performanceProfiler,
|
|
1151
|
+
getLatestServerManifest: () => latestServerManifest,
|
|
1152
|
+
getLatestServerManifestByBundleId: bundleId =>
|
|
1153
|
+
latestServerManifestsByBundleId[bundleId],
|
|
1154
|
+
routes,
|
|
1155
|
+
pluginOptions,
|
|
1156
|
+
getClientStats: () => clientStats,
|
|
1157
|
+
appDirectory,
|
|
1158
|
+
getAssetPrefix: () => assetPrefix,
|
|
1159
|
+
routeChunkOptions: modePlan.routeChunkOptions,
|
|
1160
|
+
routeModuleAnalysis,
|
|
1161
|
+
routeTransformRunner,
|
|
1162
|
+
routeByFilePath,
|
|
1163
|
+
routeChunkConfig: modePlan.routeChunkConfig,
|
|
1164
|
+
isBuild,
|
|
1165
|
+
splitRouteModules: Boolean(modePlan.routeChunkConfig.splitRouteModules),
|
|
1166
|
+
useRouteModuleTransformApi: !useRouteModuleTransformLoader,
|
|
1167
|
+
ssr,
|
|
1168
|
+
isSpaMode,
|
|
1169
|
+
rootRoutePath,
|
|
1170
|
+
outputClientPath,
|
|
1171
|
+
isDevHmrEnabled: () => devHmrEnabled,
|
|
1172
|
+
onRouteModuleAnalysis: rememberRouteModuleAnalysis,
|
|
1173
|
+
});
|
|
1174
|
+
}
|
|
1018
1175
|
},
|
|
1019
1176
|
});
|
|
1177
|
+
|
|
1178
|
+
export const pluginReactRouterRSC = (
|
|
1179
|
+
options: ReactRouterRSCPluginOptions = {}
|
|
1180
|
+
): RsbuildPlugin =>
|
|
1181
|
+
pluginReactRouter({
|
|
1182
|
+
...options,
|
|
1183
|
+
rsc: options.rsc ?? true,
|
|
1184
|
+
});
|