rsbuild-plugin-react-router 0.4.1 → 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 +72 -240
- package/dist/{451.js → 511.js} +461 -331
- package/dist/build-output-transforms.d.ts +32 -7
- 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 -3
- 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/federation.d.ts +2 -0
- package/dist/index.cjs +3675 -2107
- package/dist/index.d.ts +3 -1
- package/dist/index.js +3614 -2214
- 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/performance.d.ts +4 -1
- 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-module-transform-loader.d.ts +14 -0
- package/dist/route-module-transform-loader.js +44 -0
- package/dist/route-module-transform-rules.d.ts +14 -0
- package/dist/route-transform-tasks.d.ts +6 -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 +34 -6
- package/package.json +76 -22
- package/src/build-output-transforms.ts +181 -43
- 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 -100
- 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/federation.ts +38 -0
- package/src/index.ts +666 -519
- 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/performance.ts +11 -2
- 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-module-transform-loader.ts +149 -0
- package/src/route-module-transform-rules.ts +115 -0
- package/src/route-transform-tasks.ts +44 -29
- 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 +43 -6
- package/src/warnings/warn-on-client-source-maps.ts +6 -10
- package/dist/parallel-route-transform-protocol.d.ts +0 -25
- package/dist/parallel-route-transform-worker.d.ts +0 -1
- package/dist/parallel-route-transform-worker.js +0 -38
- package/dist/parallel-route-transforms.d.ts +0 -29
- package/src/parallel-route-transform-protocol.ts +0 -35
- package/src/parallel-route-transform-worker.ts +0 -82
- package/src/parallel-route-transforms.ts +0 -458
package/src/index.ts
CHANGED
|
@@ -2,101 +2,109 @@ 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 { createReactRouterDevServerSetup } from './dev-server.js';
|
|
22
15
|
import {
|
|
23
|
-
generateWithProps,
|
|
24
16
|
findEntryFile,
|
|
25
|
-
|
|
17
|
+
resolveAppPackagePath,
|
|
18
|
+
resolveEffectiveAssetPrefix,
|
|
26
19
|
} from './plugin-utils.js';
|
|
27
|
-
import
|
|
28
|
-
import {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
} from './
|
|
32
|
-
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';
|
|
33
25
|
import { runReactRouterPrerenderBuild } from './prerender-build.js';
|
|
26
|
+
import { runReactRouterRscPrerenderBuild } from './rsc-prerender.js';
|
|
34
27
|
import {
|
|
35
|
-
|
|
28
|
+
resolveReactRouterConfigEffect,
|
|
29
|
+
resolveRouteDiscoveryConfig,
|
|
36
30
|
type ResolvedReactRouterConfig,
|
|
37
31
|
} from './react-router-config.js';
|
|
38
32
|
import {
|
|
39
|
-
getReactRouterManifestForDev,
|
|
40
33
|
configRoutesToRouteManifest,
|
|
41
34
|
createReactRouterManifestStats,
|
|
35
|
+
type ReactRouterManifestForDev as ReactRouterManifest,
|
|
42
36
|
type ReactRouterManifestStats,
|
|
43
37
|
type RouteManifestModuleExports,
|
|
44
38
|
} from './manifest.js';
|
|
39
|
+
import type { RouteModuleAnalysis } from './export-utils.js';
|
|
45
40
|
import { registerModifyBrowserManifestAssets } from './modify-browser-manifest.js';
|
|
46
|
-
import { registerBuildOutputTransforms } from './build-output-transforms.js';
|
|
47
41
|
import {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
42
|
+
registerBuildOutputTransforms,
|
|
43
|
+
registerSsrAssetRelocation,
|
|
44
|
+
} from './build-output-transforms.js';
|
|
45
|
+
import { type RouteChunkCache } from './route-chunks.js';
|
|
46
|
+
import {
|
|
47
|
+
registerRouteModuleTransformRules,
|
|
48
|
+
shouldUseRouteModuleTransformLoader,
|
|
49
|
+
} from './route-module-transform-rules.js';
|
|
54
50
|
import {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
} from './
|
|
51
|
+
executeRouteTransformTask,
|
|
52
|
+
type RouteTransformRunner,
|
|
53
|
+
} from './route-transform-tasks.js';
|
|
58
54
|
import { getRouteRestartMarkerPath, mergeWatchFiles } from './route-watch.js';
|
|
59
55
|
import { validateRouteConfig } from './route-config.js';
|
|
60
|
-
import {
|
|
61
|
-
getBuildManifest,
|
|
62
|
-
getRoutesByServerBundleId,
|
|
63
|
-
} from './build-manifest.js';
|
|
64
|
-
import {
|
|
65
|
-
createReactRouterNodeEntries,
|
|
66
|
-
createReactRouterServerBuildPlan,
|
|
67
|
-
} from './server-build-plan.js';
|
|
68
56
|
import { warnOnClientSourceMaps } from './warnings/warn-on-client-source-maps.js';
|
|
69
57
|
import { validatePluginOrderFromConfig } from './validation/validate-plugin-order.js';
|
|
70
|
-
import { getSsrExternals } from './ssr-externals.js';
|
|
71
58
|
import {
|
|
72
59
|
createReactRouterPerformanceProfiler,
|
|
73
60
|
roundMs,
|
|
74
61
|
} from './performance.js';
|
|
75
62
|
import { mapVirtualModules } from './virtual-modules.js';
|
|
76
|
-
import { createReactRouterDevRuntimeController } from './dev-runtime-controller.js';
|
|
77
|
-
import { runPluginEffect, tryPluginPromise } from './effect-runtime.js';
|
|
78
|
-
import { registerReactRouterTypegen } from './typegen.js';
|
|
79
|
-
import { importConfigWithWatchPaths } from './config-imports.js';
|
|
80
|
-
import {
|
|
81
|
-
createReactRouterRouteTopology,
|
|
82
|
-
createReactRouterRouteWatchFiles,
|
|
83
|
-
registerReactRouterDevBackgroundResources,
|
|
84
|
-
} from './dev-background-resources.js';
|
|
85
63
|
import {
|
|
86
64
|
createDevHdrRevisionSignal,
|
|
87
65
|
generateDevHmrRuntimeModule,
|
|
88
66
|
getDevHdrRevisionFilePath,
|
|
89
67
|
isRspackSwcReactRefreshEnabled,
|
|
90
68
|
resolveReactRefreshRuntimePath,
|
|
91
|
-
DEV_HMR_RUNTIME_MODULE_ID,
|
|
92
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';
|
|
93
94
|
|
|
94
95
|
export type { Config as ReactRouterRsbuildConfig } from './react-router-config.js';
|
|
95
96
|
export { loadReactRouterServerBuild } from './dev-generation.js';
|
|
96
97
|
export { resolveReactRouterServerBuild };
|
|
98
|
+
export type { PluginOptions, ReactRouterRSCPluginOptions } from './types.js';
|
|
97
99
|
|
|
98
100
|
const MIN_PARALLEL_ENVIRONMENT_BUILD_SPARE_CORES = 4;
|
|
99
101
|
|
|
102
|
+
type ReactRouterPresetResolvedConfig = Parameters<
|
|
103
|
+
NonNullable<
|
|
104
|
+
NonNullable<Config['presets']>[number]['reactRouterConfigResolved']
|
|
105
|
+
>
|
|
106
|
+
>[0]['reactRouterConfig'];
|
|
107
|
+
|
|
100
108
|
export const shouldParallelizeEnvironmentBuilds = ({
|
|
101
109
|
isBuild,
|
|
102
110
|
spareCoreCount = getDefaultConcurrency(),
|
|
@@ -106,46 +114,60 @@ export const shouldParallelizeEnvironmentBuilds = ({
|
|
|
106
114
|
}): boolean =>
|
|
107
115
|
!isBuild && spareCoreCount >= MIN_PARALLEL_ENVIRONMENT_BUILD_SPARE_CORES;
|
|
108
116
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
return;
|
|
117
|
+
const cssUrlAssetExtensions =
|
|
118
|
+
/\.(?:css|less|sass|scss|styl|stylus|pcss|postcss|sss)$/;
|
|
119
|
+
const urlAssetResourceQuery =
|
|
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;
|
|
120
129
|
}
|
|
121
130
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
131
|
+
while (index < code.length) {
|
|
132
|
+
while (
|
|
133
|
+
index < code.length &&
|
|
134
|
+
javascriptWhitespace.test(code.charAt(index))
|
|
135
|
+
) {
|
|
136
|
+
index += 1;
|
|
125
137
|
}
|
|
126
|
-
|
|
127
|
-
|
|
138
|
+
if (code.startsWith('//', index)) {
|
|
139
|
+
const lineEnd = code.indexOf('\n', index + 2);
|
|
140
|
+
if (lineEnd === -1) return false;
|
|
141
|
+
index = lineEnd + 1;
|
|
128
142
|
continue;
|
|
129
143
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
(
|
|
133
|
-
|
|
134
|
-
if (!pluginOptions) {
|
|
144
|
+
if (code.startsWith('/*', index)) {
|
|
145
|
+
const commentEnd = code.indexOf('*/', index + 2);
|
|
146
|
+
if (commentEnd === -1) return false;
|
|
147
|
+
index = commentEnd + 2;
|
|
135
148
|
continue;
|
|
136
149
|
}
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
137
152
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
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;
|
|
142
160
|
}
|
|
161
|
+
return code.charAt(index) === ';';
|
|
143
162
|
};
|
|
144
163
|
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
164
|
+
const isRscClientModule = (filePath: string): boolean => {
|
|
165
|
+
try {
|
|
166
|
+
return hasUseClientDirective(readFileSync(filePath, 'utf8'));
|
|
167
|
+
} catch {
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
};
|
|
149
171
|
|
|
150
172
|
export const pluginReactRouter = (
|
|
151
173
|
options: PluginOptions = {}
|
|
@@ -153,9 +175,15 @@ export const pluginReactRouter = (
|
|
|
153
175
|
name: PLUGIN_NAME,
|
|
154
176
|
|
|
155
177
|
async setup(api) {
|
|
178
|
+
const effectRuntime = createPluginEffectRuntime();
|
|
179
|
+
api.onCloseBuild(effectRuntime.dispose);
|
|
180
|
+
api.onCloseDevServer(effectRuntime.dispose);
|
|
181
|
+
api.onExit(effectRuntime.dispose);
|
|
182
|
+
|
|
156
183
|
const defaultOptions = {
|
|
157
184
|
customServer: false,
|
|
158
185
|
lazyCompilation: true,
|
|
186
|
+
rsc: false,
|
|
159
187
|
serverOutput: 'module' as const,
|
|
160
188
|
};
|
|
161
189
|
|
|
@@ -163,16 +191,13 @@ export const pluginReactRouter = (
|
|
|
163
191
|
...defaultOptions,
|
|
164
192
|
...options,
|
|
165
193
|
};
|
|
194
|
+
const isRscMode = Boolean(pluginOptions.rsc);
|
|
166
195
|
const logPerformance = pluginOptions.logPerformance === true;
|
|
167
196
|
const setupStartMs = logPerformance ? performance.now() : 0;
|
|
168
197
|
const performanceProfiler = createReactRouterPerformanceProfiler({
|
|
169
198
|
enabled: logPerformance,
|
|
170
199
|
log: message => api.logger.info(message),
|
|
171
200
|
});
|
|
172
|
-
const nodeExternals = Array.from(
|
|
173
|
-
new Set(['express', ...getSsrExternals(process.cwd())])
|
|
174
|
-
);
|
|
175
|
-
|
|
176
201
|
let assetPrefix = '/';
|
|
177
202
|
|
|
178
203
|
// Best-effort configuration validation (upstream: validate-plugin-order).
|
|
@@ -188,7 +213,6 @@ export const pluginReactRouter = (
|
|
|
188
213
|
}
|
|
189
214
|
api.logger.warn(issue.message);
|
|
190
215
|
}
|
|
191
|
-
assetPrefix = normalizeAssetPrefix(config.output?.assetPrefix);
|
|
192
216
|
return config;
|
|
193
217
|
},
|
|
194
218
|
});
|
|
@@ -198,6 +222,15 @@ export const pluginReactRouter = (
|
|
|
198
222
|
warnOnClientSourceMaps(normalized, msg => api.logger.warn(msg), 'web');
|
|
199
223
|
});
|
|
200
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
|
+
|
|
201
234
|
const configPath = findEntryFile(resolve('react-router.config'));
|
|
202
235
|
const configExists = existsSync(configPath);
|
|
203
236
|
let configWatchPaths: string | string[] = configExists
|
|
@@ -230,9 +263,12 @@ export const pluginReactRouter = (
|
|
|
230
263
|
|
|
231
264
|
const {
|
|
232
265
|
resolved: resolvedConfig,
|
|
266
|
+
userAndPresetConfig,
|
|
233
267
|
presets: configPresets,
|
|
234
268
|
hasConfiguredServerModuleFormat,
|
|
235
|
-
} = await
|
|
269
|
+
} = await effectRuntime.runPromise(
|
|
270
|
+
resolveReactRouterConfigEffect(reactRouterUserConfig)
|
|
271
|
+
);
|
|
236
272
|
|
|
237
273
|
const {
|
|
238
274
|
appDirectory,
|
|
@@ -244,12 +280,17 @@ export const pluginReactRouter = (
|
|
|
244
280
|
ssr,
|
|
245
281
|
prerender: prerenderConfig,
|
|
246
282
|
serverBuildFile,
|
|
283
|
+
serverBundles,
|
|
247
284
|
serverModuleFormat,
|
|
248
285
|
splitRouteModules,
|
|
286
|
+
subResourceIntegrity,
|
|
249
287
|
buildEnd,
|
|
250
288
|
} = resolvedConfig;
|
|
251
289
|
|
|
252
|
-
registerReactRouterTypegen(api, {
|
|
290
|
+
await registerReactRouterTypegen(api, {
|
|
291
|
+
runtime: effectRuntime,
|
|
292
|
+
appDirectory,
|
|
293
|
+
});
|
|
253
294
|
|
|
254
295
|
const hasExplicitServerOutput = Object.prototype.hasOwnProperty.call(
|
|
255
296
|
options,
|
|
@@ -290,57 +331,57 @@ export const pluginReactRouter = (
|
|
|
290
331
|
throw new Error(prerenderConfigError);
|
|
291
332
|
}
|
|
292
333
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
if (!userRouteDiscovery) {
|
|
298
|
-
routeDiscovery = ssr
|
|
299
|
-
? ({ mode: 'lazy', manifestPath: '/__manifest' } as const)
|
|
300
|
-
: ({ mode: 'initial' } as const);
|
|
301
|
-
} else if (userRouteDiscovery.mode === 'initial') {
|
|
302
|
-
routeDiscovery = userRouteDiscovery;
|
|
303
|
-
} else if (userRouteDiscovery.mode === 'lazy') {
|
|
304
|
-
if (!ssr) {
|
|
305
|
-
throw new Error(
|
|
306
|
-
'The `routeDiscovery.mode` config cannot be set to "lazy" when setting `ssr:false`'
|
|
307
|
-
);
|
|
308
|
-
}
|
|
309
|
-
const manifestPath = userRouteDiscovery.manifestPath;
|
|
310
|
-
if (manifestPath && !manifestPath.startsWith('/')) {
|
|
311
|
-
throw new Error(
|
|
312
|
-
'The `routeDiscovery.manifestPath` config must be a root-relative pathname beginning with a slash (i.e., "/__manifest")'
|
|
313
|
-
);
|
|
314
|
-
}
|
|
315
|
-
routeDiscovery = userRouteDiscovery;
|
|
316
|
-
}
|
|
334
|
+
const routeDiscovery = resolveRouteDiscoveryConfig({
|
|
335
|
+
ssr,
|
|
336
|
+
userRouteDiscovery,
|
|
337
|
+
});
|
|
317
338
|
|
|
318
339
|
(globalThis as any).__reactRouterAppDirectory = resolve(appDirectory);
|
|
319
340
|
const routesPath = findEntryFile(resolve(appDirectory, 'routes'));
|
|
320
341
|
if (!existsSync(routesPath)) {
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
routesPath
|
|
325
|
-
)}".`
|
|
342
|
+
const missingRoutesPath = relative(
|
|
343
|
+
process.cwd(),
|
|
344
|
+
resolve(appDirectory, 'routes.ts')
|
|
326
345
|
);
|
|
346
|
+
throw new Error(`Route config file not found at "${missingRoutesPath}".`);
|
|
327
347
|
}
|
|
328
348
|
|
|
329
|
-
const
|
|
349
|
+
const routeConfigDefine =
|
|
350
|
+
typeof api.getRsbuildConfig === 'function'
|
|
351
|
+
? api.getRsbuildConfig().source?.define
|
|
352
|
+
: undefined;
|
|
353
|
+
const jiti = createConfigImporter({
|
|
354
|
+
define: routeConfigDefine,
|
|
330
355
|
moduleCache: false,
|
|
331
356
|
});
|
|
332
357
|
const importRouteConfig = async (
|
|
333
|
-
importer:
|
|
358
|
+
importer: ConfigImporter
|
|
334
359
|
): Promise<RouteConfigEntry[]> => {
|
|
335
|
-
const
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
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
|
+
}
|
|
342
383
|
const validation = validateRouteConfig({
|
|
343
|
-
routeConfigFile
|
|
384
|
+
routeConfigFile,
|
|
344
385
|
routeConfig: routeConfigValue,
|
|
345
386
|
});
|
|
346
387
|
if (!validation.valid) {
|
|
@@ -350,33 +391,41 @@ export const pluginReactRouter = (
|
|
|
350
391
|
};
|
|
351
392
|
const loadRouteConfig = () => importRouteConfig(jiti);
|
|
352
393
|
const { value: routeConfig, watchPaths: routeConfigWatchPaths } =
|
|
353
|
-
await importConfigWithWatchPaths(routesPath, importRouteConfig
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
resolve(appDirectory, 'entry.client')
|
|
357
|
-
);
|
|
358
|
-
const entryServerPath = findEntryFile(
|
|
359
|
-
resolve(appDirectory, 'entry.server')
|
|
360
|
-
);
|
|
361
|
-
|
|
362
|
-
const serverAppPath = findEntryFile(
|
|
363
|
-
resolve(appDirectory, '../server/index')
|
|
364
|
-
);
|
|
365
|
-
const hasServerApp = existsSync(serverAppPath);
|
|
366
|
-
const devServerBuildEntryName = hasServerApp
|
|
367
|
-
? 'static/js/react-router-server-build'
|
|
368
|
-
: 'static/js/app';
|
|
394
|
+
await importConfigWithWatchPaths(routesPath, importRouteConfig, {
|
|
395
|
+
define: routeConfigDefine,
|
|
396
|
+
});
|
|
369
397
|
|
|
370
|
-
const
|
|
371
|
-
|
|
372
|
-
|
|
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
|
+
});
|
|
373
411
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
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
|
+
}
|
|
380
429
|
|
|
381
430
|
const getRootRoutePath = () => findEntryFile(resolve(appDirectory, 'root'));
|
|
382
431
|
const rootRoutePath = getRootRoutePath();
|
|
@@ -397,25 +446,45 @@ export const pluginReactRouter = (
|
|
|
397
446
|
};
|
|
398
447
|
|
|
399
448
|
const resolvedConfigWithRoutes: ResolvedReactRouterConfig = {
|
|
400
|
-
...resolvedConfig,
|
|
401
449
|
appDirectory: resolve(appDirectory),
|
|
450
|
+
basename,
|
|
402
451
|
buildDirectory: resolve(buildDirectory),
|
|
403
|
-
|
|
452
|
+
buildEnd,
|
|
453
|
+
future,
|
|
404
454
|
prerender: prerenderConfig,
|
|
405
455
|
routes,
|
|
406
|
-
|
|
456
|
+
routeDiscovery,
|
|
457
|
+
serverBuildFile,
|
|
458
|
+
serverBundles,
|
|
459
|
+
serverModuleFormat,
|
|
460
|
+
ssr,
|
|
461
|
+
splitRouteModules,
|
|
462
|
+
subResourceIntegrity,
|
|
407
463
|
allowedActionOrigins: allowedActionOrigins ?? false,
|
|
464
|
+
unstable_routeConfig: routeConfig,
|
|
408
465
|
};
|
|
409
466
|
|
|
410
467
|
const { buildEnd: _buildEnd, ...resolvedConfigForPreset } =
|
|
411
468
|
resolvedConfigWithRoutes;
|
|
412
469
|
for (const preset of configPresets) {
|
|
413
470
|
await preset.reactRouterConfigResolved?.({
|
|
414
|
-
reactRouterConfig:
|
|
471
|
+
reactRouterConfig:
|
|
472
|
+
resolvedConfigForPreset as ReactRouterPresetResolvedConfig,
|
|
415
473
|
});
|
|
416
474
|
}
|
|
475
|
+
const buildEndReactRouterConfig: ResolvedReactRouterConfig = {
|
|
476
|
+
...resolvedConfigWithRoutes,
|
|
477
|
+
future: userAndPresetConfig.future ?? {},
|
|
478
|
+
} as ResolvedReactRouterConfig;
|
|
417
479
|
|
|
418
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
|
+
}
|
|
419
488
|
const shouldDependOnWebCompiler = !shouldParallelizeEnvironmentBuilds({
|
|
420
489
|
isBuild,
|
|
421
490
|
});
|
|
@@ -423,57 +492,216 @@ export const pluginReactRouter = (
|
|
|
423
492
|
prerenderConfig !== undefined && prerenderConfig !== false;
|
|
424
493
|
const isSpaMode = !ssr && !isPrerenderEnabled;
|
|
425
494
|
const routeCount = Object.keys(routes).length;
|
|
426
|
-
const routeChunkConfig: RouteChunkConfig = {
|
|
427
|
-
splitRouteModules,
|
|
428
|
-
appDirectory,
|
|
429
|
-
rootRouteFile,
|
|
430
|
-
};
|
|
431
495
|
const routeChunkCache: RouteChunkCache = new Map();
|
|
432
|
-
const
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
routeChunkCache
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
496
|
+
const useRouteModuleTransformLoader =
|
|
497
|
+
!isRscMode &&
|
|
498
|
+
shouldUseRouteModuleTransformLoader(pluginOptions.parallelRouteTransform);
|
|
499
|
+
const routeTransformRunner: RouteTransformRunner = task =>
|
|
500
|
+
executeRouteTransformTask(task, { routeChunkCache });
|
|
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);
|
|
445
510
|
};
|
|
511
|
+
const routeModuleAnalysis = async (routeFilePath: string) =>
|
|
512
|
+
transformedRouteModuleAnalyses.get(resolve(routeFilePath));
|
|
446
513
|
const outputClientPath = resolve(buildDirectory, 'client');
|
|
447
514
|
const assetsBuildDirectory = relative(process.cwd(), outputClientPath);
|
|
448
515
|
const watchDirectory = resolve(appDirectory);
|
|
449
|
-
const routeRestartMarkerPath = getRouteRestartMarkerPath(
|
|
516
|
+
const routeRestartMarkerPath = getRouteRestartMarkerPath(appDirectory);
|
|
450
517
|
const routeWatchFiles = createReactRouterRouteWatchFiles({
|
|
451
518
|
configWatchPaths,
|
|
452
519
|
routeConfigWatchPaths,
|
|
453
520
|
routeRestartMarkerPath,
|
|
454
521
|
onRouteTopologyChange: pluginOptions.onRouteTopologyChange,
|
|
455
522
|
});
|
|
456
|
-
const devBackgroundResources = registerReactRouterDevBackgroundResources({
|
|
457
|
-
api,
|
|
458
|
-
isBuild,
|
|
459
|
-
lazyCompilationPrewarm: pluginOptions.unstableLazyCompilationPrewarm,
|
|
460
|
-
routeTransformExecutor,
|
|
461
|
-
routeRestartMarkerPath,
|
|
462
|
-
watchDirectory,
|
|
463
|
-
getRouteTopology: routeTopology.getRouteTopology,
|
|
464
|
-
initialRouteTopology: routeTopology.initialRouteTopology,
|
|
465
|
-
onRouteTopologyChange: pluginOptions.onRouteTopologyChange,
|
|
466
|
-
});
|
|
467
|
-
|
|
468
|
-
type ReactRouterManifest = Awaited<
|
|
469
|
-
ReturnType<typeof getReactRouterManifestForDev>
|
|
470
|
-
>;
|
|
471
523
|
let latestBrowserManifest: ReactRouterManifest | null = null;
|
|
472
524
|
let latestBrowserManifestModuleExports: RouteManifestModuleExports = {};
|
|
473
525
|
let latestServerManifest: ReactRouterManifest | null = null;
|
|
474
526
|
const latestServerManifestsByBundleId: Record<string, ReactRouterManifest> =
|
|
475
527
|
{};
|
|
476
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
|
+
|
|
477
705
|
const stageLatestManifests = (
|
|
478
706
|
manifest: ReactRouterManifest,
|
|
479
707
|
sri: ReactRouterManifest['sri'],
|
|
@@ -497,8 +725,14 @@ export const pluginReactRouter = (
|
|
|
497
725
|
[devServerBuildEntryName]: baseServerManifest,
|
|
498
726
|
};
|
|
499
727
|
|
|
500
|
-
|
|
501
|
-
|
|
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];
|
|
502
736
|
if (!bundleRoutes) {
|
|
503
737
|
continue;
|
|
504
738
|
}
|
|
@@ -518,94 +752,15 @@ export const pluginReactRouter = (
|
|
|
518
752
|
}
|
|
519
753
|
|
|
520
754
|
if (!isBuild) {
|
|
521
|
-
devRuntime.captureWeb(
|
|
755
|
+
modePlan.artifacts.devRuntime.captureWeb(
|
|
756
|
+
compilation,
|
|
757
|
+
manifestsByEntryName
|
|
758
|
+
);
|
|
522
759
|
}
|
|
523
760
|
}
|
|
524
761
|
);
|
|
525
762
|
};
|
|
526
763
|
|
|
527
|
-
const routeByFilePath = new Map(
|
|
528
|
-
Object.values(routes).map(route => [
|
|
529
|
-
resolve(appDirectory, route.file),
|
|
530
|
-
route,
|
|
531
|
-
])
|
|
532
|
-
);
|
|
533
|
-
|
|
534
|
-
const manifestChunkNames = new Set<string>(['entry.client']);
|
|
535
|
-
const webRouteEntries = Object.values(routes).reduce(
|
|
536
|
-
(acc, route) => {
|
|
537
|
-
const entryName = route.file.slice(0, route.file.lastIndexOf('.'));
|
|
538
|
-
const routeFilePath = resolve(appDirectory, route.file);
|
|
539
|
-
manifestChunkNames.add(entryName);
|
|
540
|
-
acc[entryName] = {
|
|
541
|
-
import: `${routeFilePath}${BUILD_CLIENT_ROUTE_QUERY_STRING}`,
|
|
542
|
-
html: false,
|
|
543
|
-
};
|
|
544
|
-
|
|
545
|
-
if (isBuild && splitRouteModules && route.id !== 'root') {
|
|
546
|
-
let source: string;
|
|
547
|
-
try {
|
|
548
|
-
source = readFileSync(routeFilePath, 'utf8');
|
|
549
|
-
} catch (error) {
|
|
550
|
-
if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
|
|
551
|
-
return acc;
|
|
552
|
-
}
|
|
553
|
-
throw error;
|
|
554
|
-
}
|
|
555
|
-
for (const exportName of routeChunkExportNames) {
|
|
556
|
-
if (!source.includes(exportName)) {
|
|
557
|
-
continue;
|
|
558
|
-
}
|
|
559
|
-
const chunkEntryName = getRouteChunkEntryName(route.id, exportName);
|
|
560
|
-
manifestChunkNames.add(chunkEntryName);
|
|
561
|
-
acc[chunkEntryName] = {
|
|
562
|
-
import: getRouteChunkModuleId(routeFilePath, exportName),
|
|
563
|
-
html: false,
|
|
564
|
-
};
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
return acc;
|
|
569
|
-
},
|
|
570
|
-
{} as Record<string, RsbuildEntryDescription>
|
|
571
|
-
);
|
|
572
|
-
const buildManifest = await getBuildManifest({
|
|
573
|
-
reactRouterConfig: resolvedConfigWithRoutes,
|
|
574
|
-
routes,
|
|
575
|
-
rootDirectory: process.cwd(),
|
|
576
|
-
});
|
|
577
|
-
const routesByServerBundleId = getRoutesByServerBundleId(
|
|
578
|
-
buildManifest,
|
|
579
|
-
routes
|
|
580
|
-
);
|
|
581
|
-
const serverBuildPlan = createReactRouterServerBuildPlan({
|
|
582
|
-
routesByServerBundleId,
|
|
583
|
-
serverBuildFile,
|
|
584
|
-
defaultEntryName: devServerBuildEntryName,
|
|
585
|
-
});
|
|
586
|
-
const { serverBundleEntries } = serverBuildPlan;
|
|
587
|
-
|
|
588
|
-
const devHmrRefreshRuntimePath = isBuild
|
|
589
|
-
? undefined
|
|
590
|
-
: resolveReactRefreshRuntimePath(api.context.rootPath);
|
|
591
|
-
const devHdrSignal = devHmrRefreshRuntimePath
|
|
592
|
-
? createDevHdrRevisionSignal({
|
|
593
|
-
filePath: getDevHdrRevisionFilePath(api.context.rootPath),
|
|
594
|
-
onError: error =>
|
|
595
|
-
api.logger.debug(
|
|
596
|
-
`[${PLUGIN_NAME}] Failed to signal hot data revalidation: ${error.message}`
|
|
597
|
-
),
|
|
598
|
-
})
|
|
599
|
-
: undefined;
|
|
600
|
-
let devHmrEnabled = false;
|
|
601
|
-
|
|
602
|
-
const devRuntime = createReactRouterDevRuntimeController({
|
|
603
|
-
api,
|
|
604
|
-
isBuild,
|
|
605
|
-
buildPlan: serverBuildPlan,
|
|
606
|
-
onNodeRebuildCommitted: () => devHdrSignal?.bump(),
|
|
607
|
-
});
|
|
608
|
-
|
|
609
764
|
let clientStats: ReactRouterManifestStats | undefined;
|
|
610
765
|
api.onAfterEnvironmentCompile(({ stats, environment }) => {
|
|
611
766
|
if (environment.name === 'web') {
|
|
@@ -629,121 +784,82 @@ export const pluginReactRouter = (
|
|
|
629
784
|
}
|
|
630
785
|
});
|
|
631
786
|
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
api.onAfterBuild(({ environments }) =>
|
|
643
|
-
runPluginEffect(
|
|
644
|
-
tryPluginPromise(() =>
|
|
645
|
-
runReactRouterPrerenderBuild({
|
|
646
|
-
api,
|
|
647
|
-
hasWebEnvironment: Boolean(environments.web),
|
|
648
|
-
buildDirectory,
|
|
649
|
-
serverBuildFile,
|
|
650
|
-
ssr,
|
|
651
|
-
isPrerenderEnabled,
|
|
652
|
-
prerenderConfig,
|
|
653
|
-
prerenderPaths,
|
|
654
|
-
basename,
|
|
655
|
-
future,
|
|
656
|
-
routes,
|
|
657
|
-
latestBrowserManifest,
|
|
658
|
-
latestBrowserManifestModuleExports,
|
|
659
|
-
clientStats,
|
|
660
|
-
pluginOptions,
|
|
661
|
-
appDirectory,
|
|
662
|
-
assetPrefix,
|
|
663
|
-
routeChunkOptions,
|
|
664
|
-
buildManifest,
|
|
665
|
-
resolvedConfigWithRoutes,
|
|
666
|
-
buildEnd,
|
|
667
|
-
})
|
|
668
|
-
)
|
|
669
|
-
)
|
|
670
|
-
);
|
|
671
|
-
|
|
672
|
-
const allowedActionOriginsForBuild =
|
|
673
|
-
allowedActionOrigins === false ? undefined : allowedActionOrigins;
|
|
674
|
-
|
|
675
|
-
// Public requests stay bare while Rspack resolves seeded virtual files.
|
|
676
|
-
const createVirtualModulePlugin = (publicPath: string) => {
|
|
677
|
-
const bundleVirtualModules = Object.fromEntries(
|
|
678
|
-
Object.entries(routesByServerBundleId).map(
|
|
679
|
-
([bundleId, bundleRoutes]) => [
|
|
680
|
-
`virtual/react-router/server-build-${bundleId}`,
|
|
681
|
-
generateServerBuild(bundleRoutes, {
|
|
682
|
-
entryServerPath: finalEntryServerPath,
|
|
683
|
-
assetsBuildDirectory,
|
|
684
|
-
basename,
|
|
685
|
-
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,
|
|
686
796
|
ssr,
|
|
687
|
-
|
|
797
|
+
isPrerenderEnabled,
|
|
798
|
+
prerenderConfig,
|
|
799
|
+
prerenderPaths: modePlan.artifacts.prerenderPaths,
|
|
800
|
+
basename,
|
|
688
801
|
future,
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
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
|
+
)
|
|
696
816
|
)
|
|
697
817
|
);
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
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
|
+
})
|
|
703
832
|
)
|
|
704
|
-
|
|
705
|
-
`virtual/react-router/server-manifest-${bundleId}`,
|
|
706
|
-
'export default {};',
|
|
707
|
-
])
|
|
833
|
+
)
|
|
708
834
|
);
|
|
835
|
+
}
|
|
709
836
|
|
|
837
|
+
// Public requests stay bare while Rspack resolves seeded virtual files.
|
|
838
|
+
const createVirtualModulePlugin = (
|
|
839
|
+
publicPath: string,
|
|
840
|
+
jsDistPath: string
|
|
841
|
+
) => {
|
|
710
842
|
return new rspack.experiments.VirtualModulesPlugin(
|
|
711
|
-
mapVirtualModules(
|
|
712
|
-
'virtual/react-router/browser-manifest': 'export default {};',
|
|
713
|
-
'virtual/react-router/server-manifest': 'export default {};',
|
|
714
|
-
'virtual/react-router/server-build': generateServerBuild(routes, {
|
|
715
|
-
entryServerPath: finalEntryServerPath,
|
|
716
|
-
assetsBuildDirectory,
|
|
717
|
-
basename,
|
|
718
|
-
appDirectory,
|
|
719
|
-
ssr,
|
|
720
|
-
federation: options.federation,
|
|
721
|
-
future,
|
|
722
|
-
allowedActionOrigins: allowedActionOriginsForBuild,
|
|
723
|
-
prerender: prerenderPaths,
|
|
724
|
-
routeDiscovery,
|
|
725
|
-
publicPath,
|
|
726
|
-
}),
|
|
727
|
-
...bundleVirtualModules,
|
|
728
|
-
...bundleManifestModules,
|
|
729
|
-
'virtual/react-router/with-props': generateWithProps(),
|
|
730
|
-
...(devHmrRefreshRuntimePath
|
|
731
|
-
? {
|
|
732
|
-
[DEV_HMR_RUNTIME_MODULE_ID]: generateDevHmrRuntimeModule({
|
|
733
|
-
reactRefreshRuntimePath: devHmrRefreshRuntimePath,
|
|
734
|
-
hdrRevisionFilePath: getDevHdrRevisionFilePath(
|
|
735
|
-
api.context.rootPath
|
|
736
|
-
),
|
|
737
|
-
}),
|
|
738
|
-
}
|
|
739
|
-
: {}),
|
|
740
|
-
})
|
|
843
|
+
mapVirtualModules(modePlan.createVirtualModules(publicPath, jsDistPath))
|
|
741
844
|
);
|
|
742
845
|
};
|
|
743
846
|
|
|
744
847
|
api.modifyRsbuildConfig(async (config, { mergeRsbuildConfig }) => {
|
|
745
|
-
|
|
746
|
-
|
|
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);
|
|
747
863
|
const useAsyncNodeChunkLoading =
|
|
748
864
|
options.federation && resolvedServerOutput === 'commonjs';
|
|
749
865
|
let nodeChunkLoading: 'import' | 'async-node' | 'require' = 'require';
|
|
@@ -752,15 +868,6 @@ export const pluginReactRouter = (
|
|
|
752
868
|
} else if (useAsyncNodeChunkLoading) {
|
|
753
869
|
nodeChunkLoading = 'async-node';
|
|
754
870
|
}
|
|
755
|
-
const nodeEntries = createReactRouterNodeEntries({
|
|
756
|
-
hasServerApp,
|
|
757
|
-
isBuild,
|
|
758
|
-
serverAppPath,
|
|
759
|
-
entryServerPath: finalEntryServerPath,
|
|
760
|
-
defaultEntryName: devServerBuildEntryName,
|
|
761
|
-
serverBundleEntries,
|
|
762
|
-
});
|
|
763
|
-
|
|
764
871
|
const configuredLazyCompilation = Object.prototype.hasOwnProperty.call(
|
|
765
872
|
options,
|
|
766
873
|
'lazyCompilation'
|
|
@@ -769,7 +876,9 @@ export const pluginReactRouter = (
|
|
|
769
876
|
: (config.dev?.lazyCompilation ?? pluginOptions.lazyCompilation);
|
|
770
877
|
const guardedLazyCompilation = guardReactRouterLazyCompilation({
|
|
771
878
|
lazyCompilation: configuredLazyCompilation,
|
|
772
|
-
entryClientPath:
|
|
879
|
+
entryClientPath: isRscMode
|
|
880
|
+
? finalEntryRscClientPath
|
|
881
|
+
: finalEntryClientPath,
|
|
773
882
|
prewarmReactRouterModules: Boolean(
|
|
774
883
|
pluginOptions.unstableLazyCompilationPrewarm
|
|
775
884
|
),
|
|
@@ -783,6 +892,27 @@ export const pluginReactRouter = (
|
|
|
783
892
|
routeCount >= 256 &&
|
|
784
893
|
(config.performance?.printFileSize === undefined ||
|
|
785
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';
|
|
786
916
|
|
|
787
917
|
return mergeRsbuildConfig(config, {
|
|
788
918
|
...(shouldCompactFileSizeReport
|
|
@@ -799,29 +929,20 @@ export const pluginReactRouter = (
|
|
|
799
929
|
output: {
|
|
800
930
|
assetPrefix: config.output?.assetPrefix || '/',
|
|
801
931
|
},
|
|
932
|
+
server: modePlan.server,
|
|
802
933
|
dev: {
|
|
803
934
|
...lazyCompilation,
|
|
804
935
|
watchFiles: mergeWatchFiles(config.dev?.watchFiles, routeWatchFiles),
|
|
805
936
|
},
|
|
806
|
-
// React Router's request handler natively supports `ssr:false`
|
|
807
|
-
// builds (it renders the SPA shell for document requests), so the
|
|
808
|
-
// middleware is registered for SPA mode too — without it, dev
|
|
809
|
-
// requests would 404 because no HTML entry exists.
|
|
810
|
-
...(pluginOptions.customServer
|
|
811
|
-
? {}
|
|
812
|
-
: {
|
|
813
|
-
server: {
|
|
814
|
-
setup: [
|
|
815
|
-
createReactRouterDevServerSetup({
|
|
816
|
-
// Lazy: the dev runtime binding does not exist yet here.
|
|
817
|
-
loadBuild: () => devRuntime.createBuildLoader()(),
|
|
818
|
-
}),
|
|
819
|
-
],
|
|
820
|
-
},
|
|
821
|
-
}),
|
|
822
937
|
tools: {
|
|
823
938
|
rspack: {
|
|
824
|
-
|
|
939
|
+
resolve: resolveConfig,
|
|
940
|
+
plugins: [
|
|
941
|
+
vmodPlugin,
|
|
942
|
+
createQuerylessRouteImportPlugin(routeByFilePath, {
|
|
943
|
+
rsc: isRscMode,
|
|
944
|
+
}),
|
|
945
|
+
],
|
|
825
946
|
},
|
|
826
947
|
},
|
|
827
948
|
environments: {
|
|
@@ -836,15 +957,14 @@ export const pluginReactRouter = (
|
|
|
836
957
|
}
|
|
837
958
|
: {}),
|
|
838
959
|
source: {
|
|
839
|
-
entry:
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
},
|
|
960
|
+
entry: modePlan.webEntries,
|
|
961
|
+
...(userDefinesNodeEnv
|
|
962
|
+
? {}
|
|
963
|
+
: {
|
|
964
|
+
define: {
|
|
965
|
+
'process.env.NODE_ENV': JSON.stringify(webNodeEnv),
|
|
966
|
+
},
|
|
967
|
+
}),
|
|
848
968
|
},
|
|
849
969
|
output: {
|
|
850
970
|
filename: {
|
|
@@ -856,6 +976,7 @@ export const pluginReactRouter = (
|
|
|
856
976
|
},
|
|
857
977
|
tools: {
|
|
858
978
|
rspack: {
|
|
979
|
+
resolve: resolveConfig,
|
|
859
980
|
name: 'web',
|
|
860
981
|
module: {
|
|
861
982
|
rules: [
|
|
@@ -866,26 +987,17 @@ export const pluginReactRouter = (
|
|
|
866
987
|
},
|
|
867
988
|
],
|
|
868
989
|
},
|
|
869
|
-
|
|
870
|
-
? {
|
|
871
|
-
output: {
|
|
872
|
-
chunkLoading: 'import',
|
|
873
|
-
},
|
|
874
|
-
}
|
|
875
|
-
: {}),
|
|
876
|
-
externalsType: 'module',
|
|
990
|
+
externalsType: modePlan.webExternalsType,
|
|
877
991
|
output: {
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
optimization: {
|
|
886
|
-
avoidEntryIife: true,
|
|
887
|
-
runtimeChunk: 'single',
|
|
992
|
+
...modePlan.webOutput,
|
|
993
|
+
publicPath: assetPrefix,
|
|
994
|
+
...(options.federation
|
|
995
|
+
? {
|
|
996
|
+
chunkLoading: 'import',
|
|
997
|
+
}
|
|
998
|
+
: {}),
|
|
888
999
|
},
|
|
1000
|
+
optimization: modePlan.webOptimization,
|
|
889
1001
|
},
|
|
890
1002
|
},
|
|
891
1003
|
},
|
|
@@ -894,7 +1006,7 @@ export const pluginReactRouter = (
|
|
|
894
1006
|
// root route into a hydratable `index.html` at build time.
|
|
895
1007
|
node: {
|
|
896
1008
|
source: {
|
|
897
|
-
entry: nodeEntries,
|
|
1009
|
+
entry: modePlan.nodeEntries,
|
|
898
1010
|
},
|
|
899
1011
|
output: {
|
|
900
1012
|
distPath: {
|
|
@@ -903,6 +1015,15 @@ export const pluginReactRouter = (
|
|
|
903
1015
|
target: config.environments?.node?.output?.target || 'node',
|
|
904
1016
|
filename: {
|
|
905
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
|
+
},
|
|
906
1027
|
},
|
|
907
1028
|
},
|
|
908
1029
|
tools: {
|
|
@@ -917,15 +1038,19 @@ export const pluginReactRouter = (
|
|
|
917
1038
|
},
|
|
918
1039
|
],
|
|
919
1040
|
},
|
|
920
|
-
externals: nodeExternals,
|
|
921
|
-
...
|
|
1041
|
+
externals: modePlan.nodeExternals,
|
|
1042
|
+
...modePlan.nodeDependencies,
|
|
922
1043
|
externalsType: resolvedServerOutput,
|
|
923
1044
|
output: {
|
|
924
1045
|
chunkFormat: resolvedServerOutput,
|
|
925
1046
|
chunkLoading: nodeChunkLoading,
|
|
1047
|
+
devtoolModuleFilenameTemplate: '[absolute-resource-path]',
|
|
1048
|
+
devtoolFallbackModuleFilenameTemplate:
|
|
1049
|
+
'[absolute-resource-path]?[hash]',
|
|
926
1050
|
workerChunkLoading: nodeChunkLoading,
|
|
927
1051
|
wasmLoading: 'fetch',
|
|
928
1052
|
module: resolvedServerOutput === 'module',
|
|
1053
|
+
chunkFilename: 'static/js/async/[name].js',
|
|
929
1054
|
},
|
|
930
1055
|
},
|
|
931
1056
|
},
|
|
@@ -934,104 +1059,126 @@ export const pluginReactRouter = (
|
|
|
934
1059
|
});
|
|
935
1060
|
});
|
|
936
1061
|
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
1062
|
+
registerReactRouterEnvironmentOutput({
|
|
1063
|
+
api,
|
|
1064
|
+
federation: pluginOptions.federation,
|
|
1065
|
+
resolvedServerOutput,
|
|
1066
|
+
});
|
|
942
1067
|
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
1068
|
+
if (modePlan.kind === 'classic' && useRouteModuleTransformLoader) {
|
|
1069
|
+
api.modifyEnvironmentConfig(
|
|
1070
|
+
async (config, { name, mergeEnvironmentConfig }) => {
|
|
1071
|
+
if (name !== 'web' && name !== 'node') {
|
|
1072
|
+
return config;
|
|
1073
|
+
}
|
|
949
1074
|
|
|
950
|
-
|
|
951
|
-
|
|
1075
|
+
return mergeEnvironmentConfig(config, {
|
|
1076
|
+
tools: {
|
|
1077
|
+
rspack: rspackConfig => {
|
|
1078
|
+
const environmentDevHmrEnabled =
|
|
1079
|
+
name === 'web' &&
|
|
952
1080
|
!isBuild &&
|
|
953
1081
|
devHmrRefreshRuntimePath !== undefined &&
|
|
954
1082
|
config.mode === 'development' &&
|
|
955
1083
|
config.dev?.hmr !== false &&
|
|
956
1084
|
isRspackSwcReactRefreshEnabled(rspackConfig);
|
|
957
|
-
if (devHmrEnabled) {
|
|
958
|
-
devHdrSignal?.ensure();
|
|
959
|
-
}
|
|
960
|
-
}
|
|
961
1085
|
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
...libraryOptions,
|
|
976
|
-
type:
|
|
977
|
-
resolvedServerOutput === 'module'
|
|
978
|
-
? 'module'
|
|
979
|
-
: 'commonjs2',
|
|
980
|
-
},
|
|
981
|
-
};
|
|
982
|
-
}
|
|
983
|
-
}
|
|
984
|
-
|
|
985
|
-
return rspackConfig;
|
|
1086
|
+
registerRouteModuleTransformRules(rspackConfig, {
|
|
1087
|
+
environmentName: name,
|
|
1088
|
+
ssr,
|
|
1089
|
+
isBuild,
|
|
1090
|
+
isSpaMode,
|
|
1091
|
+
rootRoutePath,
|
|
1092
|
+
devHmr: environmentDevHmrEnabled,
|
|
1093
|
+
logPerformance,
|
|
1094
|
+
routeByFilePath,
|
|
1095
|
+
parallelRouteTransform: pluginOptions.parallelRouteTransform,
|
|
1096
|
+
});
|
|
1097
|
+
return rspackConfig;
|
|
1098
|
+
},
|
|
986
1099
|
},
|
|
987
|
-
}
|
|
988
|
-
}
|
|
989
|
-
|
|
990
|
-
|
|
1100
|
+
});
|
|
1101
|
+
}
|
|
1102
|
+
);
|
|
1103
|
+
}
|
|
991
1104
|
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
future,
|
|
1002
|
-
manifestChunkNames,
|
|
1003
|
-
onManifest: (manifest, sri, moduleExportsByRouteId, context) =>
|
|
1004
|
-
stageLatestManifests(
|
|
1005
|
-
manifest,
|
|
1006
|
-
sri,
|
|
1007
|
-
moduleExportsByRouteId,
|
|
1008
|
-
context.compilation
|
|
1009
|
-
),
|
|
1010
|
-
}
|
|
1011
|
-
);
|
|
1105
|
+
if (modePlan.kind === 'rsc') {
|
|
1106
|
+
registerReactRouterRscRouteTransforms({
|
|
1107
|
+
api,
|
|
1108
|
+
isBuild,
|
|
1109
|
+
performanceProfiler,
|
|
1110
|
+
routeByFilePath,
|
|
1111
|
+
routeChunkCache,
|
|
1112
|
+
routeChunkConfig: modePlan.routeChunkConfig,
|
|
1113
|
+
});
|
|
1012
1114
|
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
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
|
+
}
|
|
1036
1175
|
},
|
|
1037
1176
|
});
|
|
1177
|
+
|
|
1178
|
+
export const pluginReactRouterRSC = (
|
|
1179
|
+
options: ReactRouterRSCPluginOptions = {}
|
|
1180
|
+
): RsbuildPlugin =>
|
|
1181
|
+
pluginReactRouter({
|
|
1182
|
+
...options,
|
|
1183
|
+
rsc: options.rsc ?? true,
|
|
1184
|
+
});
|