rsbuild-plugin-react-router 0.2.0 → 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 (96) 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 +3050 -1244
  17. package/dist/index.d.ts +4 -1
  18. package/dist/index.js +2015 -1279
  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.server.cjs +3 -3
  42. package/dist/templates/entry.server.js +3 -3
  43. package/dist/typegen.d.ts +2 -0
  44. package/dist/types.d.ts +30 -12
  45. package/dist/virtual-modules.d.ts +2 -0
  46. package/dist/warnings/warn-on-client-source-maps.d.ts +1 -0
  47. package/dist/yuku.d.ts +15 -0
  48. package/package.json +22 -19
  49. package/src/bounded-cache.ts +18 -0
  50. package/src/build-manifest.ts +168 -0
  51. package/src/build-output-transforms.ts +273 -0
  52. package/src/concurrency.ts +34 -0
  53. package/src/config-imports.ts +45 -0
  54. package/src/constants.ts +91 -0
  55. package/src/dev-generation.ts +700 -0
  56. package/src/dev-runtime-artifacts.ts +207 -0
  57. package/src/dev-runtime-compilation.ts +92 -0
  58. package/src/dev-runtime-controller.ts +462 -0
  59. package/src/dev-runtime-session.ts +184 -0
  60. package/src/dev-server.ts +58 -0
  61. package/src/export-utils.ts +219 -0
  62. package/src/index.ts +1025 -0
  63. package/src/lazy-compilation.ts +94 -0
  64. package/src/manifest.ts +480 -0
  65. package/src/modify-browser-manifest.ts +245 -0
  66. package/src/parallel-route-transform-protocol.ts +35 -0
  67. package/src/parallel-route-transform-worker.ts +82 -0
  68. package/src/parallel-route-transforms.ts +332 -0
  69. package/src/performance.ts +254 -0
  70. package/src/plugin-utils.ts +82 -0
  71. package/src/prerender-build.ts +623 -0
  72. package/src/prerender.ts +367 -0
  73. package/src/react-router-config.ts +220 -0
  74. package/src/route-artifacts.ts +155 -0
  75. package/src/route-ast.ts +163 -0
  76. package/src/route-chunks.ts +857 -0
  77. package/src/route-component-transform.ts +314 -0
  78. package/src/route-config.ts +106 -0
  79. package/src/route-export-pruning.ts +668 -0
  80. package/src/route-export-resolution.ts +329 -0
  81. package/src/route-transform-tasks.ts +249 -0
  82. package/src/route-watch.ts +322 -0
  83. package/src/server-build-plan.ts +91 -0
  84. package/src/server-utils.ts +210 -0
  85. package/src/ssr-externals.ts +59 -0
  86. package/src/templates/context.ts +12 -0
  87. package/src/templates/entry.client.tsx +12 -0
  88. package/src/templates/entry.server.tsx +76 -0
  89. package/src/typegen.ts +49 -0
  90. package/src/types.ts +82 -0
  91. package/src/validation/validate-plugin-order.ts +76 -0
  92. package/src/virtual-modules.ts +30 -0
  93. package/src/warnings/warn-on-client-source-maps.ts +96 -0
  94. package/src/yuku.ts +67 -0
  95. package/dist/0~rslib-runtime.js +0 -16
  96. package/dist/babel.d.ts +0 -8
@@ -0,0 +1,94 @@
1
+ import { BUILD_CLIENT_ROUTE_QUERY_STRING } from './constants.js';
2
+ import type { PluginOptions } from './types.js';
3
+
4
+ type LazyCompilationOptions = Exclude<
5
+ NonNullable<PluginOptions['lazyCompilation']>,
6
+ boolean
7
+ >;
8
+
9
+ type LazyCompilationModule = {
10
+ request?: string;
11
+ userRequest?: string;
12
+ rawRequest?: string;
13
+ resource?: string;
14
+ identifier?: () => string;
15
+ nameForCondition?: () => string | null;
16
+ };
17
+
18
+ const normalizeSlashes = (value: string): string => value.replace(/\\/g, '/');
19
+
20
+ const getLazyCompilationModuleValues = (
21
+ module: LazyCompilationModule
22
+ ): string[] =>
23
+ [
24
+ module.request,
25
+ module.userRequest,
26
+ module.rawRequest,
27
+ module.resource,
28
+ module.identifier?.(),
29
+ module.nameForCondition?.(),
30
+ ].filter((value): value is string => Boolean(value));
31
+
32
+ const matchesLazyCompilationTest = (
33
+ test: LazyCompilationOptions['test'] | undefined,
34
+ module: LazyCompilationModule
35
+ ): boolean => {
36
+ if (!test) {
37
+ return true;
38
+ }
39
+ if (typeof test === 'function') {
40
+ return test(module as Parameters<typeof test>[0]);
41
+ }
42
+ const conditionName = module.nameForCondition?.();
43
+ if (!conditionName) {
44
+ return false;
45
+ }
46
+ test.lastIndex = 0;
47
+ return test.test(conditionName);
48
+ };
49
+
50
+ const createReactRouterHydrationModuleTest = (entryClientPath: string) => {
51
+ const eagerPatterns = [
52
+ normalizeSlashes(entryClientPath),
53
+ 'virtual/react-router/browser-manifest',
54
+ BUILD_CLIENT_ROUTE_QUERY_STRING,
55
+ '?react-router-route',
56
+ ];
57
+
58
+ return (module: LazyCompilationModule): boolean =>
59
+ getLazyCompilationModuleValues(module).some(value => {
60
+ const normalizedValue = normalizeSlashes(value);
61
+ return eagerPatterns.some(pattern => normalizedValue.includes(pattern));
62
+ });
63
+ };
64
+
65
+ export const guardReactRouterLazyCompilation = ({
66
+ lazyCompilation,
67
+ entryClientPath,
68
+ }: {
69
+ lazyCompilation: PluginOptions['lazyCompilation'] | undefined;
70
+ entryClientPath: string;
71
+ }): PluginOptions['lazyCompilation'] | undefined => {
72
+ if (lazyCompilation === undefined || lazyCompilation === false) {
73
+ return lazyCompilation;
74
+ }
75
+
76
+ const options: LazyCompilationOptions =
77
+ lazyCompilation === true
78
+ ? { entries: true, imports: true }
79
+ : lazyCompilation;
80
+ const userTest = options.test;
81
+ const isReactRouterHydrationModule =
82
+ createReactRouterHydrationModuleTest(entryClientPath);
83
+
84
+ return {
85
+ ...options,
86
+ test(module) {
87
+ const lazyModule = module as LazyCompilationModule;
88
+ if (isReactRouterHydrationModule(lazyModule)) {
89
+ return false;
90
+ }
91
+ return matchesLazyCompilationTest(userTest, lazyModule);
92
+ },
93
+ };
94
+ };
@@ -0,0 +1,480 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { dirname, isAbsolute, relative, resolve } from 'pathe';
3
+ import type { Route, PluginOptions, RouteManifestItem } from './types.js';
4
+ import type { RouteConfigEntry } from '@react-router/dev/routes';
5
+ import { combineURLs, createRouteId } from './plugin-utils.js';
6
+ import { SERVER_EXPORTS, CLIENT_EXPORTS } from './constants.js';
7
+ import {
8
+ buildManifestChunkValidity,
9
+ createEmptyRouteChunkByExportName,
10
+ detectRouteChunksIfEnabled,
11
+ getRouteChunkEntryName,
12
+ routeChunkExportNames,
13
+ validateRouteChunks,
14
+ type RouteChunkCache,
15
+ type RouteChunkConfig,
16
+ } from './route-chunks.js';
17
+ import { getRouteModuleAnalysis } from './export-utils.js';
18
+ import { getDefaultConcurrency, mapWithConcurrency } from './concurrency.js';
19
+
20
+ const ROUTE_ANALYSIS_CONCURRENCY = Math.max(
21
+ 1,
22
+ Math.min(16, getDefaultConcurrency() || 1)
23
+ );
24
+
25
+ export function configRoutesToRouteManifest(
26
+ appDirectory: string,
27
+ routes: RouteConfigEntry[],
28
+ rootId = 'root'
29
+ ): Record<string, Route> {
30
+ return Object.fromEntries(
31
+ configRoutesToRouteManifestEntries(appDirectory, routes, rootId)
32
+ );
33
+ }
34
+
35
+ export function configRoutesToRouteManifestEntries(
36
+ appDirectory: string,
37
+ routes: RouteConfigEntry[],
38
+ rootId = 'root'
39
+ ): Array<[string, Route]> {
40
+ const routeManifestEntries: Array<[string, Route]> = [];
41
+ const routeIds = new Set<string>();
42
+
43
+ function walk(route: RouteConfigEntry, parentId: string) {
44
+ const id = route.id || createRouteId(route.file);
45
+ const manifestItem = {
46
+ id,
47
+ parentId,
48
+ file: isAbsolute(route.file)
49
+ ? relative(appDirectory, route.file)
50
+ : route.file,
51
+ path: route.path,
52
+ index: route.index,
53
+ caseSensitive: route.caseSensitive,
54
+ };
55
+
56
+ if (routeIds.has(id)) {
57
+ throw new Error(
58
+ `Unable to define routes with duplicate route id: "${id}"`
59
+ );
60
+ }
61
+ routeIds.add(id);
62
+ routeManifestEntries.push([id, manifestItem]);
63
+
64
+ if (route.children) {
65
+ for (const child of route.children) {
66
+ walk(child, id);
67
+ }
68
+ }
69
+ }
70
+
71
+ for (const route of routes) {
72
+ walk(route, rootId);
73
+ }
74
+
75
+ return routeManifestEntries;
76
+ }
77
+
78
+ type RouteChunkManifestOptions = {
79
+ splitRouteModules?: boolean | 'enforce';
80
+ rootRouteFile?: string;
81
+ isBuild?: boolean;
82
+ cache?: RouteChunkCache;
83
+ };
84
+
85
+ export type ReactRouterManifestForDev = {
86
+ version: string;
87
+ url: string;
88
+ hmr?: {
89
+ runtime: string;
90
+ };
91
+ entry: {
92
+ module: string;
93
+ imports: string[];
94
+ css: string[];
95
+ };
96
+ sri?: Record<string, string> | true;
97
+ routes: Record<string, RouteManifestItem>;
98
+ };
99
+
100
+ export type ReactRouterManifestStats = {
101
+ assetsByChunkName?: Record<string, string[]>;
102
+ entrypointFilesByName?: Record<string, string[]>;
103
+ };
104
+
105
+ type ReactRouterManifestStatsChunk = {
106
+ files?: Iterable<string>;
107
+ };
108
+
109
+ type ReactRouterManifestStatsEntrypoint = {
110
+ getFiles?: () => Iterable<string>;
111
+ };
112
+
113
+ type ReactRouterManifestStatsCompilation = {
114
+ namedChunks: Iterable<[string, ReactRouterManifestStatsChunk]>;
115
+ entrypoints?: Iterable<[string, ReactRouterManifestStatsEntrypoint]>;
116
+ };
117
+
118
+ type ReactRouterManifestStatsNamedChunks =
119
+ ReactRouterManifestStatsCompilation['namedChunks'] & {
120
+ get?: (chunkName: string) => ReactRouterManifestStatsChunk | undefined;
121
+ };
122
+
123
+ type ReactRouterManifestStatsEntrypoints = NonNullable<
124
+ ReactRouterManifestStatsCompilation['entrypoints']
125
+ > & {
126
+ get?: (
127
+ entrypointName: string
128
+ ) => ReactRouterManifestStatsEntrypoint | undefined;
129
+ };
130
+
131
+ const orderChunkFiles = (chunkName: string, files: string[]): string[] => {
132
+ const ownChunkAsset = `${chunkName}.js`;
133
+ const ownFileIndex = files.findIndex(file => file.endsWith(ownChunkAsset));
134
+ if (ownFileIndex <= 0) {
135
+ return files;
136
+ }
137
+
138
+ return [
139
+ files[ownFileIndex],
140
+ ...files.slice(0, ownFileIndex),
141
+ ...files.slice(ownFileIndex + 1),
142
+ ];
143
+ };
144
+
145
+ export const createReactRouterManifestStats = (
146
+ compilation: ReactRouterManifestStatsCompilation | undefined,
147
+ chunkNames?: ReadonlySet<string>
148
+ ): ReactRouterManifestStats | undefined => {
149
+ if (!compilation) {
150
+ return undefined;
151
+ }
152
+
153
+ const assetsByChunkName: Record<string, string[]> = {};
154
+ const entrypointFilesByName: Record<string, string[]> = {};
155
+ const namedChunks =
156
+ compilation.namedChunks as ReactRouterManifestStatsNamedChunks;
157
+ const entrypoints = compilation.entrypoints as
158
+ | ReactRouterManifestStatsEntrypoints
159
+ | undefined;
160
+
161
+ if (chunkNames && typeof namedChunks.get === 'function') {
162
+ for (const chunkName of chunkNames) {
163
+ const chunk = namedChunks.get(chunkName);
164
+ if (!chunk) {
165
+ continue;
166
+ }
167
+ const files = Array.from(chunk.files ?? []);
168
+ assetsByChunkName[chunkName] = orderChunkFiles(chunkName, files);
169
+ }
170
+ } else {
171
+ for (const [chunkName, chunk] of namedChunks) {
172
+ if (chunkNames && !chunkNames.has(chunkName)) {
173
+ continue;
174
+ }
175
+ const files = Array.from(chunk.files ?? []);
176
+ assetsByChunkName[chunkName] = orderChunkFiles(chunkName, files);
177
+ }
178
+ }
179
+
180
+ if (entrypoints) {
181
+ if (chunkNames && typeof entrypoints.get === 'function') {
182
+ for (const entrypointName of chunkNames) {
183
+ const entrypoint = entrypoints.get(entrypointName);
184
+ if (!entrypoint) {
185
+ continue;
186
+ }
187
+ entrypointFilesByName[entrypointName] = Array.from(
188
+ entrypoint.getFiles?.() ?? []
189
+ );
190
+ }
191
+ } else {
192
+ for (const [entrypointName, entrypoint] of entrypoints) {
193
+ if (chunkNames && !chunkNames.has(entrypointName)) {
194
+ continue;
195
+ }
196
+ entrypointFilesByName[entrypointName] = Array.from(
197
+ entrypoint.getFiles?.() ?? []
198
+ );
199
+ }
200
+ }
201
+ }
202
+
203
+ return Object.keys(entrypointFilesByName).length > 0
204
+ ? { assetsByChunkName, entrypointFilesByName }
205
+ : { assetsByChunkName };
206
+ };
207
+
208
+ export type RouteManifestModuleExports = Record<string, readonly string[]>;
209
+
210
+ export type ReactRouterManifestGenerationResult = {
211
+ manifest: ReactRouterManifestForDev;
212
+ moduleExportsByRouteId: RouteManifestModuleExports;
213
+ };
214
+
215
+ const DEFAULT_MANIFEST_DIR = 'static/js';
216
+
217
+ const getManifestDirFromEntryAsset = (entryModulePath?: string): string => {
218
+ if (!entryModulePath) {
219
+ return DEFAULT_MANIFEST_DIR;
220
+ }
221
+ const dir = dirname(entryModulePath);
222
+ return dir === '.' ? DEFAULT_MANIFEST_DIR : dir;
223
+ };
224
+
225
+ export const getReactRouterManifestPath = ({
226
+ version,
227
+ isBuild,
228
+ entryModulePath,
229
+ }: {
230
+ version: string;
231
+ isBuild: boolean;
232
+ entryModulePath?: string;
233
+ }): string => {
234
+ if (!isBuild) {
235
+ return 'static/js/virtual/react-router/browser-manifest.js';
236
+ }
237
+ const dir = getManifestDirFromEntryAsset(entryModulePath);
238
+ return `${dir}/manifest-${version}.js`;
239
+ };
240
+
241
+ const getManifestVersion = (
242
+ fingerprintedValues: { entry: unknown; routes: unknown },
243
+ isBuild: boolean
244
+ ): string => {
245
+ if (!isBuild) {
246
+ return String(Math.random());
247
+ }
248
+ return createHash('md5')
249
+ .update(JSON.stringify(fingerprintedValues))
250
+ .digest('hex')
251
+ .slice(0, 8);
252
+ };
253
+
254
+ const getRouteEntryName = (route: Route): string => {
255
+ const extensionIndex = route.file.lastIndexOf('.');
256
+ return extensionIndex >= 0 ? route.file.slice(0, extensionIndex) : route.file;
257
+ };
258
+
259
+ export const getReactRouterManifestChunkNames = (
260
+ routes: Record<string, Route>,
261
+ splitRouteModules: boolean | 'enforce' = false
262
+ ): Set<string> => {
263
+ const chunkNames = new Set<string>(['entry.client']);
264
+ for (const route of Object.values(routes)) {
265
+ chunkNames.add(getRouteEntryName(route));
266
+ if (!splitRouteModules || route.id === 'root') {
267
+ continue;
268
+ }
269
+ for (const exportName of routeChunkExportNames) {
270
+ chunkNames.add(getRouteChunkEntryName(route.id, exportName));
271
+ }
272
+ }
273
+ return chunkNames;
274
+ };
275
+
276
+ export async function generateReactRouterManifestForDev(
277
+ routes: Record<string, Route>,
278
+ _options: PluginOptions,
279
+ clientStats: ReactRouterManifestStats | undefined,
280
+ context: string,
281
+ assetPrefix = '/',
282
+ routeChunkOptions?: RouteChunkManifestOptions
283
+ ): Promise<ReactRouterManifestGenerationResult> {
284
+ const result: Record<string, RouteManifestItem> = {};
285
+ const splitRouteModules = routeChunkOptions?.splitRouteModules ?? false;
286
+ const enforceSplitRouteModules = splitRouteModules === 'enforce';
287
+ const isBuild = routeChunkOptions?.isBuild ?? false;
288
+ const routeChunkConfig: RouteChunkConfig | null =
289
+ splitRouteModules && routeChunkOptions?.rootRouteFile
290
+ ? {
291
+ splitRouteModules,
292
+ appDirectory: context,
293
+ rootRouteFile: routeChunkOptions.rootRouteFile,
294
+ }
295
+ : null;
296
+
297
+ const getAssetsForChunk = (chunkName: string): string[] => {
298
+ const assets = clientStats?.assetsByChunkName?.[chunkName];
299
+ if (!assets) {
300
+ return [`${DEFAULT_MANIFEST_DIR}/${chunkName}.js`];
301
+ }
302
+ const entrypointCssAssets =
303
+ clientStats?.entrypointFilesByName?.[chunkName]?.filter(asset =>
304
+ asset.endsWith('.css')
305
+ ) ?? [];
306
+ const cssAssets = [
307
+ ...assets.filter(asset => asset.endsWith('.css')),
308
+ ...entrypointCssAssets,
309
+ ].filter((asset, index, all) => all.indexOf(asset) === index);
310
+ const nonCssAssets = assets.filter(asset => !asset.endsWith('.css'));
311
+
312
+ if (!nonCssAssets.some(asset => asset.endsWith('.js'))) {
313
+ return [
314
+ `${DEFAULT_MANIFEST_DIR}/${chunkName}.js`,
315
+ ...nonCssAssets,
316
+ ...cssAssets,
317
+ ];
318
+ }
319
+ return [...nonCssAssets, ...cssAssets];
320
+ };
321
+
322
+ const getModulePathForChunk = (chunkName: string): string | undefined => {
323
+ const assets = getAssetsForChunk(chunkName);
324
+ const jsAssets = assets.filter(asset => asset.endsWith('.js'));
325
+ return jsAssets[0] ? combineURLs(assetPrefix, jsAssets[0]) : undefined;
326
+ };
327
+
328
+ const manifestEntries = await mapWithConcurrency(
329
+ Object.entries(routes),
330
+ ROUTE_ANALYSIS_CONCURRENCY,
331
+ async ([key, route]) => {
332
+ const routeEntryName = getRouteEntryName(route);
333
+ const assets = getAssetsForChunk(routeEntryName);
334
+ const jsAssets = assets.filter(asset => asset.endsWith('.js'));
335
+ let cssAssets = assets.filter(asset => asset.endsWith('.css'));
336
+ const routeFilePath = resolve(context, route.file);
337
+ let exports = new Set<string>();
338
+ let routeModuleExports: readonly string[] = [];
339
+ let hasRouteChunkByExportName: ReturnType<
340
+ typeof createEmptyRouteChunkByExportName
341
+ > | null = null;
342
+
343
+ try {
344
+ const { code, exports: exportNames } =
345
+ await getRouteModuleAnalysis(routeFilePath);
346
+ if (
347
+ !isBuild &&
348
+ cssAssets.length === 0 &&
349
+ /\.(?:css|less|sass|scss)(?:\?[^'"`]+)?['"`]/.test(code)
350
+ ) {
351
+ cssAssets = [
352
+ `${DEFAULT_MANIFEST_DIR.replace('/js', '/css')}/${routeEntryName}.css`,
353
+ ];
354
+ }
355
+ routeModuleExports = exportNames;
356
+ exports = new Set(exportNames);
357
+
358
+ if (isBuild && routeChunkConfig) {
359
+ const { hasRouteChunkByExportName: chunkInfo } =
360
+ await detectRouteChunksIfEnabled(
361
+ routeChunkOptions?.cache,
362
+ routeChunkConfig,
363
+ routeFilePath,
364
+ code
365
+ );
366
+ hasRouteChunkByExportName = chunkInfo;
367
+ }
368
+ } catch (error) {
369
+ if (isBuild) {
370
+ throw error;
371
+ }
372
+ console.error(`Failed to analyze route file ${routeFilePath}:`, error);
373
+ }
374
+
375
+ const hasClientAction = exports.has(CLIENT_EXPORTS.clientAction);
376
+ const hasClientLoader = exports.has(CLIENT_EXPORTS.clientLoader);
377
+ const hasClientMiddleware = exports.has(CLIENT_EXPORTS.clientMiddleware);
378
+ const hasDefaultExport = exports.has('default');
379
+ const routeChunkMap = hasRouteChunkByExportName;
380
+
381
+ if (isBuild && enforceSplitRouteModules && routeChunkConfig) {
382
+ validateRouteChunks({
383
+ config: routeChunkConfig,
384
+ id: routeFilePath,
385
+ valid: buildManifestChunkValidity(
386
+ exports,
387
+ routeChunkMap ?? createEmptyRouteChunkByExportName()
388
+ ),
389
+ });
390
+ }
391
+
392
+ return [
393
+ key,
394
+ {
395
+ id: route.id,
396
+ parentId: route.parentId,
397
+ path: route.path,
398
+ index: route.index,
399
+ caseSensitive: route.caseSensitive,
400
+ module: combineURLs(assetPrefix, jsAssets[0] || ''),
401
+ clientActionModule: routeChunkMap?.clientAction
402
+ ? getModulePathForChunk(
403
+ getRouteChunkEntryName(route.id, 'clientAction')
404
+ )
405
+ : undefined,
406
+ clientLoaderModule: routeChunkMap?.clientLoader
407
+ ? getModulePathForChunk(
408
+ getRouteChunkEntryName(route.id, 'clientLoader')
409
+ )
410
+ : undefined,
411
+ clientMiddlewareModule: routeChunkMap?.clientMiddleware
412
+ ? getModulePathForChunk(
413
+ getRouteChunkEntryName(route.id, 'clientMiddleware')
414
+ )
415
+ : undefined,
416
+ hydrateFallbackModule: routeChunkMap?.HydrateFallback
417
+ ? getModulePathForChunk(
418
+ getRouteChunkEntryName(route.id, 'HydrateFallback')
419
+ )
420
+ : undefined,
421
+ hasAction: exports.has(SERVER_EXPORTS.action),
422
+ hasLoader: exports.has(SERVER_EXPORTS.loader),
423
+ hasClientAction,
424
+ hasClientLoader,
425
+ hasClientMiddleware,
426
+ hasDefaultExport,
427
+ hasErrorBoundary: exports.has(CLIENT_EXPORTS.ErrorBoundary),
428
+ imports: jsAssets.map(asset => combineURLs(assetPrefix, asset)),
429
+ css: cssAssets.map(asset => combineURLs(assetPrefix, asset)),
430
+ },
431
+ routeModuleExports,
432
+ ] as const;
433
+ }
434
+ );
435
+
436
+ const routeModuleExportsByRouteId: RouteManifestModuleExports = {};
437
+ for (const [key, routeManifestItem, routeModuleExports] of manifestEntries) {
438
+ result[key] = routeManifestItem;
439
+ routeModuleExportsByRouteId[key] = routeModuleExports;
440
+ }
441
+
442
+ const entryAssets = getAssetsForChunk('entry.client');
443
+ const entryJsAssets = entryAssets.filter(asset => asset.endsWith('.js'));
444
+ const entryCssAssets = entryAssets.filter(asset => asset.endsWith('.css'));
445
+
446
+ const fingerprintedValues = {
447
+ entry: {
448
+ module: combineURLs(assetPrefix, entryJsAssets[0] || ''),
449
+ imports: entryJsAssets.map(asset => combineURLs(assetPrefix, asset)),
450
+ css: entryCssAssets.map(asset => combineURLs(assetPrefix, asset)),
451
+ },
452
+ routes: result,
453
+ };
454
+ const version = getManifestVersion(fingerprintedValues, isBuild);
455
+ const manifestPath = getReactRouterManifestPath({
456
+ version,
457
+ isBuild,
458
+ entryModulePath: entryJsAssets[0],
459
+ });
460
+
461
+ const manifest = {
462
+ version,
463
+ url: combineURLs(assetPrefix, manifestPath),
464
+ hmr: undefined,
465
+ entry: fingerprintedValues.entry,
466
+ sri: undefined,
467
+ routes: result,
468
+ };
469
+
470
+ return {
471
+ manifest,
472
+ moduleExportsByRouteId: routeModuleExportsByRouteId,
473
+ };
474
+ }
475
+
476
+ export async function getReactRouterManifestForDev(
477
+ ...args: Parameters<typeof generateReactRouterManifestForDev>
478
+ ): Promise<ReactRouterManifestForDev> {
479
+ return (await generateReactRouterManifestForDev(...args)).manifest;
480
+ }