rsbuild-plugin-react-router 0.3.0 → 0.3.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 +55 -24
- package/dist/451.js +36 -20
- package/dist/build-manifest.d.ts +6 -3
- package/dist/concurrency.d.ts +2 -1
- package/dist/config-imports.d.ts +7 -0
- package/dist/dev-background-resources.d.ts +38 -0
- package/dist/dev-generation.d.ts +2 -2
- package/dist/dev-runtime-artifacts.d.ts +9 -1
- package/dist/dev-runtime-compilation.d.ts +17 -2
- package/dist/dev-server.d.ts +5 -0
- package/dist/effect-runtime.d.ts +18 -0
- package/dist/export-utils.d.ts +2 -2
- package/dist/index.cjs +11448 -891
- package/dist/index.d.ts +4 -0
- package/dist/index.js +7950 -758
- package/dist/lazy-compilation-prewarm.d.ts +25 -0
- package/dist/lazy-compilation.d.ts +2 -1
- package/dist/manifest.d.ts +19 -4
- package/dist/parallel-route-transforms.d.ts +17 -2
- package/dist/prerender-build.d.ts +4 -0
- package/dist/prerender.d.ts +0 -1
- package/dist/react-router-config.d.ts +8 -5
- package/dist/server-build-resolution.d.ts +3 -0
- package/dist/ssr-externals.d.ts +1 -0
- package/dist/typegen.d.ts +14 -1
- package/dist/types.d.ts +15 -6
- package/package.json +11 -9
- package/src/build-manifest.ts +110 -73
- package/src/concurrency.ts +3 -22
- package/src/config-imports.ts +38 -0
- package/src/dev-background-resources.ts +255 -0
- package/src/dev-generation.ts +43 -53
- package/src/dev-runtime-artifacts.ts +50 -18
- package/src/dev-runtime-compilation.ts +80 -1
- package/src/dev-runtime-controller.ts +111 -31
- package/src/dev-runtime-session.ts +18 -11
- package/src/dev-server.ts +31 -1
- package/src/effect-runtime.ts +130 -0
- package/src/export-utils.ts +82 -23
- package/src/index.ts +118 -153
- package/src/lazy-compilation-prewarm.ts +279 -0
- package/src/lazy-compilation.ts +12 -5
- package/src/manifest.ts +366 -255
- package/src/modify-browser-manifest.ts +2 -1
- package/src/parallel-route-transforms.ts +195 -69
- package/src/prerender-build.ts +125 -61
- package/src/prerender.ts +0 -18
- package/src/react-router-config.ts +98 -73
- package/src/route-artifacts.ts +2 -2
- package/src/route-export-resolution.ts +3 -3
- package/src/route-watch.ts +119 -84
- package/src/server-build-resolution.ts +131 -0
- package/src/server-utils.ts +7 -106
- package/src/ssr-externals.ts +1 -1
- package/src/typegen.ts +162 -33
- package/src/types.ts +16 -6
package/src/export-utils.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { readFile, stat } from 'node:fs/promises';
|
|
2
|
-
import {
|
|
2
|
+
import { rspack } from '@rsbuild/core';
|
|
3
|
+
import { langFromPath, parse, type ParseOptions } from 'yuku-parser';
|
|
3
4
|
import { setBoundedCacheEntry } from './bounded-cache.js';
|
|
4
5
|
import {
|
|
5
6
|
getExportedName,
|
|
@@ -34,6 +35,75 @@ const routeModuleAnalysisCache = new Map<
|
|
|
34
35
|
|
|
35
36
|
const MAX_EXPORT_UTILS_CACHE_ENTRIES = 2048;
|
|
36
37
|
|
|
38
|
+
const stripResourcePathQuery = (resourcePath: string): string =>
|
|
39
|
+
resourcePath.replace(/[?#].*$/, '');
|
|
40
|
+
|
|
41
|
+
type TypeScriptParseLang = Extract<
|
|
42
|
+
NonNullable<ParseOptions['lang']>,
|
|
43
|
+
'ts' | 'tsx'
|
|
44
|
+
>;
|
|
45
|
+
|
|
46
|
+
const getExportAnalysisCode = (
|
|
47
|
+
code: string,
|
|
48
|
+
resourcePath: string,
|
|
49
|
+
lang: TypeScriptParseLang
|
|
50
|
+
): string =>
|
|
51
|
+
rspack.experiments.swc.transformSync(code, {
|
|
52
|
+
filename: resourcePath,
|
|
53
|
+
jsc: {
|
|
54
|
+
parser: {
|
|
55
|
+
syntax: 'typescript',
|
|
56
|
+
tsx: lang === 'tsx',
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
}).code;
|
|
60
|
+
|
|
61
|
+
const getParseErrors = (result: ReturnType<typeof parse>) =>
|
|
62
|
+
result.diagnostics.filter(diagnostic => diagnostic.severity === 'error');
|
|
63
|
+
|
|
64
|
+
const getParseErrorMessage = (
|
|
65
|
+
errors: ReturnType<typeof getParseErrors>
|
|
66
|
+
): string => errors.map(error => error.message).join('\n');
|
|
67
|
+
|
|
68
|
+
const parseProgram = (code: string, resourcePath?: string): ProgramNode => {
|
|
69
|
+
const sourcePath = resourcePath
|
|
70
|
+
? stripResourcePathQuery(resourcePath)
|
|
71
|
+
: undefined;
|
|
72
|
+
const lang = sourcePath ? langFromPath(sourcePath) : 'tsx';
|
|
73
|
+
const result = parse(code, {
|
|
74
|
+
sourceType: 'module',
|
|
75
|
+
lang,
|
|
76
|
+
});
|
|
77
|
+
const errors = getParseErrors(result);
|
|
78
|
+
if (errors.length === 0) {
|
|
79
|
+
return getProgram(result);
|
|
80
|
+
}
|
|
81
|
+
if (!sourcePath || (lang !== 'ts' && lang !== 'tsx')) {
|
|
82
|
+
throw new Error(getParseErrorMessage(errors));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const normalizedCode = getExportAnalysisCode(code, sourcePath, lang);
|
|
86
|
+
const normalizedResult = parse(normalizedCode, {
|
|
87
|
+
sourceType: 'module',
|
|
88
|
+
lang: 'js',
|
|
89
|
+
});
|
|
90
|
+
const normalizedErrors = getParseErrors(normalizedResult);
|
|
91
|
+
if (normalizedErrors.length > 0) {
|
|
92
|
+
throw new Error(getParseErrorMessage(normalizedErrors));
|
|
93
|
+
}
|
|
94
|
+
return getProgram(normalizedResult);
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const getExportInfoCacheKey = (
|
|
98
|
+
code: string,
|
|
99
|
+
resourcePath?: string
|
|
100
|
+
): string => {
|
|
101
|
+
const lang = resourcePath
|
|
102
|
+
? langFromPath(stripResourcePathQuery(resourcePath))
|
|
103
|
+
: 'inline';
|
|
104
|
+
return `${lang}\0${code}`;
|
|
105
|
+
};
|
|
106
|
+
|
|
37
107
|
const cachePromiseOnReject = <T>(
|
|
38
108
|
promise: Promise<T>,
|
|
39
109
|
invalidate: () => void
|
|
@@ -43,20 +113,6 @@ const cachePromiseOnReject = <T>(
|
|
|
43
113
|
throw error;
|
|
44
114
|
});
|
|
45
115
|
|
|
46
|
-
const parseProgram = (code: string, resourcePath?: string): ProgramNode => {
|
|
47
|
-
const result = parse(code, {
|
|
48
|
-
sourceType: 'module',
|
|
49
|
-
lang: resourcePath ? langFromPath(resourcePath) : 'tsx',
|
|
50
|
-
});
|
|
51
|
-
const errors = result.diagnostics.filter(
|
|
52
|
-
diagnostic => diagnostic.severity === 'error'
|
|
53
|
-
);
|
|
54
|
-
if (errors.length > 0) {
|
|
55
|
-
throw new Error(errors.map(error => error.message).join('\n'));
|
|
56
|
-
}
|
|
57
|
-
return getProgram(result);
|
|
58
|
-
};
|
|
59
|
-
|
|
60
116
|
const isTypeOnlyExport = (node: AnyNode): boolean =>
|
|
61
117
|
node.exportKind === 'type' ||
|
|
62
118
|
node.type === 'TSExportAssignment' ||
|
|
@@ -140,21 +196,24 @@ const collectExportAllModules = (program: AnyNode): string[] => {
|
|
|
140
196
|
};
|
|
141
197
|
|
|
142
198
|
export const getExportNames = async (
|
|
143
|
-
code: string
|
|
199
|
+
code: string,
|
|
200
|
+
resourcePath?: string
|
|
144
201
|
): Promise<readonly string[]> => {
|
|
145
|
-
return (await getExportNamesAndExportAll(code)).exportNames;
|
|
202
|
+
return (await getExportNamesAndExportAll(code, resourcePath)).exportNames;
|
|
146
203
|
};
|
|
147
204
|
|
|
148
205
|
export const getExportNamesAndExportAll = async (
|
|
149
|
-
code: string
|
|
206
|
+
code: string,
|
|
207
|
+
resourcePath?: string
|
|
150
208
|
): Promise<ExportInfo> => {
|
|
151
|
-
const
|
|
209
|
+
const cacheKey = getExportInfoCacheKey(code, resourcePath);
|
|
210
|
+
const cached = exportInfoCache.get(cacheKey);
|
|
152
211
|
if (cached) {
|
|
153
212
|
return cached;
|
|
154
213
|
}
|
|
155
214
|
|
|
156
215
|
const exportInfo = (async () => {
|
|
157
|
-
const program = parseProgram(code);
|
|
216
|
+
const program = parseProgram(code, resourcePath);
|
|
158
217
|
return {
|
|
159
218
|
exportNames: collectProgramExportNames(program),
|
|
160
219
|
exportAllModules: collectExportAllModules(program),
|
|
@@ -163,14 +222,14 @@ export const getExportNamesAndExportAll = async (
|
|
|
163
222
|
|
|
164
223
|
let trackedExportInfo: Promise<ExportInfo>;
|
|
165
224
|
trackedExportInfo = cachePromiseOnReject(exportInfo, () => {
|
|
166
|
-
if (exportInfoCache.get(
|
|
167
|
-
exportInfoCache.delete(
|
|
225
|
+
if (exportInfoCache.get(cacheKey) === trackedExportInfo) {
|
|
226
|
+
exportInfoCache.delete(cacheKey);
|
|
168
227
|
}
|
|
169
228
|
});
|
|
170
229
|
|
|
171
230
|
setBoundedCacheEntry(
|
|
172
231
|
exportInfoCache,
|
|
173
|
-
|
|
232
|
+
cacheKey,
|
|
174
233
|
trackedExportInfo,
|
|
175
234
|
MAX_EXPORT_UTILS_CACHE_ENTRIES
|
|
176
235
|
);
|
package/src/index.ts
CHANGED
|
@@ -11,13 +11,14 @@ import {
|
|
|
11
11
|
import { createJiti } from 'jiti';
|
|
12
12
|
import { relative, resolve } from 'pathe';
|
|
13
13
|
|
|
14
|
+
import { getDefaultConcurrency } from './concurrency.js';
|
|
14
15
|
import {
|
|
15
16
|
BUILD_CLIENT_ROUTE_QUERY_STRING,
|
|
16
17
|
JS_EXTENSIONS,
|
|
17
18
|
PLUGIN_NAME,
|
|
18
19
|
} from './constants.js';
|
|
19
20
|
import { guardReactRouterLazyCompilation } from './lazy-compilation.js';
|
|
20
|
-
import {
|
|
21
|
+
import { createReactRouterDevServerSetup } from './dev-server.js';
|
|
21
22
|
import {
|
|
22
23
|
generateWithProps,
|
|
23
24
|
findEntryFile,
|
|
@@ -37,7 +38,6 @@ import {
|
|
|
37
38
|
import {
|
|
38
39
|
getReactRouterManifestForDev,
|
|
39
40
|
configRoutesToRouteManifest,
|
|
40
|
-
configRoutesToRouteManifestEntries,
|
|
41
41
|
createReactRouterManifestStats,
|
|
42
42
|
type ReactRouterManifestStats,
|
|
43
43
|
type RouteManifestModuleExports,
|
|
@@ -55,14 +55,7 @@ import {
|
|
|
55
55
|
createRouteTransformExecutor,
|
|
56
56
|
shouldParallelizeRouteTransforms,
|
|
57
57
|
} from './parallel-route-transforms.js';
|
|
58
|
-
import {
|
|
59
|
-
createRouteTopologyWatcher,
|
|
60
|
-
createRouteManifestSnapshot,
|
|
61
|
-
ensureDevRestartMarker,
|
|
62
|
-
getRouteRestartMarkerPath,
|
|
63
|
-
mergeWatchFiles,
|
|
64
|
-
type WatchFileConfig,
|
|
65
|
-
} from './route-watch.js';
|
|
58
|
+
import { getRouteRestartMarkerPath, mergeWatchFiles } from './route-watch.js';
|
|
66
59
|
import { validateRouteConfig } from './route-config.js';
|
|
67
60
|
import {
|
|
68
61
|
getBuildManifest,
|
|
@@ -81,15 +74,29 @@ import {
|
|
|
81
74
|
} from './performance.js';
|
|
82
75
|
import { mapVirtualModules } from './virtual-modules.js';
|
|
83
76
|
import { createReactRouterDevRuntimeController } from './dev-runtime-controller.js';
|
|
77
|
+
import { runPluginEffect, tryPluginPromise } from './effect-runtime.js';
|
|
84
78
|
import { registerReactRouterTypegen } from './typegen.js';
|
|
79
|
+
import { importConfigWithWatchPaths } from './config-imports.js';
|
|
85
80
|
import {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
81
|
+
createReactRouterRouteTopology,
|
|
82
|
+
createReactRouterRouteWatchFiles,
|
|
83
|
+
registerReactRouterDevBackgroundResources,
|
|
84
|
+
} from './dev-background-resources.js';
|
|
89
85
|
|
|
90
86
|
export { loadReactRouterServerBuild } from './dev-generation.js';
|
|
91
87
|
export { resolveReactRouterServerBuild };
|
|
92
88
|
|
|
89
|
+
const MIN_PARALLEL_ENVIRONMENT_BUILD_SPARE_CORES = 4;
|
|
90
|
+
|
|
91
|
+
export const shouldParallelizeEnvironmentBuilds = ({
|
|
92
|
+
isBuild,
|
|
93
|
+
spareCoreCount = getDefaultConcurrency(),
|
|
94
|
+
}: {
|
|
95
|
+
isBuild: boolean;
|
|
96
|
+
spareCoreCount?: number;
|
|
97
|
+
}): boolean =>
|
|
98
|
+
!isBuild && spareCoreCount >= MIN_PARALLEL_ENVIRONMENT_BUILD_SPARE_CORES;
|
|
99
|
+
|
|
93
100
|
type ModuleFederationPluginLike = {
|
|
94
101
|
name?: string;
|
|
95
102
|
_options?: { experiments?: { asyncStartup?: boolean } };
|
|
@@ -139,6 +146,7 @@ export const pluginReactRouter = (
|
|
|
139
146
|
async setup(api) {
|
|
140
147
|
const defaultOptions = {
|
|
141
148
|
customServer: false,
|
|
149
|
+
lazyCompilation: true,
|
|
142
150
|
serverOutput: 'module' as const,
|
|
143
151
|
};
|
|
144
152
|
|
|
@@ -181,8 +189,6 @@ export const pluginReactRouter = (
|
|
|
181
189
|
warnOnClientSourceMaps(normalized, msg => api.logger.warn(msg), 'web');
|
|
182
190
|
});
|
|
183
191
|
|
|
184
|
-
registerReactRouterTypegen(api);
|
|
185
|
-
|
|
186
192
|
const configPath = findEntryFile(resolve('react-router.config'));
|
|
187
193
|
const configExists = existsSync(configPath);
|
|
188
194
|
let configWatchPaths: string | string[] = configExists
|
|
@@ -197,22 +203,10 @@ export const pluginReactRouter = (
|
|
|
197
203
|
);
|
|
198
204
|
} else {
|
|
199
205
|
const displayPath = relative(process.cwd(), configPath);
|
|
200
|
-
const configJiti = createJiti(process.cwd(), {
|
|
201
|
-
moduleCache: true,
|
|
202
|
-
});
|
|
203
|
-
const cacheKeysBeforeImport = new Set(Object.keys(configJiti.cache));
|
|
204
206
|
try {
|
|
205
|
-
const imported
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
const importedConfigPaths = collectConfigImportWatchPaths(
|
|
209
|
-
configPath,
|
|
210
|
-
configJiti.cache,
|
|
211
|
-
cacheKeysBeforeImport
|
|
212
|
-
);
|
|
213
|
-
if (importedConfigPaths.length > 0) {
|
|
214
|
-
configWatchPaths = [configPath, ...importedConfigPaths];
|
|
215
|
-
}
|
|
207
|
+
const { value: imported, watchPaths } =
|
|
208
|
+
await importConfigWithWatchPaths<Config>(configPath);
|
|
209
|
+
configWatchPaths = watchPaths;
|
|
216
210
|
if (imported === undefined) {
|
|
217
211
|
throw new Error(`${displayPath} must provide a default export`);
|
|
218
212
|
}
|
|
@@ -222,22 +216,9 @@ export const pluginReactRouter = (
|
|
|
222
216
|
reactRouterUserConfig = imported;
|
|
223
217
|
} catch (error) {
|
|
224
218
|
throw new Error(`Error loading ${displayPath}: ${error}`);
|
|
225
|
-
} finally {
|
|
226
|
-
clearConfigImportCache(configJiti.cache, [
|
|
227
|
-
configPath,
|
|
228
|
-
...collectConfigImportWatchPaths(
|
|
229
|
-
configPath,
|
|
230
|
-
configJiti.cache,
|
|
231
|
-
cacheKeysBeforeImport
|
|
232
|
-
),
|
|
233
|
-
]);
|
|
234
219
|
}
|
|
235
220
|
}
|
|
236
221
|
|
|
237
|
-
const jiti = createJiti(process.cwd(), {
|
|
238
|
-
moduleCache: false,
|
|
239
|
-
});
|
|
240
|
-
|
|
241
222
|
const {
|
|
242
223
|
resolved: resolvedConfig,
|
|
243
224
|
presets: configPresets,
|
|
@@ -259,6 +240,8 @@ export const pluginReactRouter = (
|
|
|
259
240
|
buildEnd,
|
|
260
241
|
} = resolvedConfig;
|
|
261
242
|
|
|
243
|
+
registerReactRouterTypegen(api, { appDirectory });
|
|
244
|
+
|
|
262
245
|
const hasExplicitServerOutput = Object.prototype.hasOwnProperty.call(
|
|
263
246
|
options,
|
|
264
247
|
'serverOutput'
|
|
@@ -334,8 +317,13 @@ export const pluginReactRouter = (
|
|
|
334
317
|
);
|
|
335
318
|
}
|
|
336
319
|
|
|
337
|
-
const
|
|
338
|
-
|
|
320
|
+
const jiti = createJiti(process.cwd(), {
|
|
321
|
+
moduleCache: false,
|
|
322
|
+
});
|
|
323
|
+
const importRouteConfig = async (
|
|
324
|
+
importer: Pick<typeof jiti, 'import'>
|
|
325
|
+
): Promise<RouteConfigEntry[]> => {
|
|
326
|
+
const routeConfigExport = await importer.import<RouteConfigEntry[]>(
|
|
339
327
|
routesPath,
|
|
340
328
|
{
|
|
341
329
|
default: true,
|
|
@@ -351,7 +339,9 @@ export const pluginReactRouter = (
|
|
|
351
339
|
}
|
|
352
340
|
return validation.routeConfig;
|
|
353
341
|
};
|
|
354
|
-
const
|
|
342
|
+
const loadRouteConfig = () => importRouteConfig(jiti);
|
|
343
|
+
const { value: routeConfig, watchPaths: routeConfigWatchPaths } =
|
|
344
|
+
await importConfigWithWatchPaths(routesPath, importRouteConfig);
|
|
355
345
|
|
|
356
346
|
const entryClientPath = findEntryFile(
|
|
357
347
|
resolve(appDirectory, 'entry.client')
|
|
@@ -384,22 +374,13 @@ export const pluginReactRouter = (
|
|
|
384
374
|
// React Router's server build expects route files relative to `appDirectory`
|
|
385
375
|
// so it can resolve them correctly during compilation.
|
|
386
376
|
const rootRouteFile = relative(appDirectory, rootRoutePath);
|
|
387
|
-
const
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
]);
|
|
395
|
-
const getWatchedRouteTopology = async (): Promise<Set<string>> => {
|
|
396
|
-
const latestRouteConfig = await loadRouteConfig();
|
|
397
|
-
const latestRootRouteFile = relative(appDirectory, getRootRoutePath());
|
|
398
|
-
return createRouteTopologySnapshot(
|
|
399
|
-
latestRootRouteFile,
|
|
400
|
-
latestRouteConfig
|
|
401
|
-
);
|
|
402
|
-
};
|
|
377
|
+
const routeTopology = createReactRouterRouteTopology({
|
|
378
|
+
appDirectory,
|
|
379
|
+
rootRouteFile,
|
|
380
|
+
routeConfig,
|
|
381
|
+
loadRouteConfig,
|
|
382
|
+
getRootRoutePath,
|
|
383
|
+
});
|
|
403
384
|
|
|
404
385
|
const routes = {
|
|
405
386
|
root: { path: '', id: 'root', file: rootRouteFile },
|
|
@@ -426,6 +407,9 @@ export const pluginReactRouter = (
|
|
|
426
407
|
}
|
|
427
408
|
|
|
428
409
|
const isBuild = api.context.action === 'build';
|
|
410
|
+
const shouldDependOnWebCompiler = !shouldParallelizeEnvironmentBuilds({
|
|
411
|
+
isBuild,
|
|
412
|
+
});
|
|
429
413
|
const isPrerenderEnabled =
|
|
430
414
|
prerenderConfig !== undefined && prerenderConfig !== false;
|
|
431
415
|
const isSpaMode = !ssr && !isPrerenderEnabled;
|
|
@@ -442,6 +426,7 @@ export const pluginReactRouter = (
|
|
|
442
426
|
shouldParallelizeRouteTransforms(routeCount),
|
|
443
427
|
routeChunkCache,
|
|
444
428
|
splitRouteModules: Boolean(splitRouteModules),
|
|
429
|
+
isBuild,
|
|
445
430
|
});
|
|
446
431
|
const routeChunkOptions = {
|
|
447
432
|
splitRouteModules,
|
|
@@ -453,56 +438,22 @@ export const pluginReactRouter = (
|
|
|
453
438
|
const assetsBuildDirectory = relative(process.cwd(), outputClientPath);
|
|
454
439
|
const watchDirectory = resolve(appDirectory);
|
|
455
440
|
const routeRestartMarkerPath = getRouteRestartMarkerPath(outputClientPath);
|
|
456
|
-
const
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
paths: routesPath,
|
|
462
|
-
type: 'reload-server',
|
|
463
|
-
},
|
|
464
|
-
{
|
|
465
|
-
paths: routeRestartMarkerPath,
|
|
466
|
-
type: 'reload-server',
|
|
467
|
-
},
|
|
468
|
-
];
|
|
469
|
-
const routeWatchFiles: WatchFileConfig[] = [
|
|
470
|
-
{
|
|
471
|
-
paths: configWatchPaths,
|
|
472
|
-
type: 'reload-server',
|
|
473
|
-
},
|
|
474
|
-
...routeTopologyWatchFiles,
|
|
475
|
-
];
|
|
476
|
-
let closeRouteTopologyWatcher: (() => Promise<void>) | undefined;
|
|
477
|
-
|
|
478
|
-
api.onBeforeStartDevServer(async () => {
|
|
479
|
-
await ensureDevRestartMarker(routeRestartMarkerPath);
|
|
480
|
-
closeRouteTopologyWatcher = await createRouteTopologyWatcher({
|
|
481
|
-
watchDirectory,
|
|
482
|
-
getRouteTopology: getWatchedRouteTopology,
|
|
483
|
-
initialRouteTopology: createRouteTopologySnapshot(
|
|
484
|
-
rootRouteFile,
|
|
485
|
-
routeConfig
|
|
486
|
-
),
|
|
487
|
-
restartMarkerPath: routeRestartMarkerPath,
|
|
488
|
-
onRouteTopologyChange: pluginOptions.onRouteTopologyChange,
|
|
489
|
-
onError: error => {
|
|
490
|
-
api.logger.warn(
|
|
491
|
-
`[${PLUGIN_NAME}] Failed to watch route topology changes: ${error}`
|
|
492
|
-
);
|
|
493
|
-
},
|
|
494
|
-
});
|
|
495
|
-
});
|
|
496
|
-
|
|
497
|
-
api.onCloseDevServer(async () => {
|
|
498
|
-
await closeRouteTopologyWatcher?.();
|
|
499
|
-
closeRouteTopologyWatcher = undefined;
|
|
500
|
-
});
|
|
501
|
-
api.onCloseBuild(async () => {
|
|
502
|
-
await routeTransformExecutor.close();
|
|
441
|
+
const routeWatchFiles = createReactRouterRouteWatchFiles({
|
|
442
|
+
configWatchPaths,
|
|
443
|
+
routeConfigWatchPaths,
|
|
444
|
+
routeRestartMarkerPath,
|
|
445
|
+
onRouteTopologyChange: pluginOptions.onRouteTopologyChange,
|
|
503
446
|
});
|
|
504
|
-
|
|
505
|
-
|
|
447
|
+
const devBackgroundResources = registerReactRouterDevBackgroundResources({
|
|
448
|
+
api,
|
|
449
|
+
isBuild,
|
|
450
|
+
lazyCompilationPrewarm: pluginOptions.unstableLazyCompilationPrewarm,
|
|
451
|
+
routeTransformExecutor,
|
|
452
|
+
routeRestartMarkerPath,
|
|
453
|
+
watchDirectory,
|
|
454
|
+
getRouteTopology: routeTopology.getRouteTopology,
|
|
455
|
+
initialRouteTopology: routeTopology.initialRouteTopology,
|
|
456
|
+
onRouteTopologyChange: pluginOptions.onRouteTopologyChange,
|
|
506
457
|
});
|
|
507
458
|
|
|
508
459
|
type ReactRouterManifest = Awaited<
|
|
@@ -526,6 +477,7 @@ export const pluginReactRouter = (
|
|
|
526
477
|
'virtual/react-router/browser-manifest',
|
|
527
478
|
() => {
|
|
528
479
|
latestBrowserManifest = manifest;
|
|
480
|
+
devBackgroundResources.setManifest(manifest);
|
|
529
481
|
latestBrowserManifestModuleExports = moduleExportsByRouteId;
|
|
530
482
|
const baseServerManifest = {
|
|
531
483
|
...manifest,
|
|
@@ -662,31 +614,35 @@ export const pluginReactRouter = (
|
|
|
662
614
|
}
|
|
663
615
|
);
|
|
664
616
|
|
|
665
|
-
api.onAfterBuild(
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
617
|
+
api.onAfterBuild(({ environments }) =>
|
|
618
|
+
runPluginEffect(
|
|
619
|
+
tryPluginPromise(() =>
|
|
620
|
+
runReactRouterPrerenderBuild({
|
|
621
|
+
api,
|
|
622
|
+
hasWebEnvironment: Boolean(environments.web),
|
|
623
|
+
buildDirectory,
|
|
624
|
+
serverBuildFile,
|
|
625
|
+
ssr,
|
|
626
|
+
isPrerenderEnabled,
|
|
627
|
+
prerenderConfig,
|
|
628
|
+
prerenderPaths,
|
|
629
|
+
basename,
|
|
630
|
+
future,
|
|
631
|
+
routes,
|
|
632
|
+
latestBrowserManifest,
|
|
633
|
+
latestBrowserManifestModuleExports,
|
|
634
|
+
clientStats,
|
|
635
|
+
pluginOptions,
|
|
636
|
+
appDirectory,
|
|
637
|
+
assetPrefix,
|
|
638
|
+
routeChunkOptions,
|
|
639
|
+
buildManifest,
|
|
640
|
+
resolvedConfigWithRoutes,
|
|
641
|
+
buildEnd,
|
|
642
|
+
})
|
|
643
|
+
)
|
|
644
|
+
)
|
|
645
|
+
);
|
|
690
646
|
|
|
691
647
|
const allowedActionOriginsForBuild =
|
|
692
648
|
allowedActionOrigins === false ? undefined : allowedActionOrigins;
|
|
@@ -770,13 +726,18 @@ export const pluginReactRouter = (
|
|
|
770
726
|
serverBundleEntries,
|
|
771
727
|
});
|
|
772
728
|
|
|
773
|
-
const configuredLazyCompilation =
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
729
|
+
const configuredLazyCompilation = Object.prototype.hasOwnProperty.call(
|
|
730
|
+
options,
|
|
731
|
+
'lazyCompilation'
|
|
732
|
+
)
|
|
733
|
+
? pluginOptions.lazyCompilation
|
|
734
|
+
: (config.dev?.lazyCompilation ?? pluginOptions.lazyCompilation);
|
|
777
735
|
const guardedLazyCompilation = guardReactRouterLazyCompilation({
|
|
778
736
|
lazyCompilation: configuredLazyCompilation,
|
|
779
737
|
entryClientPath: finalEntryClientPath,
|
|
738
|
+
prewarmReactRouterModules: Boolean(
|
|
739
|
+
pluginOptions.unstableLazyCompilationPrewarm
|
|
740
|
+
),
|
|
780
741
|
});
|
|
781
742
|
const lazyCompilation =
|
|
782
743
|
guardedLazyCompilation === undefined
|
|
@@ -807,19 +768,23 @@ export const pluginReactRouter = (
|
|
|
807
768
|
writeToDisk: true,
|
|
808
769
|
...lazyCompilation,
|
|
809
770
|
watchFiles: mergeWatchFiles(config.dev?.watchFiles, routeWatchFiles),
|
|
810
|
-
setupMiddlewares:
|
|
811
|
-
pluginOptions.customServer || !ssr
|
|
812
|
-
? []
|
|
813
|
-
: [
|
|
814
|
-
middlewares => {
|
|
815
|
-
middlewares.push(
|
|
816
|
-
createDevServerMiddleware({
|
|
817
|
-
loadBuild: devRuntime.createBuildLoader(),
|
|
818
|
-
})
|
|
819
|
-
);
|
|
820
|
-
},
|
|
821
|
-
],
|
|
822
771
|
},
|
|
772
|
+
// React Router's request handler natively supports `ssr:false`
|
|
773
|
+
// builds (it renders the SPA shell for document requests), so the
|
|
774
|
+
// middleware is registered for SPA mode too — without it, dev
|
|
775
|
+
// requests would 404 because no HTML entry exists.
|
|
776
|
+
...(pluginOptions.customServer
|
|
777
|
+
? {}
|
|
778
|
+
: {
|
|
779
|
+
server: {
|
|
780
|
+
setup: [
|
|
781
|
+
createReactRouterDevServerSetup({
|
|
782
|
+
// Lazy: the dev runtime binding does not exist yet here.
|
|
783
|
+
loadBuild: () => devRuntime.createBuildLoader()(),
|
|
784
|
+
}),
|
|
785
|
+
],
|
|
786
|
+
},
|
|
787
|
+
}),
|
|
823
788
|
tools: {
|
|
824
789
|
rspack: {
|
|
825
790
|
plugins: [vmodPlugin],
|
|
@@ -919,7 +884,7 @@ export const pluginReactRouter = (
|
|
|
919
884
|
],
|
|
920
885
|
},
|
|
921
886
|
externals: nodeExternals,
|
|
922
|
-
dependencies: ['web'],
|
|
887
|
+
...(shouldDependOnWebCompiler ? { dependencies: ['web'] } : {}),
|
|
923
888
|
externalsType: resolvedServerOutput,
|
|
924
889
|
output: {
|
|
925
890
|
chunkFormat: resolvedServerOutput,
|