rsbuild-plugin-react-router 0.6.2 → 0.6.4
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/dist/511.js +1 -1
- package/dist/index.cjs +26 -18
- package/dist/index.js +23 -15
- package/dist/react-router-config.d.ts +1 -0
- package/dist/route-chunks.d.ts +1 -3
- package/package.json +8 -8
- package/src/classic-mode.ts +17 -5
- package/src/index.ts +1 -5
- package/src/manifest.ts +24 -37
- package/src/react-router-config.ts +5 -0
- package/src/route-chunks.ts +6 -10
package/dist/511.js
CHANGED
|
@@ -679,7 +679,7 @@ let mightContainRouteChunkExportName = (source)=>routeChunkExportNames.some((exp
|
|
|
679
679
|
invalidChunks.map((name)=>`- ${name}`).join('\n'),
|
|
680
680
|
`${plural ? 'These exports' : 'This export'} could not be split into ${plural ? 'their own chunks' : 'its own chunk'} because ${plural ? 'they share' : 'it shares'} code with other exports. You should extract any shared code into its own module and then import it within the route module.`
|
|
681
681
|
].join('\n\n'));
|
|
682
|
-
}, getRouteEntryBaseName = (route, appDirectory)=>normalizeRelativeFilePath(route.file, appDirectory).replace(/^[A-Za-z]:/, '').split('/').filter((segment)=>'' !== segment && '.' !== segment).map((segment)=>'..' === segment ? '__' : segment).join('/')
|
|
682
|
+
}, getRouteEntryBaseName = (route, appDirectory)=>createRouteId(normalizeRelativeFilePath(route.file, appDirectory).replace(/^[A-Za-z]:/, '').split('/').filter((segment)=>'' !== segment && '.' !== segment).map((segment)=>'..' === segment ? '__' : segment).join('/')), getRouteChunkEntryName = (routeEntryBaseName, chunkName)=>`${routeEntryBaseName}-${routeChunkEntrySuffix[chunkName]}`, setBoundedCacheEntry = (cache, key, value, maxEntries)=>{
|
|
683
683
|
if (maxEntries <= 0) return void cache.clear();
|
|
684
684
|
if (!cache.has(key) && cache.size >= maxEntries) {
|
|
685
685
|
let oldestEntry = cache.keys().next();
|
package/dist/index.cjs
CHANGED
|
@@ -11665,7 +11665,7 @@ const external_react_router_namespaceObject = require("react-router"), normalize
|
|
|
11665
11665
|
invalidChunks.map((name)=>`- ${name}`).join('\n'),
|
|
11666
11666
|
`${plural ? 'These exports' : 'This export'} could not be split into ${plural ? 'their own chunks' : 'its own chunk'} because ${plural ? 'they share' : 'it shares'} code with other exports. You should extract any shared code into its own module and then import it within the route module.`
|
|
11667
11667
|
].join('\n\n'));
|
|
11668
|
-
}, getRouteEntryBaseName = (route, appDirectory)=>toSafeEntryPath(normalizeRelativeFilePath(route.file, appDirectory))
|
|
11668
|
+
}, getRouteEntryBaseName = (route, appDirectory)=>createRouteId(toSafeEntryPath(normalizeRelativeFilePath(route.file, appDirectory))), getRouteChunkEntryName = (routeEntryBaseName, chunkName)=>`${routeEntryBaseName}-${routeChunkEntrySuffix[chunkName]}`, setBoundedCacheEntry = (cache1, key, value, maxEntries)=>{
|
|
11669
11669
|
if (maxEntries <= 0) return void cache1.clear();
|
|
11670
11670
|
if (!cache1.has(key) && cache1.size >= maxEntries) {
|
|
11671
11671
|
let oldestEntry = cache1.keys().next();
|
|
@@ -11872,16 +11872,25 @@ const createReactRouterManifestOptions = ({ routeChunks, routeModuleAnalysis })=
|
|
|
11872
11872
|
if (!isBuild) return 'static/js/virtual/react-router/browser-manifest.js';
|
|
11873
11873
|
let dir = getManifestDirFromEntryAsset(entryModulePath);
|
|
11874
11874
|
return `${dir}/manifest-${version}.js`;
|
|
11875
|
-
},
|
|
11875
|
+
}, getReactRouterManifestChunkNames = (routes, appDirectory, splitRouteModules = !1)=>{
|
|
11876
11876
|
let chunkNames = new Set([
|
|
11877
11877
|
'entry.client'
|
|
11878
11878
|
]);
|
|
11879
|
-
for (let route of Object.values(routes))
|
|
11879
|
+
for (let route of Object.values(routes)){
|
|
11880
|
+
let routeEntryName = getRouteEntryBaseName(route, appDirectory);
|
|
11881
|
+
if (chunkNames.add(routeEntryName), splitRouteModules && 'root' !== route.id) for (let exportName of routeChunkExportNames)chunkNames.add(getRouteChunkEntryName(routeEntryName, exportName));
|
|
11882
|
+
}
|
|
11880
11883
|
return chunkNames;
|
|
11881
|
-
}, createRouteManifestItem = ({ route,
|
|
11882
|
-
let routeChunkMap = routeAnalysis.hasRouteChunkByExportName,
|
|
11884
|
+
}, createRouteManifestItem = ({ route, routeEntryName, assetPrefix, jsAssets, routeAnalysis, getModulePathForChunk, getCssAssetsForChunk })=>{
|
|
11885
|
+
let routeChunkMap = routeAnalysis.hasRouteChunkByExportName, chunkEntryName = (exportName)=>routeChunkMap?.[exportName] ? getRouteChunkEntryName(routeEntryName, exportName) : void 0, chunkModulePath = (exportName)=>{
|
|
11886
|
+
let name = chunkEntryName(exportName);
|
|
11887
|
+
return name ? getModulePathForChunk(name) : void 0;
|
|
11888
|
+
}, cssAssets = [
|
|
11883
11889
|
...routeAnalysis.cssAssets,
|
|
11884
|
-
...routeChunkExportNames.flatMap((exportName)=>
|
|
11890
|
+
...routeChunkExportNames.flatMap((exportName)=>{
|
|
11891
|
+
let name = chunkEntryName(exportName);
|
|
11892
|
+
return name ? getCssAssetsForChunk(name) : [];
|
|
11893
|
+
})
|
|
11885
11894
|
];
|
|
11886
11895
|
return {
|
|
11887
11896
|
id: route.id,
|
|
@@ -11933,7 +11942,7 @@ function generateReactRouterManifestForDevEffect(routes, clientStats, context, a
|
|
|
11933
11942
|
key,
|
|
11934
11943
|
createRouteManifestItem({
|
|
11935
11944
|
route,
|
|
11936
|
-
|
|
11945
|
+
routeEntryName,
|
|
11937
11946
|
assetPrefix,
|
|
11938
11947
|
jsAssets,
|
|
11939
11948
|
routeAnalysis,
|
|
@@ -11953,7 +11962,7 @@ function generateReactRouterManifestForDevEffect(routes, clientStats, context, a
|
|
|
11953
11962
|
css: entryCssAssets.map((asset)=>combineURLs(assetPrefix, asset))
|
|
11954
11963
|
},
|
|
11955
11964
|
routes: result
|
|
11956
|
-
}, version =
|
|
11965
|
+
}, version = (0, external_node_crypto_namespaceObject.createHash)('md5').update(JSON.stringify(fingerprintedValues)).digest('hex').slice(0, 8), manifestPath = getReactRouterManifestPath({
|
|
11957
11966
|
version,
|
|
11958
11967
|
isBuild,
|
|
11959
11968
|
entryModulePath: entryJsAssets[0]
|
|
@@ -12305,6 +12314,7 @@ const redirectStatusCodes = new Set([
|
|
|
12305
12314
|
if (manifestPath && !manifestPath.startsWith('/')) throw Error('The `routeDiscovery.manifestPath` config must be a root-relative pathname beginning with a slash (i.e., "/__manifest")');
|
|
12306
12315
|
return userRouteDiscovery;
|
|
12307
12316
|
}, createDefaultFutureConfig = ()=>({
|
|
12317
|
+
unstable_enableNodeReadableStream: !1,
|
|
12308
12318
|
unstable_optimizeDeps: !1,
|
|
12309
12319
|
unstable_subResourceIntegrity: !1,
|
|
12310
12320
|
unstable_trailingSlashAwareDataRequests: getDefaultTrailingSlashAwareDataRequests(),
|
|
@@ -15476,9 +15486,10 @@ export {
|
|
|
15476
15486
|
}, createClassicWebRouteEntries = ({ appDirectory, isBuild, routes, splitRouteModules })=>{
|
|
15477
15487
|
let manifestChunkNames = new Set([
|
|
15478
15488
|
'entry.client'
|
|
15479
|
-
]), webRouteEntries = Object.values(routes).reduce((acc, route)=>{
|
|
15480
|
-
let entryName = getRouteEntryBaseName(route, appDirectory), routeFilePath = (0, external_pathe_namespaceObject.resolve)(appDirectory, route.file);
|
|
15481
|
-
if (
|
|
15489
|
+
]), routeFileByEntryName = new Map(), webRouteEntries = Object.values(routes).reduce((acc, route)=>{
|
|
15490
|
+
let entryName = getRouteEntryBaseName(route, appDirectory), routeFilePath = (0, external_pathe_namespaceObject.resolve)(appDirectory, route.file), existingRouteFile = routeFileByEntryName.get(entryName);
|
|
15491
|
+
if (void 0 !== existingRouteFile && existingRouteFile !== routeFilePath) throw Error(`[rsbuild-plugin-react-router] Route files ${JSON.stringify(existingRouteFile)} and ${JSON.stringify(routeFilePath)} both resolve to the entry name ${JSON.stringify(entryName)}. Rename one of them so their paths relative to the app directory differ.`);
|
|
15492
|
+
if (routeFileByEntryName.set(entryName, routeFilePath), manifestChunkNames.add(entryName), acc[entryName] = {
|
|
15482
15493
|
import: `${routeFilePath}${BUILD_CLIENT_ROUTE_QUERY_STRING}`,
|
|
15483
15494
|
html: !1
|
|
15484
15495
|
}, isBuild && splitRouteModules && 'root' !== route.id) {
|
|
@@ -15491,7 +15502,7 @@ export {
|
|
|
15491
15502
|
}
|
|
15492
15503
|
for (let exportName of routeChunkExportNames){
|
|
15493
15504
|
if (!source.includes(exportName)) continue;
|
|
15494
|
-
let chunkEntryName = getRouteChunkEntryName(
|
|
15505
|
+
let chunkEntryName = getRouteChunkEntryName(entryName, exportName);
|
|
15495
15506
|
manifestChunkNames.add(chunkEntryName), acc[chunkEntryName] = {
|
|
15496
15507
|
import: getRouteChunkModuleId(routeFilePath, exportName),
|
|
15497
15508
|
html: !1
|
|
@@ -15813,7 +15824,7 @@ export {
|
|
|
15813
15824
|
throw Error(`Error loading ${displayPath}: ${error}`);
|
|
15814
15825
|
}
|
|
15815
15826
|
} else console.warn('No react-router.config found, using default configuration.');
|
|
15816
|
-
let { resolved: resolvedConfig,
|
|
15827
|
+
let { resolved: resolvedConfig, presets: configPresets, hasConfiguredServerModuleFormat } = await effectRuntime.runPromise(resolveReactRouterConfigEffect(reactRouterUserConfig)), { appDirectory, basename, buildDirectory, future, allowedActionOrigins, routeDiscovery: userRouteDiscovery, ssr, prerender: prerenderConfig, serverBuildFile, serverBundles, serverModuleFormat, splitRouteModules, subResourceIntegrity, buildEnd } = resolvedConfig;
|
|
15817
15828
|
await registerReactRouterTypegen(api, {
|
|
15818
15829
|
runtime: effectRuntime,
|
|
15819
15830
|
appDirectory
|
|
@@ -15909,10 +15920,7 @@ export {
|
|
|
15909
15920
|
for (let preset of configPresets)await preset.reactRouterConfigResolved?.({
|
|
15910
15921
|
reactRouterConfig: resolvedConfigForPreset
|
|
15911
15922
|
});
|
|
15912
|
-
let
|
|
15913
|
-
...resolvedConfigWithRoutes,
|
|
15914
|
-
future: userAndPresetConfig.future ?? {}
|
|
15915
|
-
}, isBuild = 'build' === api.context.action;
|
|
15923
|
+
let isBuild = 'build' === api.context.action;
|
|
15916
15924
|
isBuild || api.onAfterEnvironmentCompile(({ environment, stats })=>{
|
|
15917
15925
|
'node' === environment.name && stats && !stats.hasErrors() && registerDevServerSourceMaps(stats.compilation);
|
|
15918
15926
|
});
|
|
@@ -16056,7 +16064,7 @@ export {
|
|
|
16056
16064
|
routeChunkOptions: modePlan.routeChunkOptions,
|
|
16057
16065
|
routeModuleAnalysis,
|
|
16058
16066
|
buildManifest: modePlan.artifacts.buildManifest,
|
|
16059
|
-
buildEndReactRouterConfig,
|
|
16067
|
+
buildEndReactRouterConfig: resolvedConfigWithRoutes,
|
|
16060
16068
|
buildEnd
|
|
16061
16069
|
})))) : api.onAfterBuild(({ environments })=>effectRuntime.runPromise(tryPluginPromise(()=>runReactRouterRscPrerenderBuild({
|
|
16062
16070
|
api,
|
package/dist/index.js
CHANGED
|
@@ -7463,10 +7463,16 @@ async function generateReactRouterManifestForDev(routes, _options, clientStats,
|
|
|
7463
7463
|
valid: buildManifestChunkValidity(routeAnalysis.exports, routeAnalysis.hasRouteChunkByExportName ?? createEmptyRouteChunkByExportName())
|
|
7464
7464
|
}), [
|
|
7465
7465
|
key,
|
|
7466
|
-
(({ route,
|
|
7467
|
-
let routeChunkMap = routeAnalysis.hasRouteChunkByExportName,
|
|
7466
|
+
(({ route, routeEntryName, assetPrefix, jsAssets, routeAnalysis, getModulePathForChunk, getCssAssetsForChunk })=>{
|
|
7467
|
+
let routeChunkMap = routeAnalysis.hasRouteChunkByExportName, chunkEntryName = (exportName)=>routeChunkMap?.[exportName] ? getRouteChunkEntryName(routeEntryName, exportName) : void 0, chunkModulePath = (exportName)=>{
|
|
7468
|
+
let name = chunkEntryName(exportName);
|
|
7469
|
+
return name ? getModulePathForChunk(name) : void 0;
|
|
7470
|
+
}, cssAssets = [
|
|
7468
7471
|
...routeAnalysis.cssAssets,
|
|
7469
|
-
...routeChunkExportNames.flatMap((exportName)=>
|
|
7472
|
+
...routeChunkExportNames.flatMap((exportName)=>{
|
|
7473
|
+
let name = chunkEntryName(exportName);
|
|
7474
|
+
return name ? getCssAssetsForChunk(name) : [];
|
|
7475
|
+
})
|
|
7470
7476
|
];
|
|
7471
7477
|
return {
|
|
7472
7478
|
id: route.id,
|
|
@@ -7491,7 +7497,7 @@ async function generateReactRouterManifestForDev(routes, _options, clientStats,
|
|
|
7491
7497
|
};
|
|
7492
7498
|
})({
|
|
7493
7499
|
route,
|
|
7494
|
-
|
|
7500
|
+
routeEntryName,
|
|
7495
7501
|
assetPrefix: assetPrefix,
|
|
7496
7502
|
jsAssets,
|
|
7497
7503
|
routeAnalysis,
|
|
@@ -7874,6 +7880,7 @@ let redirectStatusCodes = new Set([
|
|
|
7874
7880
|
subResourceIntegrity: !1,
|
|
7875
7881
|
ssr: !0,
|
|
7876
7882
|
future: {
|
|
7883
|
+
unstable_enableNodeReadableStream: !1,
|
|
7877
7884
|
unstable_optimizeDeps: !1,
|
|
7878
7885
|
unstable_subResourceIntegrity: !1,
|
|
7879
7886
|
unstable_trailingSlashAwareDataRequests: ((reactRouterVersion = getPackageVersion('react-router'))=>(parseVersionMajorMinor(reactRouterVersion)?.major ?? 0) >= 8)(),
|
|
@@ -9741,9 +9748,10 @@ export {
|
|
|
9741
9748
|
let reactRouterPath, reactRouterDomPath, { manifestChunkNames, webRouteEntries } = (({ appDirectory, isBuild, routes, splitRouteModules })=>{
|
|
9742
9749
|
let manifestChunkNames = new Set([
|
|
9743
9750
|
'entry.client'
|
|
9744
|
-
]), webRouteEntries = Object.values(routes).reduce((acc, route)=>{
|
|
9745
|
-
let entryName = getRouteEntryBaseName(route, appDirectory), routeFilePath = external_pathe_resolve(appDirectory, route.file);
|
|
9746
|
-
if (
|
|
9751
|
+
]), routeFileByEntryName = new Map(), webRouteEntries = Object.values(routes).reduce((acc, route)=>{
|
|
9752
|
+
let entryName = getRouteEntryBaseName(route, appDirectory), routeFilePath = external_pathe_resolve(appDirectory, route.file), existingRouteFile = routeFileByEntryName.get(entryName);
|
|
9753
|
+
if (void 0 !== existingRouteFile && existingRouteFile !== routeFilePath) throw Error(`[rsbuild-plugin-react-router] Route files ${JSON.stringify(existingRouteFile)} and ${JSON.stringify(routeFilePath)} both resolve to the entry name ${JSON.stringify(entryName)}. Rename one of them so their paths relative to the app directory differ.`);
|
|
9754
|
+
if (routeFileByEntryName.set(entryName, routeFilePath), manifestChunkNames.add(entryName), acc[entryName] = {
|
|
9747
9755
|
import: `${routeFilePath}${BUILD_CLIENT_ROUTE_QUERY_STRING}`,
|
|
9748
9756
|
html: !1
|
|
9749
9757
|
}, isBuild && splitRouteModules && 'root' !== route.id) {
|
|
@@ -9756,7 +9764,7 @@ export {
|
|
|
9756
9764
|
}
|
|
9757
9765
|
for (let exportName of routeChunkExportNames){
|
|
9758
9766
|
if (!source.includes(exportName)) continue;
|
|
9759
|
-
let chunkEntryName = getRouteChunkEntryName(
|
|
9767
|
+
let chunkEntryName = getRouteChunkEntryName(entryName, exportName);
|
|
9760
9768
|
manifestChunkNames.add(chunkEntryName), acc[chunkEntryName] = {
|
|
9761
9769
|
import: getRouteChunkModuleId(routeFilePath, exportName),
|
|
9762
9770
|
html: !1
|
|
@@ -10110,7 +10118,7 @@ export {
|
|
|
10110
10118
|
throw Error(`Error loading ${displayPath}: ${error}`);
|
|
10111
10119
|
}
|
|
10112
10120
|
} else console.warn('No react-router.config found, using default configuration.');
|
|
10113
|
-
let { resolved: resolvedConfig,
|
|
10121
|
+
let { resolved: resolvedConfig, presets: configPresets, hasConfiguredServerModuleFormat } = await effectRuntime.runPromise((reactRouterUserConfig = reactRouterUserConfig1, core_gen(function*() {
|
|
10114
10122
|
let userAndPresetConfigs = ((...configs)=>configs.reduce((configA, configB)=>{
|
|
10115
10123
|
let mergeRequired = (key)=>void 0 !== configA[key] && void 0 !== configB[key];
|
|
10116
10124
|
return {
|
|
@@ -10392,10 +10400,7 @@ export {
|
|
|
10392
10400
|
for (let preset of configPresets)await preset.reactRouterConfigResolved?.({
|
|
10393
10401
|
reactRouterConfig: resolvedConfigForPreset
|
|
10394
10402
|
});
|
|
10395
|
-
let
|
|
10396
|
-
...resolvedConfigWithRoutes,
|
|
10397
|
-
future: userAndPresetConfig.future ?? {}
|
|
10398
|
-
}, isBuild = 'build' === api.context.action;
|
|
10403
|
+
let isBuild = 'build' === api.context.action;
|
|
10399
10404
|
isBuild || api.onAfterEnvironmentCompile(({ environment, stats })=>{
|
|
10400
10405
|
'node' === environment.name && stats && !stats.hasErrors() && ((compilation)=>{
|
|
10401
10406
|
let outputPath = compilation.outputOptions.path;
|
|
@@ -10909,7 +10914,7 @@ if (typeof window !== 'undefined' && import.meta.webpackHot) {
|
|
|
10909
10914
|
routeChunkOptions: modePlan.routeChunkOptions,
|
|
10910
10915
|
routeModuleAnalysis,
|
|
10911
10916
|
buildManifest: modePlan.artifacts.buildManifest,
|
|
10912
|
-
buildEndReactRouterConfig,
|
|
10917
|
+
buildEndReactRouterConfig: resolvedConfigWithRoutes,
|
|
10913
10918
|
buildEnd
|
|
10914
10919
|
})))) : api.onAfterBuild(({ environments })=>effectRuntime.runPromise(tryPluginPromise(()=>runReactRouterRscPrerenderBuild({
|
|
10915
10920
|
api,
|
|
@@ -11253,7 +11258,10 @@ if (typeof window !== 'undefined' && import.meta.webpackHot) {
|
|
|
11253
11258
|
let chunkNames = new Set([
|
|
11254
11259
|
'entry.client'
|
|
11255
11260
|
]);
|
|
11256
|
-
for (let route of Object.values(routes))
|
|
11261
|
+
for (let route of Object.values(routes)){
|
|
11262
|
+
let routeEntryName = getRouteEntryBaseName(route, appDirectory);
|
|
11263
|
+
if (chunkNames.add(routeEntryName), splitRouteModules && 'root' !== route.id) for (let exportName of routeChunkExportNames)chunkNames.add(getRouteChunkEntryName(routeEntryName, exportName));
|
|
11264
|
+
}
|
|
11257
11265
|
return chunkNames;
|
|
11258
11266
|
})(routes, appDirectory, routeChunkOptions?.splitRouteModules), isBuild = !!routeChunkOptions?.isBuild, finalizeSri = !!(isBuild && (options?.subResourceIntegrity ?? options?.future?.unstable_subResourceIntegrity)), buildAndEmitManifest = async ({ assets, sources, compilation }, { withSri })=>{
|
|
11259
11267
|
let currentAssetPrefix = getAssetPrefix(), stats = createReactRouterManifestStats(compilation, manifestChunkNames), { manifest, moduleExportsByRouteId } = await generateReactRouterManifestForDev(routes, pluginOptions, stats, appDirectory, currentAssetPrefix, createReactRouterManifestOptions({
|
|
@@ -19,6 +19,7 @@ export type Config = Omit<ReactRouterConfig, 'buildEnd' | 'future' | 'prerender'
|
|
|
19
19
|
subResourceIntegrity?: boolean;
|
|
20
20
|
};
|
|
21
21
|
type FutureConfig = {
|
|
22
|
+
unstable_enableNodeReadableStream: boolean;
|
|
22
23
|
unstable_optimizeDeps: boolean;
|
|
23
24
|
unstable_subResourceIntegrity: boolean;
|
|
24
25
|
unstable_trailingSlashAwareDataRequests: boolean;
|
package/dist/route-chunks.d.ts
CHANGED
|
@@ -40,7 +40,5 @@ export declare const validateRouteChunks: (args: {
|
|
|
40
40
|
export declare const getRouteEntryBaseName: (route: {
|
|
41
41
|
file: string;
|
|
42
42
|
}, appDirectory: string) => string;
|
|
43
|
-
export declare const getRouteChunkEntryName: (
|
|
44
|
-
file: string;
|
|
45
|
-
}, chunkName: RouteChunkExportName, appDirectory: string) => string;
|
|
43
|
+
export declare const getRouteChunkEntryName: (routeEntryBaseName: string, chunkName: RouteChunkExportName) => string;
|
|
46
44
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rsbuild-plugin-react-router",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.4",
|
|
4
4
|
"description": "React Router plugin for Rsbuild",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -81,11 +81,11 @@
|
|
|
81
81
|
"@codspeed/vitest-plugin": "^5.7.1",
|
|
82
82
|
"@jridgewell/trace-mapping": "^0.3.31",
|
|
83
83
|
"@playwright/test": "^1.61.1",
|
|
84
|
-
"@react-router/dev": "^8.
|
|
85
|
-
"@react-router/express": "^8.
|
|
86
|
-
"@react-router/fs-routes": "^8.
|
|
87
|
-
"@react-router/remix-routes-option-adapter": "^8.
|
|
88
|
-
"@react-router/serve": "^8.
|
|
84
|
+
"@react-router/dev": "^8.3.1",
|
|
85
|
+
"@react-router/express": "^8.3.1",
|
|
86
|
+
"@react-router/fs-routes": "^8.3.1",
|
|
87
|
+
"@react-router/remix-routes-option-adapter": "^8.3.1",
|
|
88
|
+
"@react-router/serve": "^8.3.1",
|
|
89
89
|
"@rsbuild/core": "2.2.0",
|
|
90
90
|
"@rsbuild/plugin-less": "1.6.4",
|
|
91
91
|
"@rsbuild/plugin-mdx": "^1.1.3",
|
|
@@ -119,8 +119,8 @@
|
|
|
119
119
|
"prettier": "3.8.1",
|
|
120
120
|
"react": "^19.2.4",
|
|
121
121
|
"react-dom": "^19.2.4",
|
|
122
|
-
"react-router": "^7.18.
|
|
123
|
-
"react-router-dom": "^7.18.
|
|
122
|
+
"react-router": "^7.18.3",
|
|
123
|
+
"react-router-dom": "^7.18.3",
|
|
124
124
|
"react-server-dom-rspack": "0.1.0",
|
|
125
125
|
"rsbuild-plugin-rsc": "^0.1.1",
|
|
126
126
|
"semver": "^7.8.5",
|
package/src/classic-mode.ts
CHANGED
|
@@ -143,10 +143,26 @@ export const createClassicWebRouteEntries = ({
|
|
|
143
143
|
webRouteEntries: Record<string, RsbuildEntryDescription>;
|
|
144
144
|
} => {
|
|
145
145
|
const manifestChunkNames = new Set<string>(['entry.client']);
|
|
146
|
+
// Entry names are sanitized paths, so two distinct route files could in
|
|
147
|
+
// principle map to one name (for example `../shared/x.tsx` and
|
|
148
|
+
// `__/shared/x.tsx`). Refuse that instead of letting one route silently
|
|
149
|
+
// serve the other's module. Routes that share a file intentionally share
|
|
150
|
+
// an entry.
|
|
151
|
+
const routeFileByEntryName = new Map<string, string>();
|
|
146
152
|
const webRouteEntries = Object.values(routes).reduce(
|
|
147
153
|
(acc, route) => {
|
|
148
154
|
const entryName = getRouteEntryBaseName(route, appDirectory);
|
|
149
155
|
const routeFilePath = resolve(appDirectory, route.file);
|
|
156
|
+
const existingRouteFile = routeFileByEntryName.get(entryName);
|
|
157
|
+
if (
|
|
158
|
+
existingRouteFile !== undefined &&
|
|
159
|
+
existingRouteFile !== routeFilePath
|
|
160
|
+
) {
|
|
161
|
+
throw new Error(
|
|
162
|
+
`[rsbuild-plugin-react-router] Route files ${JSON.stringify(existingRouteFile)} and ${JSON.stringify(routeFilePath)} both resolve to the entry name ${JSON.stringify(entryName)}. Rename one of them so their paths relative to the app directory differ.`
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
routeFileByEntryName.set(entryName, routeFilePath);
|
|
150
166
|
manifestChunkNames.add(entryName);
|
|
151
167
|
acc[entryName] = {
|
|
152
168
|
import: `${routeFilePath}${BUILD_CLIENT_ROUTE_QUERY_STRING}`,
|
|
@@ -167,11 +183,7 @@ export const createClassicWebRouteEntries = ({
|
|
|
167
183
|
if (!source.includes(exportName)) {
|
|
168
184
|
continue;
|
|
169
185
|
}
|
|
170
|
-
const chunkEntryName = getRouteChunkEntryName(
|
|
171
|
-
route,
|
|
172
|
-
exportName,
|
|
173
|
-
appDirectory
|
|
174
|
-
);
|
|
186
|
+
const chunkEntryName = getRouteChunkEntryName(entryName, exportName);
|
|
175
187
|
manifestChunkNames.add(chunkEntryName);
|
|
176
188
|
acc[chunkEntryName] = {
|
|
177
189
|
import: getRouteChunkModuleId(routeFilePath, exportName),
|
package/src/index.ts
CHANGED
|
@@ -263,7 +263,6 @@ export const pluginReactRouter = (
|
|
|
263
263
|
|
|
264
264
|
const {
|
|
265
265
|
resolved: resolvedConfig,
|
|
266
|
-
userAndPresetConfig,
|
|
267
266
|
presets: configPresets,
|
|
268
267
|
hasConfiguredServerModuleFormat,
|
|
269
268
|
} = await effectRuntime.runPromise(
|
|
@@ -472,10 +471,7 @@ export const pluginReactRouter = (
|
|
|
472
471
|
resolvedConfigForPreset as ReactRouterPresetResolvedConfig,
|
|
473
472
|
});
|
|
474
473
|
}
|
|
475
|
-
const buildEndReactRouterConfig
|
|
476
|
-
...resolvedConfigWithRoutes,
|
|
477
|
-
future: userAndPresetConfig.future ?? {},
|
|
478
|
-
} as ResolvedReactRouterConfig;
|
|
474
|
+
const buildEndReactRouterConfig = resolvedConfigWithRoutes;
|
|
479
475
|
|
|
480
476
|
const isBuild = api.context.action === 'build';
|
|
481
477
|
if (!isBuild) {
|
package/src/manifest.ts
CHANGED
|
@@ -413,26 +413,6 @@ export const getReactRouterManifestPath = ({
|
|
|
413
413
|
return `${dir}/manifest-${version}.js`;
|
|
414
414
|
};
|
|
415
415
|
|
|
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')
|
|
432
|
-
.update(JSON.stringify(fingerprintedValues))
|
|
433
|
-
.digest('hex')
|
|
434
|
-
.slice(0, 8);
|
|
435
|
-
|
|
436
416
|
export const getReactRouterManifestChunkNames = (
|
|
437
417
|
routes: Record<string, Route>,
|
|
438
418
|
appDirectory: string,
|
|
@@ -440,12 +420,13 @@ export const getReactRouterManifestChunkNames = (
|
|
|
440
420
|
): Set<string> => {
|
|
441
421
|
const chunkNames = new Set<string>(['entry.client']);
|
|
442
422
|
for (const route of Object.values(routes)) {
|
|
443
|
-
|
|
423
|
+
const routeEntryName = getRouteEntryBaseName(route, appDirectory);
|
|
424
|
+
chunkNames.add(routeEntryName);
|
|
444
425
|
if (!splitRouteModules || route.id === 'root') {
|
|
445
426
|
continue;
|
|
446
427
|
}
|
|
447
428
|
for (const exportName of routeChunkExportNames) {
|
|
448
|
-
chunkNames.add(getRouteChunkEntryName(
|
|
429
|
+
chunkNames.add(getRouteChunkEntryName(routeEntryName, exportName));
|
|
449
430
|
}
|
|
450
431
|
}
|
|
451
432
|
return chunkNames;
|
|
@@ -453,7 +434,7 @@ export const getReactRouterManifestChunkNames = (
|
|
|
453
434
|
|
|
454
435
|
const createRouteManifestItem = ({
|
|
455
436
|
route,
|
|
456
|
-
|
|
437
|
+
routeEntryName,
|
|
457
438
|
assetPrefix,
|
|
458
439
|
jsAssets,
|
|
459
440
|
routeAnalysis,
|
|
@@ -461,7 +442,7 @@ const createRouteManifestItem = ({
|
|
|
461
442
|
getCssAssetsForChunk,
|
|
462
443
|
}: {
|
|
463
444
|
route: Route;
|
|
464
|
-
|
|
445
|
+
routeEntryName: string;
|
|
465
446
|
assetPrefix: string;
|
|
466
447
|
jsAssets: string[];
|
|
467
448
|
routeAnalysis: RouteManifestAnalysis;
|
|
@@ -469,21 +450,20 @@ const createRouteManifestItem = ({
|
|
|
469
450
|
getCssAssetsForChunk: (chunkName: string) => string[];
|
|
470
451
|
}): RouteManifestItem => {
|
|
471
452
|
const routeChunkMap = routeAnalysis.hasRouteChunkByExportName;
|
|
472
|
-
const
|
|
453
|
+
const chunkEntryName = (exportName: RouteChunkExportName) =>
|
|
473
454
|
routeChunkMap?.[exportName]
|
|
474
|
-
?
|
|
475
|
-
getRouteChunkEntryName(route, exportName, appDirectory)
|
|
476
|
-
)
|
|
455
|
+
? getRouteChunkEntryName(routeEntryName, exportName)
|
|
477
456
|
: undefined;
|
|
457
|
+
const chunkModulePath = (exportName: RouteChunkExportName) => {
|
|
458
|
+
const name = chunkEntryName(exportName);
|
|
459
|
+
return name ? getModulePathForChunk(name) : undefined;
|
|
460
|
+
};
|
|
478
461
|
const cssAssets = [
|
|
479
462
|
...routeAnalysis.cssAssets,
|
|
480
|
-
...routeChunkExportNames.flatMap(exportName =>
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
)
|
|
485
|
-
: []
|
|
486
|
-
),
|
|
463
|
+
...routeChunkExportNames.flatMap(exportName => {
|
|
464
|
+
const name = chunkEntryName(exportName);
|
|
465
|
+
return name ? getCssAssetsForChunk(name) : [];
|
|
466
|
+
}),
|
|
487
467
|
];
|
|
488
468
|
|
|
489
469
|
return {
|
|
@@ -581,7 +561,7 @@ function generateReactRouterManifestForDevEffect(
|
|
|
581
561
|
key,
|
|
582
562
|
createRouteManifestItem({
|
|
583
563
|
route,
|
|
584
|
-
|
|
564
|
+
routeEntryName,
|
|
585
565
|
assetPrefix,
|
|
586
566
|
jsAssets,
|
|
587
567
|
routeAnalysis,
|
|
@@ -625,7 +605,14 @@ function generateReactRouterManifestForDevEffect(
|
|
|
625
605
|
},
|
|
626
606
|
routes: result,
|
|
627
607
|
};
|
|
628
|
-
|
|
608
|
+
// Content-derived in development too. React Router's stale-client check
|
|
609
|
+
// compares the browser's manifest version with the pinned server build's,
|
|
610
|
+
// and a random per-compilation version made unchanged manifests differ
|
|
611
|
+
// whenever a web compilation completed without a new server pin.
|
|
612
|
+
const version = createHash('md5')
|
|
613
|
+
.update(JSON.stringify(fingerprintedValues))
|
|
614
|
+
.digest('hex')
|
|
615
|
+
.slice(0, 8);
|
|
629
616
|
const manifestPath = getReactRouterManifestPath({
|
|
630
617
|
version,
|
|
631
618
|
isBuild,
|
|
@@ -36,6 +36,10 @@ export type Config = Omit<
|
|
|
36
36
|
};
|
|
37
37
|
|
|
38
38
|
type FutureConfig = {
|
|
39
|
+
// React Router 8.3 selects the web-streams server entry when this is set.
|
|
40
|
+
// The plugin ships its own server entry, so the flag is resolved and passed
|
|
41
|
+
// through to presets and `buildEnd` but does not change plugin behavior.
|
|
42
|
+
unstable_enableNodeReadableStream: boolean;
|
|
39
43
|
unstable_optimizeDeps: boolean;
|
|
40
44
|
unstable_subResourceIntegrity: boolean;
|
|
41
45
|
unstable_trailingSlashAwareDataRequests: boolean;
|
|
@@ -118,6 +122,7 @@ export type ResolvedReactRouterConfig = Readonly<{
|
|
|
118
122
|
}>;
|
|
119
123
|
|
|
120
124
|
const createDefaultFutureConfig = (): FutureConfig => ({
|
|
125
|
+
unstable_enableNodeReadableStream: false,
|
|
121
126
|
unstable_optimizeDeps: false,
|
|
122
127
|
unstable_subResourceIntegrity: false,
|
|
123
128
|
unstable_trailingSlashAwareDataRequests:
|
package/src/route-chunks.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { print } from 'yuku-codegen';
|
|
|
7
7
|
import { walk } from 'yuku-parser';
|
|
8
8
|
import { dirname, normalize, relative, resolve } from 'pathe';
|
|
9
9
|
import { SERVER_ONLY_ROUTE_EXPORTS_SET } from './constants.js';
|
|
10
|
+
import { createRouteId } from './plugin-utils.js';
|
|
10
11
|
|
|
11
12
|
type AnyNode = Record<string, any>;
|
|
12
13
|
|
|
@@ -984,16 +985,11 @@ export const getRouteEntryBaseName = (
|
|
|
984
985
|
route: { file: string },
|
|
985
986
|
appDirectory: string
|
|
986
987
|
): string =>
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
''
|
|
988
|
+
createRouteId(
|
|
989
|
+
toSafeEntryPath(normalizeRelativeFilePath(route.file, appDirectory))
|
|
990
990
|
);
|
|
991
991
|
|
|
992
992
|
export const getRouteChunkEntryName = (
|
|
993
|
-
|
|
994
|
-
chunkName: RouteChunkExportName
|
|
995
|
-
|
|
996
|
-
): string =>
|
|
997
|
-
`${getRouteEntryBaseName(route, appDirectory)}-${
|
|
998
|
-
routeChunkEntrySuffix[chunkName]
|
|
999
|
-
}`;
|
|
993
|
+
routeEntryBaseName: string,
|
|
994
|
+
chunkName: RouteChunkExportName
|
|
995
|
+
): string => `${routeEntryBaseName}-${routeChunkEntrySuffix[chunkName]}`;
|