rsbuild-plugin-react-router 0.5.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +58 -208
- package/dist/511.js +371 -332
- package/dist/build-output-transforms.d.ts +30 -6
- package/dist/classic-mode.d.ts +56 -0
- package/dist/config-imports.d.ts +8 -2
- package/dist/constants.d.ts +3 -0
- package/dist/dev-background-resources.d.ts +3 -1
- package/dist/dev-generation.d.ts +2 -3
- package/dist/dev-hmr.d.ts +8 -2
- package/dist/dev-runtime-controller.d.ts +6 -1
- package/dist/dev-source-maps.d.ts +4 -0
- package/dist/effect-runtime.d.ts +17 -5
- package/dist/entry-paths.d.ts +16 -0
- package/dist/environment-output.d.ts +6 -0
- package/dist/export-utils.d.ts +2 -1
- package/dist/index.cjs +3964 -2217
- package/dist/index.d.ts +3 -1
- package/dist/index.js +3474 -1799
- package/dist/lazy-compilation-prewarm.d.ts +8 -5
- package/dist/manifest.d.ts +17 -5
- package/dist/mode-plan.d.ts +82 -0
- package/dist/modify-browser-manifest.d.ts +8 -4
- package/dist/plugin-utils.d.ts +27 -1
- package/dist/prerender-build.d.ts +5 -5
- package/dist/prerender.d.ts +1 -5
- package/dist/react-router-config.d.ts +11 -3
- package/dist/route-artifacts.d.ts +4 -2
- package/dist/route-chunks.d.ts +8 -2
- package/dist/route-component-transform.d.ts +0 -2
- package/dist/route-export-pruning.d.ts +4 -1
- package/dist/route-imports.d.ts +18 -0
- package/dist/route-transform-tasks.d.ts +5 -0
- package/dist/route-watch.d.ts +11 -6
- package/dist/rsc-dev-server.d.ts +26 -0
- package/dist/rsc-prerender.d.ts +54 -0
- package/dist/rsc-route-config.d.ts +6 -0
- package/dist/rsc-route-exports.d.ts +15 -0
- package/dist/rsc-route-transform-loader.cjs +43 -0
- package/dist/rsc-route-transform-loader.d.ts +30 -0
- package/dist/rsc-route-transform-loader.js +16 -0
- package/dist/rsc-route-transform-registration.d.ts +12 -0
- package/dist/rsc-route-transforms.d.ts +21 -0
- package/dist/rsc-support.d.ts +23 -0
- package/dist/rsc-virtual-modules.d.ts +19 -0
- package/dist/server-build-plan.d.ts +2 -1
- package/dist/server-build-resolution.d.ts +1 -2
- package/dist/server-utils.d.ts +4 -5
- package/dist/ssr-asset-relocation.d.ts +98 -0
- package/dist/templates/entry.rsc.client.d.ts +1 -0
- package/dist/templates/entry.rsc.client.js +61 -0
- package/dist/templates/entry.rsc.d.ts +9 -0
- package/dist/templates/entry.rsc.js +38 -0
- package/dist/templates/entry.rsc.ssr.d.ts +4 -0
- package/dist/templates/entry.rsc.ssr.js +24 -0
- package/dist/typegen.d.ts +4 -2
- package/dist/types.d.ts +30 -1
- package/package.json +69 -14
- package/src/build-output-transforms.ts +155 -21
- package/src/classic-mode.ts +258 -0
- package/src/config-imports.ts +153 -6
- package/src/constants.ts +6 -2
- package/src/dev-background-resources.ts +46 -85
- package/src/dev-generation.ts +52 -33
- package/src/dev-hmr.ts +112 -80
- package/src/dev-runtime-artifacts.ts +11 -12
- package/src/dev-runtime-controller.ts +75 -85
- package/src/dev-runtime-session.ts +14 -18
- package/src/dev-server.ts +2 -0
- package/src/dev-source-maps.ts +257 -0
- package/src/effect-runtime.ts +105 -57
- package/src/entry-paths.ts +80 -0
- package/src/environment-output.ts +55 -0
- package/src/export-utils.ts +15 -11
- package/src/index.ts +661 -496
- package/src/lazy-compilation-prewarm.ts +20 -4
- package/src/manifest.ts +186 -100
- package/src/mode-plan.ts +367 -0
- package/src/modify-browser-manifest.ts +131 -124
- package/src/plugin-utils.ts +103 -39
- package/src/prerender-build.ts +82 -104
- package/src/prerender.ts +23 -24
- package/src/react-router-config.ts +72 -26
- package/src/route-artifacts.ts +96 -66
- package/src/route-chunks.ts +196 -54
- package/src/route-component-transform.ts +14 -21
- package/src/route-export-pruning.ts +4 -3
- package/src/route-imports.ts +100 -0
- package/src/route-transform-tasks.ts +39 -25
- package/src/route-watch.ts +166 -188
- package/src/rsc-dev-server.ts +112 -0
- package/src/rsc-prerender.ts +362 -0
- package/src/rsc-route-config.ts +175 -0
- package/src/rsc-route-exports.ts +67 -0
- package/src/rsc-route-transform-loader.ts +65 -0
- package/src/rsc-route-transform-registration.ts +145 -0
- package/src/rsc-route-transforms.ts +995 -0
- package/src/rsc-runtime.d.ts +143 -0
- package/src/rsc-support.ts +116 -0
- package/src/rsc-virtual-modules.ts +113 -0
- package/src/server-build-plan.ts +14 -3
- package/src/server-build-resolution.ts +37 -47
- package/src/server-utils.ts +21 -35
- package/src/ssr-asset-relocation.ts +183 -0
- package/src/ssr-externals.ts +8 -26
- package/src/templates/entry.rsc.client.tsx +168 -0
- package/src/templates/entry.rsc.ssr.tsx +45 -0
- package/src/templates/entry.rsc.tsx +80 -0
- package/src/typegen.ts +40 -23
- package/src/types.ts +39 -1
- package/src/warnings/warn-on-client-source-maps.ts +6 -10
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import * as Effect from 'effect/Effect';
|
|
2
|
+
import type * as Scope from 'effect/Scope';
|
|
2
3
|
import type { ReactRouterManifestForDev } from './manifest.js';
|
|
3
4
|
import type { RouteManifestItem } from './types.js';
|
|
4
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
createDelayedPluginTask,
|
|
7
|
+
type PluginEffectRuntime,
|
|
8
|
+
tryPluginPromise,
|
|
9
|
+
} from './effect-runtime.js';
|
|
5
10
|
|
|
6
11
|
const DEFAULT_LAZY_COMPILATION_TRIGGER_PREFIX = '/_rspack/lazy/trigger';
|
|
7
12
|
const DEFAULT_PREWARM_DELAY_MS = 0;
|
|
@@ -9,17 +14,17 @@ const DEFAULT_ROUTE_PREWARM_LIMIT = 8;
|
|
|
9
14
|
const PREWARM_FETCH_CONCURRENCY = 8;
|
|
10
15
|
const PREWARM_TRIGGER_CANDIDATES = 4;
|
|
11
16
|
|
|
12
|
-
type LazyCompilationPrewarmConfig = {
|
|
17
|
+
export type LazyCompilationPrewarmConfig = {
|
|
13
18
|
entry: boolean;
|
|
14
19
|
routeLimit: number;
|
|
15
20
|
delayMs: number;
|
|
16
21
|
};
|
|
17
22
|
|
|
18
|
-
type LazyCompilationPrewarmController = {
|
|
23
|
+
export type LazyCompilationPrewarmController = {
|
|
19
24
|
setServerOrigin(origin: string): void;
|
|
20
25
|
setManifest(manifest: ReactRouterManifestForDev | null): void;
|
|
21
26
|
schedule(): void;
|
|
22
|
-
cancelEffect(): Effect.Effect<void
|
|
27
|
+
cancelEffect(): Effect.Effect<void>;
|
|
23
28
|
};
|
|
24
29
|
|
|
25
30
|
export type RspackLazyCompilationTriggerClient = {
|
|
@@ -221,9 +226,11 @@ const prewarmLazyCompilation = ({
|
|
|
221
226
|
});
|
|
222
227
|
|
|
223
228
|
export const createLazyCompilationPrewarmController = ({
|
|
229
|
+
runtime,
|
|
224
230
|
config,
|
|
225
231
|
onError,
|
|
226
232
|
}: {
|
|
233
|
+
runtime: PluginEffectRuntime;
|
|
227
234
|
config: LazyCompilationPrewarmConfig;
|
|
228
235
|
onError: (error: Error) => void;
|
|
229
236
|
}): LazyCompilationPrewarmController => {
|
|
@@ -231,6 +238,7 @@ export const createLazyCompilationPrewarmController = ({
|
|
|
231
238
|
let manifest: ReactRouterManifestForDev | null = null;
|
|
232
239
|
let lastPrewarmAssetsKey: string | undefined;
|
|
233
240
|
const task = createDelayedPluginTask({
|
|
241
|
+
runtime,
|
|
234
242
|
delayMs: config.delayMs,
|
|
235
243
|
run: () =>
|
|
236
244
|
Effect.gen(function* () {
|
|
@@ -277,3 +285,11 @@ export const createLazyCompilationPrewarmController = ({
|
|
|
277
285
|
},
|
|
278
286
|
};
|
|
279
287
|
};
|
|
288
|
+
|
|
289
|
+
export const acquireLazyCompilationPrewarm = (
|
|
290
|
+
options: Parameters<typeof createLazyCompilationPrewarmController>[0]
|
|
291
|
+
): Effect.Effect<LazyCompilationPrewarmController, never, Scope.Scope> =>
|
|
292
|
+
Effect.acquireRelease(
|
|
293
|
+
Effect.sync(() => createLazyCompilationPrewarmController(options)),
|
|
294
|
+
controller => controller.cancelEffect()
|
|
295
|
+
);
|
package/src/manifest.ts
CHANGED
|
@@ -3,18 +3,27 @@ import { dirname, isAbsolute, relative, resolve } from 'pathe';
|
|
|
3
3
|
import * as Effect from 'effect/Effect';
|
|
4
4
|
import type { Route, PluginOptions, RouteManifestItem } from './types.js';
|
|
5
5
|
import { combineURLs, createRouteId } from './plugin-utils.js';
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
CLIENT_EXPORTS,
|
|
8
|
+
DEFAULT_JS_DIST_PATH,
|
|
9
|
+
SERVER_EXPORTS,
|
|
10
|
+
} from './constants.js';
|
|
7
11
|
import {
|
|
8
12
|
buildManifestChunkValidity,
|
|
9
13
|
createEmptyRouteChunkByExportName,
|
|
10
14
|
detectRouteChunksIfEnabled,
|
|
11
15
|
getRouteChunkEntryName,
|
|
16
|
+
getRouteEntryBaseName,
|
|
12
17
|
routeChunkExportNames,
|
|
13
18
|
validateRouteChunks,
|
|
14
19
|
type RouteChunkCache,
|
|
15
20
|
type RouteChunkConfig,
|
|
21
|
+
type RouteChunkExportName,
|
|
16
22
|
} from './route-chunks.js';
|
|
17
|
-
import {
|
|
23
|
+
import {
|
|
24
|
+
getRouteModuleAnalysis,
|
|
25
|
+
type RouteModuleAnalysis,
|
|
26
|
+
} from './export-utils.js';
|
|
18
27
|
import { getCappedPluginConcurrency } from './concurrency.js';
|
|
19
28
|
import { runPluginEffect, tryPluginPromise } from './effect-runtime.js';
|
|
20
29
|
|
|
@@ -87,13 +96,38 @@ export function configRoutesToRouteManifestEntries(
|
|
|
87
96
|
return routeManifestEntries;
|
|
88
97
|
}
|
|
89
98
|
|
|
90
|
-
type RouteChunkManifestOptions = {
|
|
99
|
+
export type RouteChunkManifestOptions = {
|
|
91
100
|
splitRouteModules?: boolean | 'enforce';
|
|
92
101
|
rootRouteFile?: string;
|
|
93
102
|
isBuild?: boolean;
|
|
94
103
|
cache?: RouteChunkCache;
|
|
95
104
|
};
|
|
96
105
|
|
|
106
|
+
export type RouteModuleAnalysisProvider = (
|
|
107
|
+
routeFilePath: string,
|
|
108
|
+
route: Route
|
|
109
|
+
) => Promise<RouteModuleAnalysis | undefined>;
|
|
110
|
+
|
|
111
|
+
export type ReactRouterManifestOptions = RouteChunkManifestOptions & {
|
|
112
|
+
routeModuleAnalysis?: RouteModuleAnalysisProvider;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
export const createReactRouterManifestOptions = ({
|
|
116
|
+
routeChunks,
|
|
117
|
+
routeModuleAnalysis,
|
|
118
|
+
}: {
|
|
119
|
+
routeChunks?: RouteChunkManifestOptions;
|
|
120
|
+
routeModuleAnalysis?: RouteModuleAnalysisProvider;
|
|
121
|
+
}): ReactRouterManifestOptions | undefined => {
|
|
122
|
+
if (!routeChunks && !routeModuleAnalysis) {
|
|
123
|
+
return undefined;
|
|
124
|
+
}
|
|
125
|
+
return {
|
|
126
|
+
...routeChunks,
|
|
127
|
+
...(routeModuleAnalysis ? { routeModuleAnalysis } : {}),
|
|
128
|
+
};
|
|
129
|
+
};
|
|
130
|
+
|
|
97
131
|
export type ReactRouterManifestForDev = {
|
|
98
132
|
version: string;
|
|
99
133
|
url: string;
|
|
@@ -122,8 +156,10 @@ type ReactRouterManifestStatsEntrypoint = {
|
|
|
122
156
|
getFiles?: () => Iterable<string>;
|
|
123
157
|
};
|
|
124
158
|
|
|
125
|
-
type ReactRouterManifestStatsLookup<T> = Iterable<
|
|
126
|
-
|
|
159
|
+
type ReactRouterManifestStatsLookup<T> = Iterable<
|
|
160
|
+
[string, T | null | undefined]
|
|
161
|
+
> & {
|
|
162
|
+
get?: (name: string) => T | null | undefined;
|
|
127
163
|
};
|
|
128
164
|
|
|
129
165
|
type ReactRouterManifestStatsCompilation = {
|
|
@@ -153,6 +189,9 @@ const collectManifestFilesByName = <T>(
|
|
|
153
189
|
const filesByName: Record<string, string[]> = {};
|
|
154
190
|
if (!names) {
|
|
155
191
|
for (const [name, item] of items) {
|
|
192
|
+
if (item == null) {
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
156
195
|
filesByName[name] = getFiles(name, item);
|
|
157
196
|
}
|
|
158
197
|
return filesByName;
|
|
@@ -162,7 +201,7 @@ const collectManifestFilesByName = <T>(
|
|
|
162
201
|
if (typeof items.get === 'function') {
|
|
163
202
|
for (const name of names) {
|
|
164
203
|
const item = items.get(name);
|
|
165
|
-
if (
|
|
204
|
+
if (item == null) {
|
|
166
205
|
continue;
|
|
167
206
|
}
|
|
168
207
|
filesByName[name] = getFiles(name, item);
|
|
@@ -178,6 +217,9 @@ const collectManifestFilesByName = <T>(
|
|
|
178
217
|
if (!missingNames.has(name)) {
|
|
179
218
|
continue;
|
|
180
219
|
}
|
|
220
|
+
if (item == null) {
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
181
223
|
filesByName[name] = getFiles(name, item);
|
|
182
224
|
missingNames.delete(name);
|
|
183
225
|
if (missingNames.size === 0) {
|
|
@@ -236,11 +278,12 @@ type RouteManifestAnalysis = {
|
|
|
236
278
|
> | null;
|
|
237
279
|
};
|
|
238
280
|
|
|
239
|
-
const DEFAULT_MANIFEST_DIR =
|
|
281
|
+
const DEFAULT_MANIFEST_DIR = DEFAULT_JS_DIST_PATH;
|
|
240
282
|
const CSS_IMPORT_RE = /\.(?:css|less|sass|scss)(?:\?[^'"`]+)?['"`]/;
|
|
241
283
|
|
|
242
284
|
const createChunkAssetResolver = (
|
|
243
|
-
clientStats: ReactRouterManifestStats | undefined
|
|
285
|
+
clientStats: ReactRouterManifestStats | undefined,
|
|
286
|
+
includeEntrypointJs: boolean
|
|
244
287
|
): ((chunkName: string) => ChunkAssets) => {
|
|
245
288
|
const chunkAssetsByName = new Map<string, ChunkAssets>();
|
|
246
289
|
|
|
@@ -259,24 +302,26 @@ const createChunkAssetResolver = (
|
|
|
259
302
|
}
|
|
260
303
|
|
|
261
304
|
const cssAssets = new Set<string>();
|
|
262
|
-
const jsAssets
|
|
305
|
+
const jsAssets = new Set<string>();
|
|
263
306
|
for (const asset of assets) {
|
|
264
307
|
if (asset.endsWith('.css')) {
|
|
265
308
|
cssAssets.add(asset);
|
|
266
309
|
} else if (asset.endsWith('.js')) {
|
|
267
|
-
jsAssets.
|
|
310
|
+
jsAssets.add(asset);
|
|
268
311
|
}
|
|
269
312
|
}
|
|
270
313
|
for (const asset of clientStats?.entrypointFilesByName?.[chunkName] ?? []) {
|
|
271
314
|
if (asset.endsWith('.css')) {
|
|
272
315
|
cssAssets.add(asset);
|
|
316
|
+
} else if (includeEntrypointJs && asset.endsWith('.js')) {
|
|
317
|
+
jsAssets.add(asset);
|
|
273
318
|
}
|
|
274
319
|
}
|
|
275
|
-
if (jsAssets.
|
|
276
|
-
jsAssets.
|
|
320
|
+
if (jsAssets.size === 0) {
|
|
321
|
+
jsAssets.add(`${DEFAULT_MANIFEST_DIR}/${chunkName}.js`);
|
|
277
322
|
}
|
|
278
323
|
|
|
279
|
-
const result = { js: jsAssets, css: [...cssAssets] };
|
|
324
|
+
const result = { js: [...jsAssets], css: [...cssAssets] };
|
|
280
325
|
chunkAssetsByName.set(chunkName, result);
|
|
281
326
|
return result;
|
|
282
327
|
};
|
|
@@ -289,6 +334,8 @@ const analyzeRouteForManifestEffect = ({
|
|
|
289
334
|
routeChunkConfig,
|
|
290
335
|
routeEntryName,
|
|
291
336
|
routeFilePath,
|
|
337
|
+
route,
|
|
338
|
+
routeModuleAnalysis,
|
|
292
339
|
}: {
|
|
293
340
|
discoveredCssAssets: string[];
|
|
294
341
|
isBuild: boolean;
|
|
@@ -296,10 +343,13 @@ const analyzeRouteForManifestEffect = ({
|
|
|
296
343
|
routeChunkConfig: RouteChunkConfig | null;
|
|
297
344
|
routeEntryName: string;
|
|
298
345
|
routeFilePath: string;
|
|
346
|
+
route: Route;
|
|
347
|
+
routeModuleAnalysis?: RouteModuleAnalysisProvider;
|
|
299
348
|
}): Effect.Effect<RouteManifestAnalysis, Error, never> =>
|
|
300
349
|
tryPluginPromise(async () => {
|
|
301
350
|
const { code, exports: exportNames } =
|
|
302
|
-
await
|
|
351
|
+
(await routeModuleAnalysis?.(routeFilePath, route)) ??
|
|
352
|
+
(await getRouteModuleAnalysis(routeFilePath));
|
|
303
353
|
const cssAssets =
|
|
304
354
|
!isBuild && discoveredCssAssets.length === 0 && CSS_IMPORT_RE.test(code)
|
|
305
355
|
? [
|
|
@@ -363,152 +413,181 @@ export const getReactRouterManifestPath = ({
|
|
|
363
413
|
return `${dir}/manifest-${version}.js`;
|
|
364
414
|
};
|
|
365
415
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
416
|
+
// The version is derived from the manifest content in every mode. React
|
|
417
|
+
// Router's stale-client detection compares the version the browser loaded with
|
|
418
|
+
// the one the server build was pinned to, and answers a mismatch with a
|
|
419
|
+
// document reload. In development the browser manifest asset is served from
|
|
420
|
+
// the latest web compilation while the server build stays pinned to the
|
|
421
|
+
// compilation it was committed with, so a random per-compilation version made
|
|
422
|
+
// the two disagree whenever a web compilation completed without changing the
|
|
423
|
+
// manifest (for example the hot data revalidation recompile that follows a
|
|
424
|
+
// server change), reloading the document for no reason. Equal content now
|
|
425
|
+
// yields an equal version, and a real manifest change still busts the browser
|
|
426
|
+
// cache through the `?v=` query on the development manifest URL.
|
|
427
|
+
const getManifestVersion = (fingerprintedValues: {
|
|
428
|
+
entry: unknown;
|
|
429
|
+
routes: unknown;
|
|
430
|
+
}): string =>
|
|
431
|
+
createHash('md5')
|
|
374
432
|
.update(JSON.stringify(fingerprintedValues))
|
|
375
433
|
.digest('hex')
|
|
376
434
|
.slice(0, 8);
|
|
377
|
-
};
|
|
378
|
-
|
|
379
|
-
const getRouteEntryName = (route: Route): string => {
|
|
380
|
-
const extensionIndex = route.file.lastIndexOf('.');
|
|
381
|
-
return extensionIndex >= 0 ? route.file.slice(0, extensionIndex) : route.file;
|
|
382
|
-
};
|
|
383
435
|
|
|
384
436
|
export const getReactRouterManifestChunkNames = (
|
|
385
437
|
routes: Record<string, Route>,
|
|
438
|
+
appDirectory: string,
|
|
386
439
|
splitRouteModules: boolean | 'enforce' = false
|
|
387
440
|
): Set<string> => {
|
|
388
441
|
const chunkNames = new Set<string>(['entry.client']);
|
|
389
442
|
for (const route of Object.values(routes)) {
|
|
390
|
-
chunkNames.add(
|
|
443
|
+
chunkNames.add(getRouteEntryBaseName(route, appDirectory));
|
|
391
444
|
if (!splitRouteModules || route.id === 'root') {
|
|
392
445
|
continue;
|
|
393
446
|
}
|
|
394
447
|
for (const exportName of routeChunkExportNames) {
|
|
395
|
-
chunkNames.add(getRouteChunkEntryName(route
|
|
448
|
+
chunkNames.add(getRouteChunkEntryName(route, exportName, appDirectory));
|
|
396
449
|
}
|
|
397
450
|
}
|
|
398
451
|
return chunkNames;
|
|
399
452
|
};
|
|
400
453
|
|
|
454
|
+
const createRouteManifestItem = ({
|
|
455
|
+
route,
|
|
456
|
+
appDirectory,
|
|
457
|
+
assetPrefix,
|
|
458
|
+
jsAssets,
|
|
459
|
+
routeAnalysis,
|
|
460
|
+
getModulePathForChunk,
|
|
461
|
+
getCssAssetsForChunk,
|
|
462
|
+
}: {
|
|
463
|
+
route: Route;
|
|
464
|
+
appDirectory: string;
|
|
465
|
+
assetPrefix: string;
|
|
466
|
+
jsAssets: string[];
|
|
467
|
+
routeAnalysis: RouteManifestAnalysis;
|
|
468
|
+
getModulePathForChunk: (chunkName: string) => string | undefined;
|
|
469
|
+
getCssAssetsForChunk: (chunkName: string) => string[];
|
|
470
|
+
}): RouteManifestItem => {
|
|
471
|
+
const routeChunkMap = routeAnalysis.hasRouteChunkByExportName;
|
|
472
|
+
const chunkModulePath = (exportName: RouteChunkExportName) =>
|
|
473
|
+
routeChunkMap?.[exportName]
|
|
474
|
+
? getModulePathForChunk(
|
|
475
|
+
getRouteChunkEntryName(route, exportName, appDirectory)
|
|
476
|
+
)
|
|
477
|
+
: undefined;
|
|
478
|
+
const cssAssets = [
|
|
479
|
+
...routeAnalysis.cssAssets,
|
|
480
|
+
...routeChunkExportNames.flatMap(exportName =>
|
|
481
|
+
routeChunkMap?.[exportName]
|
|
482
|
+
? getCssAssetsForChunk(
|
|
483
|
+
getRouteChunkEntryName(route, exportName, appDirectory)
|
|
484
|
+
)
|
|
485
|
+
: []
|
|
486
|
+
),
|
|
487
|
+
];
|
|
488
|
+
|
|
489
|
+
return {
|
|
490
|
+
id: route.id,
|
|
491
|
+
parentId: route.parentId,
|
|
492
|
+
path: route.path,
|
|
493
|
+
index: route.index,
|
|
494
|
+
caseSensitive: route.caseSensitive,
|
|
495
|
+
module: combineURLs(assetPrefix, jsAssets[0] || ''),
|
|
496
|
+
clientActionModule: chunkModulePath('clientAction'),
|
|
497
|
+
clientLoaderModule: chunkModulePath('clientLoader'),
|
|
498
|
+
clientMiddlewareModule: chunkModulePath('clientMiddleware'),
|
|
499
|
+
hydrateFallbackModule: chunkModulePath('HydrateFallback'),
|
|
500
|
+
hasAction: routeAnalysis.exports.has(SERVER_EXPORTS.action),
|
|
501
|
+
hasLoader: routeAnalysis.exports.has(SERVER_EXPORTS.loader),
|
|
502
|
+
hasClientAction: routeAnalysis.exports.has(CLIENT_EXPORTS.clientAction),
|
|
503
|
+
hasClientLoader: routeAnalysis.exports.has(CLIENT_EXPORTS.clientLoader),
|
|
504
|
+
hasClientMiddleware: routeAnalysis.exports.has(
|
|
505
|
+
CLIENT_EXPORTS.clientMiddleware
|
|
506
|
+
),
|
|
507
|
+
hasDefaultExport: routeAnalysis.exports.has('default'),
|
|
508
|
+
hasErrorBoundary: routeAnalysis.exports.has(CLIENT_EXPORTS.ErrorBoundary),
|
|
509
|
+
// `module` is `jsAssets[0]`; exclude it from `imports` so the browser
|
|
510
|
+
// manifest does not list the route's own module twice (upstream excludes
|
|
511
|
+
// the entry chunk's own file from its imports list). Otherwise prefetch
|
|
512
|
+
// link computations produce duplicate modulepreload hrefs.
|
|
513
|
+
imports: jsAssets.slice(1).map(asset => combineURLs(assetPrefix, asset)),
|
|
514
|
+
css: Array.from(new Set(cssAssets)).map(asset =>
|
|
515
|
+
combineURLs(assetPrefix, asset)
|
|
516
|
+
),
|
|
517
|
+
};
|
|
518
|
+
};
|
|
519
|
+
|
|
401
520
|
function generateReactRouterManifestForDevEffect(
|
|
402
521
|
routes: Record<string, Route>,
|
|
403
|
-
_options: PluginOptions,
|
|
404
522
|
clientStats: ReactRouterManifestStats | undefined,
|
|
405
523
|
context: string,
|
|
406
524
|
assetPrefix: string,
|
|
407
|
-
|
|
525
|
+
manifestOptions?: ReactRouterManifestOptions
|
|
408
526
|
): Effect.Effect<ReactRouterManifestGenerationResult, Error, never> {
|
|
409
527
|
return Effect.gen(function* () {
|
|
410
528
|
const result: Record<string, RouteManifestItem> = {};
|
|
411
|
-
const splitRouteModules =
|
|
529
|
+
const splitRouteModules = manifestOptions?.splitRouteModules ?? false;
|
|
412
530
|
const enforceSplitRouteModules = splitRouteModules === 'enforce';
|
|
413
|
-
const isBuild =
|
|
531
|
+
const isBuild = manifestOptions?.isBuild ?? false;
|
|
414
532
|
const routeChunkConfig: RouteChunkConfig | null =
|
|
415
|
-
splitRouteModules &&
|
|
533
|
+
splitRouteModules && manifestOptions?.rootRouteFile
|
|
416
534
|
? {
|
|
417
535
|
splitRouteModules,
|
|
418
536
|
appDirectory: context,
|
|
419
|
-
rootRouteFile:
|
|
537
|
+
rootRouteFile: manifestOptions.rootRouteFile,
|
|
420
538
|
}
|
|
421
539
|
: null;
|
|
422
540
|
|
|
423
|
-
const getAssetsForChunk = createChunkAssetResolver(clientStats);
|
|
541
|
+
const getAssetsForChunk = createChunkAssetResolver(clientStats, isBuild);
|
|
424
542
|
const getModulePathForChunk = (chunkName: string): string | undefined => {
|
|
425
543
|
const { js: jsAssets } = getAssetsForChunk(chunkName);
|
|
426
544
|
return jsAssets[0] ? combineURLs(assetPrefix, jsAssets[0]) : undefined;
|
|
427
545
|
};
|
|
546
|
+
const getCssAssetsForChunk = (chunkName: string): string[] =>
|
|
547
|
+
getAssetsForChunk(chunkName).css;
|
|
428
548
|
|
|
429
549
|
const manifestEntries = yield* Effect.forEach(
|
|
430
550
|
Object.entries(routes),
|
|
431
551
|
([key, route]) =>
|
|
432
552
|
Effect.gen(function* () {
|
|
433
|
-
const routeEntryName =
|
|
553
|
+
const routeEntryName = getRouteEntryBaseName(route, context);
|
|
434
554
|
const { js: jsAssets, css: discoveredCssAssets } =
|
|
435
555
|
getAssetsForChunk(routeEntryName);
|
|
436
556
|
const routeFilePath = resolve(context, route.file);
|
|
437
557
|
const routeAnalysis = yield* analyzeRouteForManifestEffect({
|
|
438
558
|
discoveredCssAssets,
|
|
439
559
|
isBuild,
|
|
440
|
-
routeChunkCache:
|
|
560
|
+
routeChunkCache: manifestOptions?.cache,
|
|
441
561
|
routeChunkConfig,
|
|
442
562
|
routeEntryName,
|
|
443
563
|
routeFilePath,
|
|
564
|
+
route,
|
|
565
|
+
routeModuleAnalysis: manifestOptions?.routeModuleAnalysis,
|
|
444
566
|
});
|
|
445
567
|
|
|
446
|
-
const hasClientAction = routeAnalysis.exports.has(
|
|
447
|
-
CLIENT_EXPORTS.clientAction
|
|
448
|
-
);
|
|
449
|
-
const hasClientLoader = routeAnalysis.exports.has(
|
|
450
|
-
CLIENT_EXPORTS.clientLoader
|
|
451
|
-
);
|
|
452
|
-
const hasClientMiddleware = routeAnalysis.exports.has(
|
|
453
|
-
CLIENT_EXPORTS.clientMiddleware
|
|
454
|
-
);
|
|
455
|
-
const hasDefaultExport = routeAnalysis.exports.has('default');
|
|
456
|
-
const routeChunkMap = routeAnalysis.hasRouteChunkByExportName;
|
|
457
|
-
|
|
458
568
|
if (isBuild && enforceSplitRouteModules && routeChunkConfig) {
|
|
459
569
|
validateRouteChunks({
|
|
460
570
|
config: routeChunkConfig,
|
|
461
571
|
id: routeFilePath,
|
|
462
572
|
valid: buildManifestChunkValidity(
|
|
463
573
|
routeAnalysis.exports,
|
|
464
|
-
|
|
574
|
+
routeAnalysis.hasRouteChunkByExportName ??
|
|
575
|
+
createEmptyRouteChunkByExportName()
|
|
465
576
|
),
|
|
466
577
|
});
|
|
467
578
|
}
|
|
468
579
|
|
|
469
580
|
return [
|
|
470
581
|
key,
|
|
471
|
-
{
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
getRouteChunkEntryName(route.id, 'clientAction')
|
|
481
|
-
)
|
|
482
|
-
: undefined,
|
|
483
|
-
clientLoaderModule: routeChunkMap?.clientLoader
|
|
484
|
-
? getModulePathForChunk(
|
|
485
|
-
getRouteChunkEntryName(route.id, 'clientLoader')
|
|
486
|
-
)
|
|
487
|
-
: undefined,
|
|
488
|
-
clientMiddlewareModule: routeChunkMap?.clientMiddleware
|
|
489
|
-
? getModulePathForChunk(
|
|
490
|
-
getRouteChunkEntryName(route.id, 'clientMiddleware')
|
|
491
|
-
)
|
|
492
|
-
: undefined,
|
|
493
|
-
hydrateFallbackModule: routeChunkMap?.HydrateFallback
|
|
494
|
-
? getModulePathForChunk(
|
|
495
|
-
getRouteChunkEntryName(route.id, 'HydrateFallback')
|
|
496
|
-
)
|
|
497
|
-
: undefined,
|
|
498
|
-
hasAction: routeAnalysis.exports.has(SERVER_EXPORTS.action),
|
|
499
|
-
hasLoader: routeAnalysis.exports.has(SERVER_EXPORTS.loader),
|
|
500
|
-
hasClientAction,
|
|
501
|
-
hasClientLoader,
|
|
502
|
-
hasClientMiddleware,
|
|
503
|
-
hasDefaultExport,
|
|
504
|
-
hasErrorBoundary: routeAnalysis.exports.has(
|
|
505
|
-
CLIENT_EXPORTS.ErrorBoundary
|
|
506
|
-
),
|
|
507
|
-
imports: jsAssets.map(asset => combineURLs(assetPrefix, asset)),
|
|
508
|
-
css: routeAnalysis.cssAssets.map(asset =>
|
|
509
|
-
combineURLs(assetPrefix, asset)
|
|
510
|
-
),
|
|
511
|
-
},
|
|
582
|
+
createRouteManifestItem({
|
|
583
|
+
route,
|
|
584
|
+
appDirectory: context,
|
|
585
|
+
assetPrefix,
|
|
586
|
+
jsAssets,
|
|
587
|
+
routeAnalysis,
|
|
588
|
+
getModulePathForChunk,
|
|
589
|
+
getCssAssetsForChunk,
|
|
590
|
+
}),
|
|
512
591
|
routeAnalysis.routeModuleExports,
|
|
513
592
|
] as const;
|
|
514
593
|
}),
|
|
@@ -536,12 +615,17 @@ function generateReactRouterManifestForDevEffect(
|
|
|
536
615
|
const fingerprintedValues = {
|
|
537
616
|
entry: {
|
|
538
617
|
module: combineURLs(assetPrefix, entryJsAssets[0] || ''),
|
|
539
|
-
|
|
618
|
+
// Exclude the entry's own module (`entryJsAssets[0]`) from imports so it
|
|
619
|
+
// is not listed twice, matching upstream where `imports` holds only the
|
|
620
|
+
// chunk's dependency imports.
|
|
621
|
+
imports: entryJsAssets
|
|
622
|
+
.slice(1)
|
|
623
|
+
.map(asset => combineURLs(assetPrefix, asset)),
|
|
540
624
|
css: entryCssAssets.map(asset => combineURLs(assetPrefix, asset)),
|
|
541
625
|
},
|
|
542
626
|
routes: result,
|
|
543
627
|
};
|
|
544
|
-
const version = getManifestVersion(fingerprintedValues
|
|
628
|
+
const version = getManifestVersion(fingerprintedValues);
|
|
545
629
|
const manifestPath = getReactRouterManifestPath({
|
|
546
630
|
version,
|
|
547
631
|
isBuild,
|
|
@@ -550,7 +634,10 @@ function generateReactRouterManifestForDevEffect(
|
|
|
550
634
|
|
|
551
635
|
const manifest = {
|
|
552
636
|
version,
|
|
553
|
-
url: combineURLs(
|
|
637
|
+
url: combineURLs(
|
|
638
|
+
assetPrefix,
|
|
639
|
+
isBuild ? manifestPath : `${manifestPath}?v=${version}`
|
|
640
|
+
),
|
|
554
641
|
hmr: undefined,
|
|
555
642
|
entry: fingerprintedValues.entry,
|
|
556
643
|
sri: undefined,
|
|
@@ -566,20 +653,19 @@ function generateReactRouterManifestForDevEffect(
|
|
|
566
653
|
|
|
567
654
|
export async function generateReactRouterManifestForDev(
|
|
568
655
|
routes: Record<string, Route>,
|
|
569
|
-
|
|
656
|
+
_options: PluginOptions,
|
|
570
657
|
clientStats: ReactRouterManifestStats | undefined,
|
|
571
658
|
context: string,
|
|
572
659
|
assetPrefix = '/',
|
|
573
|
-
|
|
660
|
+
manifestOptions?: ReactRouterManifestOptions
|
|
574
661
|
): Promise<ReactRouterManifestGenerationResult> {
|
|
575
662
|
return runPluginEffect(
|
|
576
663
|
generateReactRouterManifestForDevEffect(
|
|
577
664
|
routes,
|
|
578
|
-
options,
|
|
579
665
|
clientStats,
|
|
580
666
|
context,
|
|
581
667
|
assetPrefix,
|
|
582
|
-
|
|
668
|
+
manifestOptions
|
|
583
669
|
)
|
|
584
670
|
);
|
|
585
671
|
}
|