rsbuild-plugin-react-router 0.1.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/README.md +185 -204
  2. package/dist/451.js +1087 -0
  3. package/dist/bounded-cache.d.ts +1 -0
  4. package/dist/build-manifest.d.ts +1 -1
  5. package/dist/build-output-transforms.d.ts +30 -0
  6. package/dist/concurrency.d.ts +2 -0
  7. package/dist/config-imports.d.ts +3 -0
  8. package/dist/constants.d.ts +3 -0
  9. package/dist/dev-generation.d.ts +25 -0
  10. package/dist/dev-runtime-artifacts.d.ts +39 -0
  11. package/dist/dev-runtime-compilation.d.ts +32 -0
  12. package/dist/dev-runtime-controller.d.ts +14 -0
  13. package/dist/dev-runtime-session.d.ts +34 -0
  14. package/dist/dev-server.d.ts +11 -2
  15. package/dist/export-utils.d.ts +15 -7
  16. package/dist/index.cjs +3085 -1272
  17. package/dist/index.d.ts +4 -1
  18. package/dist/index.js +2039 -1299
  19. package/dist/lazy-compilation.d.ts +5 -0
  20. package/dist/manifest.d.ts +32 -9
  21. package/dist/modify-browser-manifest.d.ts +30 -13
  22. package/dist/parallel-route-transform-protocol.d.ts +25 -0
  23. package/dist/parallel-route-transform-worker.d.ts +1 -0
  24. package/dist/parallel-route-transform-worker.js +38 -0
  25. package/dist/parallel-route-transforms.d.ts +14 -0
  26. package/dist/performance.d.ts +26 -0
  27. package/dist/plugin-utils.d.ts +2 -12
  28. package/dist/prerender-build.d.ts +32 -0
  29. package/dist/prerender.d.ts +28 -2
  30. package/dist/react-router-config.d.ts +8 -1
  31. package/dist/route-artifacts.d.ts +33 -0
  32. package/dist/route-ast.d.ts +21 -0
  33. package/dist/route-chunks.d.ts +9 -1
  34. package/dist/route-component-transform.d.ts +5 -0
  35. package/dist/route-export-pruning.d.ts +6 -0
  36. package/dist/route-export-resolution.d.ts +5 -0
  37. package/dist/route-transform-tasks.d.ts +47 -0
  38. package/dist/route-watch.d.ts +27 -0
  39. package/dist/server-build-plan.d.ts +22 -0
  40. package/dist/server-utils.d.ts +3 -2
  41. package/dist/templates/entry.client.js +3 -3
  42. package/dist/templates/entry.server.cjs +11 -8
  43. package/dist/templates/entry.server.js +5 -5
  44. package/dist/typegen.d.ts +2 -0
  45. package/dist/types.d.ts +30 -12
  46. package/dist/virtual-modules.d.ts +2 -0
  47. package/dist/warnings/warn-on-client-source-maps.d.ts +1 -0
  48. package/dist/yuku.d.ts +15 -0
  49. package/package.json +26 -22
  50. package/src/bounded-cache.ts +18 -0
  51. package/src/build-manifest.ts +168 -0
  52. package/src/build-output-transforms.ts +273 -0
  53. package/src/concurrency.ts +34 -0
  54. package/src/config-imports.ts +45 -0
  55. package/src/constants.ts +91 -0
  56. package/src/dev-generation.ts +700 -0
  57. package/src/dev-runtime-artifacts.ts +207 -0
  58. package/src/dev-runtime-compilation.ts +92 -0
  59. package/src/dev-runtime-controller.ts +462 -0
  60. package/src/dev-runtime-session.ts +184 -0
  61. package/src/dev-server.ts +58 -0
  62. package/src/export-utils.ts +219 -0
  63. package/src/index.ts +1025 -0
  64. package/src/lazy-compilation.ts +94 -0
  65. package/src/manifest.ts +480 -0
  66. package/src/modify-browser-manifest.ts +245 -0
  67. package/src/parallel-route-transform-protocol.ts +35 -0
  68. package/src/parallel-route-transform-worker.ts +82 -0
  69. package/src/parallel-route-transforms.ts +332 -0
  70. package/src/performance.ts +254 -0
  71. package/src/plugin-utils.ts +82 -0
  72. package/src/prerender-build.ts +623 -0
  73. package/src/prerender.ts +367 -0
  74. package/src/react-router-config.ts +220 -0
  75. package/src/route-artifacts.ts +155 -0
  76. package/src/route-ast.ts +163 -0
  77. package/src/route-chunks.ts +857 -0
  78. package/src/route-component-transform.ts +314 -0
  79. package/src/route-config.ts +106 -0
  80. package/src/route-export-pruning.ts +668 -0
  81. package/src/route-export-resolution.ts +329 -0
  82. package/src/route-transform-tasks.ts +249 -0
  83. package/src/route-watch.ts +322 -0
  84. package/src/server-build-plan.ts +91 -0
  85. package/src/server-utils.ts +210 -0
  86. package/src/ssr-externals.ts +59 -0
  87. package/src/templates/context.ts +12 -0
  88. package/src/templates/entry.client.tsx +12 -0
  89. package/src/templates/entry.server.tsx +76 -0
  90. package/src/typegen.ts +49 -0
  91. package/src/types.ts +82 -0
  92. package/src/validation/validate-plugin-order.ts +76 -0
  93. package/src/virtual-modules.ts +30 -0
  94. package/src/warnings/warn-on-client-source-maps.ts +96 -0
  95. package/src/yuku.ts +67 -0
  96. package/dist/906.js +0 -1
  97. package/dist/946.js +0 -1
  98. package/dist/babel.d.ts +0 -8
  99. package/dist/rslib-runtime.js +0 -23
@@ -0,0 +1,329 @@
1
+ import { readFileSync, statSync, type Stats } from 'node:fs';
2
+ import { createRequire } from 'node:module';
3
+ import { dirname, relative, resolve } from 'pathe';
4
+ import { JS_EXTENSIONS, PLUGIN_NAME } from './constants.js';
5
+ import {
6
+ getExportNamesAndExportAll,
7
+ getRouteModuleAnalysis,
8
+ } from './export-utils.js';
9
+
10
+ const tryStat = (path: string): Stats | null =>
11
+ statSync(path, { throwIfNoEntry: false }) ?? null;
12
+
13
+ type PackageExportTarget =
14
+ | string
15
+ | PackageExportTarget[]
16
+ | { [condition: string]: PackageExportTarget | undefined }
17
+ | null;
18
+
19
+ type PackageJson = {
20
+ exports?: PackageExportTarget;
21
+ main?: string;
22
+ module?: string;
23
+ };
24
+
25
+ const PACKAGE_IMPORT_CONDITIONS = new Set(['import', 'node']);
26
+ const PACKAGE_RESOLUTION_NOT_APPLICABLE = Symbol(
27
+ 'package resolution not applicable'
28
+ );
29
+
30
+ const resolveIndexFile = (dirPath: string): string | null => {
31
+ for (const ext of JS_EXTENSIONS) {
32
+ const candidate = resolve(dirPath, `index${ext}`);
33
+ const stats = tryStat(candidate);
34
+ if (stats?.isFile()) {
35
+ return candidate;
36
+ }
37
+ }
38
+ return null;
39
+ };
40
+
41
+ const resolvePathWithExtensions = (basePath: string): string | null => {
42
+ const stats = tryStat(basePath);
43
+ if (stats?.isFile()) {
44
+ return basePath;
45
+ }
46
+ if (stats?.isDirectory()) {
47
+ return resolveIndexFile(basePath);
48
+ }
49
+
50
+ for (const ext of JS_EXTENSIONS) {
51
+ const candidate = `${basePath}${ext}`;
52
+ const candidateStats = tryStat(candidate);
53
+ if (candidateStats?.isFile()) {
54
+ return candidate;
55
+ }
56
+ }
57
+
58
+ return resolveIndexFile(basePath);
59
+ };
60
+
61
+ const parsePackageSpecifier = (
62
+ specifier: string
63
+ ): { packageName: string; packageSubpath: string } | null => {
64
+ if (
65
+ specifier.startsWith('.') ||
66
+ specifier.startsWith('/') ||
67
+ specifier.startsWith('#')
68
+ ) {
69
+ return null;
70
+ }
71
+
72
+ const parts = specifier.split('/');
73
+ const packageName = specifier.startsWith('@')
74
+ ? parts.slice(0, 2).join('/')
75
+ : parts[0];
76
+ const packagePathParts = specifier.startsWith('@')
77
+ ? parts.slice(2)
78
+ : parts.slice(1);
79
+
80
+ return {
81
+ packageName,
82
+ packageSubpath:
83
+ packagePathParts.length > 0 ? `./${packagePathParts.join('/')}` : '.',
84
+ };
85
+ };
86
+
87
+ const findPackageDirectory = (
88
+ importerPath: string,
89
+ packageName: string
90
+ ): string | null => {
91
+ let currentDirectory = dirname(importerPath);
92
+
93
+ while (true) {
94
+ const packageDirectory = resolve(
95
+ currentDirectory,
96
+ 'node_modules',
97
+ packageName
98
+ );
99
+ const packageJsonPath = resolve(packageDirectory, 'package.json');
100
+ if (tryStat(packageJsonPath)?.isFile()) {
101
+ return packageDirectory;
102
+ }
103
+
104
+ const parentDirectory = dirname(currentDirectory);
105
+ if (parentDirectory === currentDirectory) {
106
+ return null;
107
+ }
108
+ currentDirectory = parentDirectory;
109
+ }
110
+ };
111
+
112
+ const readPackageJson = (packageDirectory: string): PackageJson | null => {
113
+ try {
114
+ return JSON.parse(
115
+ readFileSync(resolve(packageDirectory, 'package.json'), 'utf8')
116
+ ) as PackageJson;
117
+ } catch {
118
+ return null;
119
+ }
120
+ };
121
+
122
+ const resolvePackageExportTarget = (
123
+ target: PackageExportTarget | undefined
124
+ ): string | null => {
125
+ if (!target) {
126
+ return null;
127
+ }
128
+
129
+ if (typeof target === 'string') {
130
+ return target;
131
+ }
132
+
133
+ if (Array.isArray(target)) {
134
+ for (const nestedTarget of target) {
135
+ const resolvedTarget = resolvePackageExportTarget(nestedTarget);
136
+ if (resolvedTarget) {
137
+ return resolvedTarget;
138
+ }
139
+ }
140
+ return null;
141
+ }
142
+
143
+ for (const [condition, nestedTarget] of Object.entries(target)) {
144
+ if (condition === 'default' || PACKAGE_IMPORT_CONDITIONS.has(condition)) {
145
+ const resolvedTarget = resolvePackageExportTarget(nestedTarget);
146
+ if (resolvedTarget) {
147
+ return resolvedTarget;
148
+ }
149
+ }
150
+ }
151
+
152
+ return null;
153
+ };
154
+
155
+ const resolvePackageExports = (
156
+ packageDirectory: string,
157
+ packageSubpath: string,
158
+ packageJson: PackageJson
159
+ ): string | null => {
160
+ const exports = packageJson.exports;
161
+ if (!exports) {
162
+ const entry = packageJson.module ?? packageJson.main;
163
+ return entry
164
+ ? resolvePathWithExtensions(resolve(packageDirectory, entry))
165
+ : null;
166
+ }
167
+
168
+ const target =
169
+ typeof exports === 'object' &&
170
+ !Array.isArray(exports) &&
171
+ Object.keys(exports).some(key => key.startsWith('.'))
172
+ ? exports[packageSubpath]
173
+ : packageSubpath === '.'
174
+ ? exports
175
+ : undefined;
176
+
177
+ const resolvedTarget = resolvePackageExportTarget(target);
178
+ if (!resolvedTarget || !resolvedTarget.startsWith('./')) {
179
+ return null;
180
+ }
181
+
182
+ return resolvePathWithExtensions(resolve(packageDirectory, resolvedTarget));
183
+ };
184
+
185
+ const resolvePackageImport = (
186
+ specifier: string,
187
+ importerPath: string
188
+ ): string | null | typeof PACKAGE_RESOLUTION_NOT_APPLICABLE => {
189
+ const parsedSpecifier = parsePackageSpecifier(specifier);
190
+ if (!parsedSpecifier) {
191
+ return PACKAGE_RESOLUTION_NOT_APPLICABLE;
192
+ }
193
+
194
+ const packageDirectory = findPackageDirectory(
195
+ importerPath,
196
+ parsedSpecifier.packageName
197
+ );
198
+ if (!packageDirectory) {
199
+ return PACKAGE_RESOLUTION_NOT_APPLICABLE;
200
+ }
201
+
202
+ const packageJson = readPackageJson(packageDirectory);
203
+ if (!packageJson) {
204
+ return PACKAGE_RESOLUTION_NOT_APPLICABLE;
205
+ }
206
+
207
+ if (
208
+ packageJson.exports === undefined &&
209
+ !packageJson.module &&
210
+ !packageJson.main
211
+ ) {
212
+ return PACKAGE_RESOLUTION_NOT_APPLICABLE;
213
+ }
214
+
215
+ return resolvePackageExports(
216
+ packageDirectory,
217
+ parsedSpecifier.packageSubpath,
218
+ packageJson
219
+ );
220
+ };
221
+
222
+ const resolveExportAllModule = (
223
+ specifier: string,
224
+ importerPath: string
225
+ ): string | null => {
226
+ if (specifier.startsWith('.') || specifier.startsWith('/')) {
227
+ const basePath = specifier.startsWith('/')
228
+ ? specifier
229
+ : resolve(dirname(importerPath), specifier);
230
+ const resolvedPath = resolvePathWithExtensions(basePath);
231
+ if (resolvedPath) {
232
+ return resolvedPath;
233
+ }
234
+ }
235
+
236
+ const importResolvedPath = resolvePackageImport(specifier, importerPath);
237
+ if (importResolvedPath !== PACKAGE_RESOLUTION_NOT_APPLICABLE) {
238
+ return importResolvedPath;
239
+ }
240
+
241
+ try {
242
+ return createRequire(importerPath).resolve(specifier);
243
+ } catch {
244
+ return null;
245
+ }
246
+ };
247
+
248
+ export type RouteExportResolver = (
249
+ specifier: string,
250
+ importerPath: string
251
+ ) => Promise<string | null> | string | null;
252
+
253
+ export type RouteModuleResolveCallback = (
254
+ error: Error | null,
255
+ resolved?: string | false
256
+ ) => void;
257
+
258
+ export type RouteModuleResolver = (
259
+ context: string,
260
+ specifier: string,
261
+ callback: RouteModuleResolveCallback
262
+ ) => void;
263
+
264
+ export const createBundlerRouteExportResolver =
265
+ (resolveModule: RouteModuleResolver): RouteExportResolver =>
266
+ (specifier, importerPath) =>
267
+ new Promise<string | null>(resolveResolvedPath => {
268
+ resolveModule(dirname(importerPath), specifier, (error, resolved) => {
269
+ resolveResolvedPath(error || !resolved ? null : resolved);
270
+ });
271
+ });
272
+
273
+ export const collectClientOnlyStubExportNames = async (
274
+ code: string,
275
+ resourcePath: string,
276
+ resolveModule: RouteExportResolver = resolveExportAllModule
277
+ ): Promise<Set<string>> => {
278
+ const { exportNames: directExportNames, exportAllModules } =
279
+ await getExportNamesAndExportAll(code);
280
+ const exportNames = new Set(directExportNames);
281
+ const unresolvedExportAll = new Set<string>();
282
+ const visitedModules = new Set<string>();
283
+
284
+ const collectExportNamesFromModule = async (
285
+ modulePath: string
286
+ ): Promise<void> => {
287
+ if (visitedModules.has(modulePath)) {
288
+ return;
289
+ }
290
+ visitedModules.add(modulePath);
291
+ const { exports: moduleExportNames, exportAllModules: moduleExportAll } =
292
+ await getRouteModuleAnalysis(modulePath);
293
+ for (const name of moduleExportNames) {
294
+ if (name !== 'default') {
295
+ exportNames.add(name);
296
+ }
297
+ }
298
+ for (const nestedSpecifier of moduleExportAll) {
299
+ const nestedPath = await resolveModule(nestedSpecifier, modulePath);
300
+ if (!nestedPath) {
301
+ unresolvedExportAll.add(nestedSpecifier);
302
+ continue;
303
+ }
304
+ await collectExportNamesFromModule(nestedPath);
305
+ }
306
+ };
307
+
308
+ for (const specifier of exportAllModules) {
309
+ const resolvedPath = await resolveModule(specifier, resourcePath);
310
+ if (!resolvedPath) {
311
+ unresolvedExportAll.add(specifier);
312
+ continue;
313
+ }
314
+ await collectExportNamesFromModule(resolvedPath);
315
+ }
316
+
317
+ if (unresolvedExportAll.size > 0) {
318
+ throw new Error(
319
+ `[${PLUGIN_NAME}] Client-only module uses \`export * from\` with ` +
320
+ `unresolvable specifier(s): ${Array.from(unresolvedExportAll)
321
+ .map(spec => `\`${spec}\``)
322
+ .join(', ')}. ` +
323
+ `Please explicitly re-export named bindings in ` +
324
+ `\`${relative(process.cwd(), resourcePath)}\`.`
325
+ );
326
+ }
327
+
328
+ return exportNames;
329
+ };
@@ -0,0 +1,249 @@
1
+ import { basename as pathBasename, relative } from 'pathe';
2
+ import { generate, parse } from './yuku.js';
3
+ import {
4
+ SERVER_ONLY_ROUTE_EXPORTS,
5
+ SERVER_ONLY_ROUTE_EXPORTS_SET,
6
+ } from './constants.js';
7
+ import { collectProgramExportNames } from './export-utils.js';
8
+ import {
9
+ removeExports,
10
+ removeUnusedImports,
11
+ transformRoute,
12
+ } from './plugin-utils.js';
13
+ import {
14
+ collectClientOnlyStubExportNames,
15
+ type RouteExportResolver,
16
+ } from './route-export-resolution.js';
17
+ import {
18
+ createRouteChunkArtifact,
19
+ createRouteClientEntryArtifact,
20
+ } from './route-artifacts.js';
21
+ import {
22
+ detectRouteChunksIfEnabled,
23
+ getRouteChunkModuleId,
24
+ type RouteChunkCache,
25
+ type RouteChunkConfig,
26
+ } from './route-chunks.js';
27
+ import { getProgram } from './route-ast.js';
28
+
29
+ export type RouteTransformResult = {
30
+ code: string;
31
+ map?: ReturnType<typeof generate>['map'];
32
+ };
33
+
34
+ type BaseRouteTransformTask = {
35
+ code: string;
36
+ resourcePath: string;
37
+ };
38
+
39
+ export type RouteClientEntryTransformTask = BaseRouteTransformTask & {
40
+ kind: 'routeClientEntry';
41
+ environmentName?: string;
42
+ isBuild: boolean;
43
+ routeChunkConfig: RouteChunkConfig;
44
+ };
45
+
46
+ export type RouteChunkTransformTask = BaseRouteTransformTask & {
47
+ kind: 'routeChunk';
48
+ resource: string;
49
+ isBuild: boolean;
50
+ routeChunkConfig: RouteChunkConfig;
51
+ };
52
+
53
+ export type SplitRouteExportsTransformTask = BaseRouteTransformTask & {
54
+ kind: 'splitRouteExports';
55
+ routeChunkConfig: RouteChunkConfig;
56
+ };
57
+
58
+ export type ClientOnlyStubTransformTask = BaseRouteTransformTask & {
59
+ kind: 'clientOnlyStub';
60
+ resolveExportAllModule?: RouteExportResolver;
61
+ };
62
+
63
+ export type RouteModuleTransformTask = BaseRouteTransformTask & {
64
+ kind: 'routeModule';
65
+ resource: string;
66
+ environmentName: string;
67
+ sourceMaps: boolean;
68
+ ssr: boolean;
69
+ isBuild: boolean;
70
+ isSpaMode: boolean;
71
+ rootRoutePath: string | null;
72
+ };
73
+
74
+ export type RouteTransformTask =
75
+ | RouteClientEntryTransformTask
76
+ | RouteChunkTransformTask
77
+ | SplitRouteExportsTransformTask
78
+ | ClientOnlyStubTransformTask
79
+ | RouteModuleTransformTask;
80
+
81
+ export type RouteTransformTaskOptions = {
82
+ routeChunkCache?: RouteChunkCache;
83
+ };
84
+
85
+ const defaultRouteChunkCache: RouteChunkCache = new Map();
86
+
87
+ const getRouteChunkCache = (options?: RouteTransformTaskOptions) =>
88
+ options?.routeChunkCache ?? defaultRouteChunkCache;
89
+
90
+ const splitRouteExports = async (
91
+ task: SplitRouteExportsTransformTask,
92
+ options?: RouteTransformTaskOptions
93
+ ): Promise<RouteTransformResult> => {
94
+ const { exportNames, hasRouteChunks, chunkedExports } =
95
+ await detectRouteChunksIfEnabled(
96
+ getRouteChunkCache(options),
97
+ task.routeChunkConfig,
98
+ task.resourcePath,
99
+ task.code
100
+ );
101
+ if (!hasRouteChunks) {
102
+ return { code: task.code, map: null };
103
+ }
104
+
105
+ const chunkedExportSet = new Set<string>(chunkedExports);
106
+ const mainChunkReexports = exportNames
107
+ .filter(name => !chunkedExportSet.has(name))
108
+ .join(', ');
109
+ const chunkBasePath = `./${pathBasename(task.resourcePath)}`;
110
+
111
+ return {
112
+ code: [
113
+ mainChunkReexports
114
+ ? `export { ${mainChunkReexports} } from "${getRouteChunkModuleId(
115
+ chunkBasePath,
116
+ 'main'
117
+ )}";`
118
+ : null,
119
+ ...chunkedExports.map(
120
+ exportName =>
121
+ `export { ${exportName} } from "${getRouteChunkModuleId(
122
+ chunkBasePath,
123
+ exportName
124
+ )}";`
125
+ ),
126
+ ]
127
+ .filter(Boolean)
128
+ .join('\n'),
129
+ map: null,
130
+ };
131
+ };
132
+
133
+ const createClientOnlyStub = async (
134
+ task: ClientOnlyStubTransformTask
135
+ ): Promise<RouteTransformResult> => {
136
+ const exportNames = await collectClientOnlyStubExportNames(
137
+ task.code,
138
+ task.resourcePath,
139
+ task.resolveExportAllModule
140
+ );
141
+
142
+ return {
143
+ code: Array.from(exportNames)
144
+ .map(name =>
145
+ name === 'default'
146
+ ? 'export default undefined;'
147
+ : `export const ${name} = undefined;`
148
+ )
149
+ .join('\n'),
150
+ map: null,
151
+ };
152
+ };
153
+
154
+ const transformRouteModule = async (
155
+ task: RouteModuleTransformTask
156
+ ): Promise<RouteTransformResult> => {
157
+ let code = task.code;
158
+
159
+ const defaultExportMatch = code.match(/\n\s{0,}([\w\d_]+)\sas default,?/);
160
+ if (defaultExportMatch && typeof defaultExportMatch.index === 'number') {
161
+ code =
162
+ code.slice(0, defaultExportMatch.index) +
163
+ code.slice(defaultExportMatch.index + defaultExportMatch[0].length);
164
+ code += `\nexport default ${defaultExportMatch[1]};`;
165
+ }
166
+
167
+ const ast = parse(code, { sourceType: 'module' });
168
+ if (task.environmentName === 'web' && !task.ssr && task.isSpaMode) {
169
+ const resolvedExportNames = collectProgramExportNames(getProgram(ast));
170
+ const isRootRoute = task.resourcePath === task.rootRoutePath;
171
+ const relativePath = relative(process.cwd(), task.resourcePath);
172
+
173
+ const invalidServerOnly = resolvedExportNames.filter(exp => {
174
+ if (isRootRoute && exp === 'loader') return false;
175
+ return SERVER_ONLY_ROUTE_EXPORTS_SET.has(exp);
176
+ });
177
+
178
+ if (invalidServerOnly.length > 0) {
179
+ const list = invalidServerOnly.map(e => `\`${e}\``).join(', ');
180
+ throw new Error(
181
+ `SPA Mode: ${invalidServerOnly.length} invalid route export(s) in ` +
182
+ `\`${relativePath}\`: ${list}. ` +
183
+ `See https://reactrouter.com/how-to/spa for more information.`
184
+ );
185
+ }
186
+
187
+ if (!isRootRoute && resolvedExportNames.includes('HydrateFallback')) {
188
+ throw new Error(
189
+ `SPA Mode: Invalid \`HydrateFallback\` export found in ` +
190
+ `\`${relativePath}\`. ` +
191
+ `\`HydrateFallback\` is only permitted on the root route in SPA Mode. ` +
192
+ `See https://reactrouter.com/how-to/spa for more information.`
193
+ );
194
+ }
195
+ }
196
+
197
+ const removedServerOnlyExports =
198
+ task.environmentName === 'web'
199
+ ? removeExports(
200
+ ast,
201
+ SERVER_ONLY_ROUTE_EXPORTS,
202
+ SERVER_ONLY_ROUTE_EXPORTS_SET
203
+ )
204
+ : false;
205
+ transformRoute(ast);
206
+ if (removedServerOnlyExports) {
207
+ removeUnusedImports(ast);
208
+ }
209
+
210
+ return generate(ast, {
211
+ // Rsbuild merges this map with its downstream SWC transform. Only pay the
212
+ // code-generation cost when this environment actually emits JS maps.
213
+ sourceMaps: task.sourceMaps,
214
+ filename: task.resource,
215
+ sourceFileName: task.resourcePath,
216
+ });
217
+ };
218
+
219
+ export const executeRouteTransformTask = async (
220
+ task: RouteTransformTask,
221
+ options?: RouteTransformTaskOptions
222
+ ): Promise<RouteTransformResult> => {
223
+ switch (task.kind) {
224
+ case 'routeClientEntry':
225
+ return createRouteClientEntryArtifact({
226
+ code: task.code,
227
+ resourcePath: task.resourcePath,
228
+ environmentName: task.environmentName,
229
+ isBuild: task.isBuild,
230
+ routeChunkCache: getRouteChunkCache(options),
231
+ routeChunkConfig: task.routeChunkConfig,
232
+ });
233
+ case 'routeChunk':
234
+ return createRouteChunkArtifact({
235
+ code: task.code,
236
+ resource: task.resource,
237
+ resourcePath: task.resourcePath,
238
+ isBuild: task.isBuild,
239
+ routeChunkCache: getRouteChunkCache(options),
240
+ routeChunkConfig: task.routeChunkConfig,
241
+ });
242
+ case 'splitRouteExports':
243
+ return splitRouteExports(task, options);
244
+ case 'clientOnlyStub':
245
+ return createClientOnlyStub(task);
246
+ case 'routeModule':
247
+ return transformRouteModule(task);
248
+ }
249
+ };