rsbuild-plugin-react-router 0.6.0 → 0.6.2

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 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
- }, getRouteChunkEntryName = (routeId, chunkName)=>`${routeId}-${routeChunkEntrySuffix[chunkName]}`, setBoundedCacheEntry = (cache, key, value, maxEntries)=>{
682
+ }, getRouteEntryBaseName = (route, appDirectory)=>normalizeRelativeFilePath(route.file, appDirectory).replace(/^[A-Za-z]:/, '').split('/').filter((segment)=>'' !== segment && '.' !== segment).map((segment)=>'..' === segment ? '__' : segment).join('/').replace(/\.[^/.]+$/, ''), getRouteChunkEntryName = (route, chunkName, appDirectory)=>`${getRouteEntryBaseName(route, appDirectory)}-${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();
@@ -1348,4 +1348,4 @@ if (import.meta.webpackHot) {
1348
1348
  }
1349
1349
  };
1350
1350
  };
1351
- export { BUILD_CLIENT_ROUTE_QUERY_STRING, CLIENT_EXPORTS, CLIENT_NON_COMPONENT_EXPORTS, DEFAULT_JS_DIST_PATH, HMR_PATCHABLE_ROUTE_FLAGS, JS_EXTENSIONS, PLUGIN_NAME, SERVER_EXPORTS, SERVER_ONLY_ROUTE_EXPORTS, SPA_FALLBACK_HTML_FILE, analyzeRouteModuleCode, buildManifestChunkValidity, collectReferencedNames, combineURLs, createBundlerRouteExportResolver, createEmptyRouteChunkByExportName, createReactRouterPerformanceProfiler, createRouteId, detectRouteChunks, detectRouteChunksIfEnabled, escapeHtml, executeRouteTransformTask, findEntryFile, generate, generateWithProps, getExportNames, getExportedName, getPackageVersion, getPatternIdentifierNames, getProgram, getRouteChunkEntryName, getRouteChunkModuleId, getRouteChunkNameFromModuleId, getRouteModuleAnalysis, normalizeAssetPrefix, parseVersionMajorMinor, removeExports, removeUnusedImports, resolveAppPackagePath, resolveEffectiveAssetPrefix, roundMs, routeChunkExportNames, validateRouteChunks, validateSpaModeRouteExports, yuku_parse };
1351
+ export { BUILD_CLIENT_ROUTE_QUERY_STRING, CLIENT_EXPORTS, CLIENT_NON_COMPONENT_EXPORTS, DEFAULT_JS_DIST_PATH, HMR_PATCHABLE_ROUTE_FLAGS, JS_EXTENSIONS, PLUGIN_NAME, SERVER_EXPORTS, SERVER_ONLY_ROUTE_EXPORTS, SPA_FALLBACK_HTML_FILE, analyzeRouteModuleCode, buildManifestChunkValidity, collectReferencedNames, combineURLs, createBundlerRouteExportResolver, createEmptyRouteChunkByExportName, createReactRouterPerformanceProfiler, createRouteId, detectRouteChunks, detectRouteChunksIfEnabled, escapeHtml, executeRouteTransformTask, findEntryFile, generate, generateWithProps, getExportNames, getExportedName, getPackageVersion, getPatternIdentifierNames, getProgram, getRouteChunkEntryName, getRouteChunkModuleId, getRouteChunkNameFromModuleId, getRouteEntryBaseName, getRouteModuleAnalysis, normalizeAssetPrefix, parseVersionMajorMinor, removeExports, removeUnusedImports, resolveAppPackagePath, resolveEffectiveAssetPrefix, roundMs, routeChunkExportNames, validateRouteChunks, validateSpaModeRouteExports, yuku_parse };
package/dist/index.cjs CHANGED
@@ -11640,7 +11640,7 @@ const external_react_router_namespaceObject = require("react-router"), normalize
11640
11640
  }, normalizeRelativeFilePath = (file, appDirectory)=>{
11641
11641
  let fullPath = (0, external_pathe_namespaceObject.resolve)(appDirectory, file), relativePath = (0, external_pathe_namespaceObject.relative)(appDirectory, fullPath);
11642
11642
  return (0, external_pathe_namespaceObject.normalize)(relativePath).split('?')[0];
11643
- }, isRootRouteModuleId = (config, id)=>normalizeRelativeFilePath(id, config.appDirectory) === config.rootRouteFile, shouldAnalyzeRouteChunks = (config, id, code)=>!!config.splitRouteModules && mightContainRouteChunkExportName(code) && !isRootRouteModuleId(config, id), createEmptyRouteChunkByExportName = ()=>createRouteChunkExportMap(()=>!1), buildEnforceChunkValidity = (exportNames)=>{
11643
+ }, toSafeEntryPath = (relativePath)=>relativePath.replace(/^[A-Za-z]:/, '').split('/').filter((segment)=>'' !== segment && '.' !== segment).map((segment)=>'..' === segment ? '__' : segment).join('/'), isRootRouteModuleId = (config, id)=>normalizeRelativeFilePath(id, config.appDirectory) === config.rootRouteFile, shouldAnalyzeRouteChunks = (config, id, code)=>!!config.splitRouteModules && mightContainRouteChunkExportName(code) && !isRootRouteModuleId(config, id), createEmptyRouteChunkByExportName = ()=>createRouteChunkExportMap(()=>!1), buildEnforceChunkValidity = (exportNames)=>{
11644
11644
  let exportNameSet = new Set(exportNames);
11645
11645
  return createRouteChunkExportMap((exportName)=>!exportNameSet.has(exportName));
11646
11646
  }, buildManifestChunkValidity = (exportNames, hasRouteChunkByExportName)=>createRouteChunkExportMap((exportName)=>!exportNames.has(exportName) || hasRouteChunkByExportName[exportName]), detectRouteChunksIfEnabled = async (cache1, config, id, code)=>shouldAnalyzeRouteChunks(config, id, code) ? detectRouteChunks(code, cache1, normalizeRelativeFilePath(id, config.appDirectory)) : {
@@ -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
- }, getRouteChunkEntryName = (routeId, chunkName)=>`${routeId}-${routeChunkEntrySuffix[chunkName]}`, setBoundedCacheEntry = (cache1, key, value, maxEntries)=>{
11668
+ }, getRouteEntryBaseName = (route, appDirectory)=>toSafeEntryPath(normalizeRelativeFilePath(route.file, appDirectory)).replace(/\.[^/.]+$/, ''), getRouteChunkEntryName = (route, chunkName, appDirectory)=>`${getRouteEntryBaseName(route, appDirectory)}-${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,19 +11872,16 @@ 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
- }, getManifestVersion = (fingerprintedValues, isBuild)=>isBuild ? (0, external_node_crypto_namespaceObject.createHash)('md5').update(JSON.stringify(fingerprintedValues)).digest('hex').slice(0, 8) : String(Math.random()), getRouteEntryName = (route)=>{
11876
- let extensionIndex = route.file.lastIndexOf('.');
11877
- return extensionIndex >= 0 ? route.file.slice(0, extensionIndex) : route.file;
11878
- }, getReactRouterManifestChunkNames = (routes, splitRouteModules = !1)=>{
11875
+ }, getManifestVersion = (fingerprintedValues)=>(0, external_node_crypto_namespaceObject.createHash)('md5').update(JSON.stringify(fingerprintedValues)).digest('hex').slice(0, 8), getReactRouterManifestChunkNames = (routes, appDirectory, splitRouteModules = !1)=>{
11879
11876
  let chunkNames = new Set([
11880
11877
  'entry.client'
11881
11878
  ]);
11882
- for (let route of Object.values(routes))if (chunkNames.add(getRouteEntryName(route)), splitRouteModules && 'root' !== route.id) for (let exportName of routeChunkExportNames)chunkNames.add(getRouteChunkEntryName(route.id, exportName));
11879
+ for (let route of Object.values(routes))if (chunkNames.add(getRouteEntryBaseName(route, appDirectory)), splitRouteModules && 'root' !== route.id) for (let exportName of routeChunkExportNames)chunkNames.add(getRouteChunkEntryName(route, exportName, appDirectory));
11883
11880
  return chunkNames;
11884
- }, createRouteManifestItem = ({ route, assetPrefix, jsAssets, routeAnalysis, getModulePathForChunk, getCssAssetsForChunk })=>{
11885
- let routeChunkMap = routeAnalysis.hasRouteChunkByExportName, chunkModulePath = (exportName)=>routeChunkMap?.[exportName] ? getModulePathForChunk(getRouteChunkEntryName(route.id, exportName)) : void 0, cssAssets = [
11881
+ }, createRouteManifestItem = ({ route, appDirectory, assetPrefix, jsAssets, routeAnalysis, getModulePathForChunk, getCssAssetsForChunk })=>{
11882
+ let routeChunkMap = routeAnalysis.hasRouteChunkByExportName, chunkModulePath = (exportName)=>routeChunkMap?.[exportName] ? getModulePathForChunk(getRouteChunkEntryName(route, exportName, appDirectory)) : void 0, cssAssets = [
11886
11883
  ...routeAnalysis.cssAssets,
11887
- ...routeChunkExportNames.flatMap((exportName)=>routeChunkMap?.[exportName] ? getCssAssetsForChunk(getRouteChunkEntryName(route.id, exportName)) : [])
11884
+ ...routeChunkExportNames.flatMap((exportName)=>routeChunkMap?.[exportName] ? getCssAssetsForChunk(getRouteChunkEntryName(route, exportName, appDirectory)) : [])
11888
11885
  ];
11889
11886
  return {
11890
11887
  id: route.id,
@@ -11918,7 +11915,7 @@ function generateReactRouterManifestForDevEffect(routes, clientStats, context, a
11918
11915
  let { js: jsAssets } = getAssetsForChunk(chunkName);
11919
11916
  return jsAssets[0] ? combineURLs(assetPrefix, jsAssets[0]) : void 0;
11920
11917
  }, getCssAssetsForChunk = (chunkName)=>getAssetsForChunk(chunkName).css, manifestEntries = yield* fiberRuntime_forEach(Object.entries(routes), ([key, route])=>core_gen(function*() {
11921
- let routeEntryName = getRouteEntryName(route), { js: jsAssets, css: discoveredCssAssets } = getAssetsForChunk(routeEntryName), routeFilePath = (0, external_pathe_namespaceObject.resolve)(context, route.file), routeAnalysis = yield* analyzeRouteForManifestEffect({
11918
+ let routeEntryName = getRouteEntryBaseName(route, context), { js: jsAssets, css: discoveredCssAssets } = getAssetsForChunk(routeEntryName), routeFilePath = (0, external_pathe_namespaceObject.resolve)(context, route.file), routeAnalysis = yield* analyzeRouteForManifestEffect({
11922
11919
  discoveredCssAssets,
11923
11920
  isBuild,
11924
11921
  routeChunkCache: manifestOptions?.cache,
@@ -11936,6 +11933,7 @@ function generateReactRouterManifestForDevEffect(routes, clientStats, context, a
11936
11933
  key,
11937
11934
  createRouteManifestItem({
11938
11935
  route,
11936
+ appDirectory: context,
11939
11937
  assetPrefix,
11940
11938
  jsAssets,
11941
11939
  routeAnalysis,
@@ -11955,7 +11953,7 @@ function generateReactRouterManifestForDevEffect(routes, clientStats, context, a
11955
11953
  css: entryCssAssets.map((asset)=>combineURLs(assetPrefix, asset))
11956
11954
  },
11957
11955
  routes: result
11958
- }, version = getManifestVersion(fingerprintedValues, isBuild), manifestPath = getReactRouterManifestPath({
11956
+ }, version = getManifestVersion(fingerprintedValues), manifestPath = getReactRouterManifestPath({
11959
11957
  version,
11960
11958
  isBuild,
11961
11959
  entryModulePath: entryJsAssets[0]
@@ -12420,7 +12418,7 @@ const BROWSER_MANIFEST_ASSET = 'static/js/virtual/react-router/browser-manifest.
12420
12418
  return Object.keys(sri).length > 0 ? sri : void 0;
12421
12419
  };
12422
12420
  function registerModifyBrowserManifestAssets(api, routes, pluginOptions, appDirectory, assetPrefix = '/', routeChunkOptions, options) {
12423
- let getAssetPrefix = 'function' == typeof assetPrefix ? assetPrefix : ()=>assetPrefix, manifestChunkNames = options?.manifestChunkNames ?? getReactRouterManifestChunkNames(routes, routeChunkOptions?.splitRouteModules), isBuild = !!routeChunkOptions?.isBuild, finalizeSri = !!(isBuild && (options?.subResourceIntegrity ?? options?.future?.unstable_subResourceIntegrity)), buildAndEmitManifest = async ({ assets, sources, compilation }, { withSri })=>{
12421
+ let getAssetPrefix = 'function' == typeof assetPrefix ? assetPrefix : ()=>assetPrefix, manifestChunkNames = options?.manifestChunkNames ?? getReactRouterManifestChunkNames(routes, appDirectory, routeChunkOptions?.splitRouteModules), isBuild = !!routeChunkOptions?.isBuild, finalizeSri = !!(isBuild && (options?.subResourceIntegrity ?? options?.future?.unstable_subResourceIntegrity)), buildAndEmitManifest = async ({ assets, sources, compilation }, { withSri })=>{
12424
12422
  let currentAssetPrefix = getAssetPrefix(), stats = createReactRouterManifestStats(compilation, manifestChunkNames), { manifest, moduleExportsByRouteId } = await generateReactRouterManifestForDev(routes, pluginOptions, stats, appDirectory, currentAssetPrefix, createReactRouterManifestOptions({
12425
12423
  routeChunks: routeChunkOptions,
12426
12424
  routeModuleAnalysis: options?.routeModuleAnalysis
@@ -15479,7 +15477,7 @@ export {
15479
15477
  let manifestChunkNames = new Set([
15480
15478
  'entry.client'
15481
15479
  ]), webRouteEntries = Object.values(routes).reduce((acc, route)=>{
15482
- let entryName = route.file.slice(0, route.file.lastIndexOf('.')), routeFilePath = (0, external_pathe_namespaceObject.resolve)(appDirectory, route.file);
15480
+ let entryName = getRouteEntryBaseName(route, appDirectory), routeFilePath = (0, external_pathe_namespaceObject.resolve)(appDirectory, route.file);
15483
15481
  if (manifestChunkNames.add(entryName), acc[entryName] = {
15484
15482
  import: `${routeFilePath}${BUILD_CLIENT_ROUTE_QUERY_STRING}`,
15485
15483
  html: !1
@@ -15493,7 +15491,7 @@ export {
15493
15491
  }
15494
15492
  for (let exportName of routeChunkExportNames){
15495
15493
  if (!source.includes(exportName)) continue;
15496
- let chunkEntryName = getRouteChunkEntryName(route.id, exportName);
15494
+ let chunkEntryName = getRouteChunkEntryName(route, exportName, appDirectory);
15497
15495
  manifestChunkNames.add(chunkEntryName), acc[chunkEntryName] = {
15498
15496
  import: getRouteChunkModuleId(routeFilePath, exportName),
15499
15497
  html: !1
@@ -15711,11 +15709,18 @@ export {
15711
15709
  library: {
15712
15710
  type: 'module'
15713
15711
  },
15714
- module: !0
15712
+ module: !0,
15713
+ ...isBuild ? {
15714
+ chunkFilename: 'static/js/async/[id]-[contenthash:16].js'
15715
+ } : {}
15715
15716
  },
15716
15717
  webOptimization: {
15717
15718
  avoidEntryIife: !0,
15718
- runtimeChunk: 'single'
15719
+ runtimeChunk: 'single',
15720
+ ...isBuild ? {
15721
+ mangleExports: 'size',
15722
+ usedExports: 'global'
15723
+ } : {}
15719
15724
  },
15720
15725
  nodeExternals: Array.from(new Set([
15721
15726
  'express',
package/dist/index.js CHANGED
@@ -13,7 +13,7 @@ import { SourceMap, createRequire } from "node:module";
13
13
  import { dirname as external_node_path_dirname, isAbsolute as external_node_path_isAbsolute, join as external_node_path_join, relative as external_node_path_relative, resolve as external_node_path_resolve, sep as external_node_path_sep, dirname as __rspack_dirname } from "node:path";
14
14
  import { createJiti } from "jiti";
15
15
  import { createRequestListener as node_fetch_server_createRequestListener } from "@remix-run/node-fetch-server";
16
- import { analyzeRouteModuleCode, collectReferencedNames, createReactRouterPerformanceProfiler, combineURLs, JS_EXTENSIONS, generate as yuku_generate, executeRouteTransformTask, generateWithProps, resolveAppPackagePath, validateRouteChunks, roundMs, BUILD_CLIENT_ROUTE_QUERY_STRING, resolveEffectiveAssetPrefix, removeUnusedImports, getProgram, detectRouteChunks, getPatternIdentifierNames, getExportedName, SERVER_ONLY_ROUTE_EXPORTS, createRouteId, removeExports, SERVER_EXPORTS, getExportNames, HMR_PATCHABLE_ROUTE_FLAGS, escapeHtml, PLUGIN_NAME, getRouteModuleAnalysis, parseVersionMajorMinor, createEmptyRouteChunkByExportName, getRouteChunkNameFromModuleId, findEntryFile, routeChunkExportNames, buildManifestChunkValidity, CLIENT_NON_COMPONENT_EXPORTS, CLIENT_EXPORTS, SPA_FALLBACK_HTML_FILE, getRouteChunkEntryName, getRouteChunkModuleId, normalizeAssetPrefix, detectRouteChunksIfEnabled, validateSpaModeRouteExports, DEFAULT_JS_DIST_PATH, getPackageVersion, createBundlerRouteExportResolver, yuku_parse } from "./511.js";
16
+ import { analyzeRouteModuleCode, yuku_parse, collectReferencedNames, createReactRouterPerformanceProfiler, combineURLs, JS_EXTENSIONS, generate as yuku_generate, executeRouteTransformTask, generateWithProps, resolveAppPackagePath, validateRouteChunks, roundMs, BUILD_CLIENT_ROUTE_QUERY_STRING, resolveEffectiveAssetPrefix, removeUnusedImports, getProgram, detectRouteChunks, getPatternIdentifierNames, getExportedName, SERVER_ONLY_ROUTE_EXPORTS, createRouteId, removeExports, SERVER_EXPORTS, getExportNames, HMR_PATCHABLE_ROUTE_FLAGS, escapeHtml, PLUGIN_NAME, getRouteModuleAnalysis, parseVersionMajorMinor, getRouteChunkNameFromModuleId, createEmptyRouteChunkByExportName, findEntryFile, routeChunkExportNames, buildManifestChunkValidity, CLIENT_NON_COMPONENT_EXPORTS, CLIENT_EXPORTS, SPA_FALLBACK_HTML_FILE, getRouteChunkEntryName, getRouteChunkModuleId, normalizeAssetPrefix, detectRouteChunksIfEnabled, validateSpaModeRouteExports, DEFAULT_JS_DIST_PATH, getRouteEntryBaseName, getPackageVersion, createBundlerRouteExportResolver } from "./511.js";
17
17
  var effect, description, __rspack_import_meta_dirname__ = __rspack_dirname(__rspack_fileURLToPath(import.meta.url));
18
18
  let getAvailableCpuCount = ()=>'function' == typeof availableParallelism ? availableParallelism() : cpus().length, getDefaultConcurrency = (cpuCount = getAvailableCpuCount())=>Math.max(0, Math.floor(cpuCount) - 2), getCappedPluginConcurrency = (cap = 16)=>Math.max(1, Math.min(cap, getDefaultConcurrency() || 1)), createReactRouterHydrationModuleTest = (entryClientPath)=>{
19
19
  let eagerPatterns = [
@@ -7395,9 +7395,6 @@ let createReactRouterManifestOptions = ({ routeChunks, routeModuleAnalysis })=>{
7395
7395
  return '.' === dir ? DEFAULT_JS_DIST_PATH : dir;
7396
7396
  })(entryModulePath);
7397
7397
  return `${dir}/manifest-${version}.js`;
7398
- }, getRouteEntryName = (route)=>{
7399
- let extensionIndex = route.file.lastIndexOf('.');
7400
- return extensionIndex >= 0 ? route.file.slice(0, extensionIndex) : route.file;
7401
7398
  };
7402
7399
  async function generateReactRouterManifestForDev(routes, _options, clientStats, context, assetPrefix = '/', manifestOptions) {
7403
7400
  return runPluginEffect(core_gen(function*() {
@@ -7435,7 +7432,7 @@ async function generateReactRouterManifestForDev(routes, _options, clientStats,
7435
7432
  let { js: jsAssets } = getAssetsForChunk(chunkName);
7436
7433
  return jsAssets[0] ? combineURLs(assetPrefix, jsAssets[0]) : void 0;
7437
7434
  }, getCssAssetsForChunk = (chunkName)=>getAssetsForChunk(chunkName).css, manifestEntries = yield* fiberRuntime_forEach(Object.entries(routes), ([key, route])=>core_gen(function*() {
7438
- let routeEntryName = getRouteEntryName(route), { js: jsAssets, css: discoveredCssAssets } = getAssetsForChunk(routeEntryName), routeFilePath = external_pathe_resolve(context, route.file), routeAnalysis = yield* (({ discoveredCssAssets, isBuild, routeChunkCache, routeChunkConfig, routeEntryName, routeFilePath, route, routeModuleAnalysis })=>tryPluginPromise(async ()=>{
7435
+ let routeEntryName = getRouteEntryBaseName(route, context), { js: jsAssets, css: discoveredCssAssets } = getAssetsForChunk(routeEntryName), routeFilePath = external_pathe_resolve(context, route.file), routeAnalysis = yield* (({ discoveredCssAssets, isBuild, routeChunkCache, routeChunkConfig, routeEntryName, routeFilePath, route, routeModuleAnalysis })=>tryPluginPromise(async ()=>{
7439
7436
  let { code, exports: exportNames } = await routeModuleAnalysis?.(routeFilePath, route) ?? await getRouteModuleAnalysis(routeFilePath), cssAssets = !isBuild && 0 === discoveredCssAssets.length && CSS_IMPORT_RE.test(code) ? [
7440
7437
  `${DEFAULT_JS_DIST_PATH.replace('/js', '/css')}/${routeEntryName}.css`
7441
7438
  ] : discoveredCssAssets, chunkInfo = isBuild && routeChunkConfig ? await detectRouteChunksIfEnabled(routeChunkCache, routeChunkConfig, routeFilePath, code) : null;
@@ -7466,10 +7463,10 @@ async function generateReactRouterManifestForDev(routes, _options, clientStats,
7466
7463
  valid: buildManifestChunkValidity(routeAnalysis.exports, routeAnalysis.hasRouteChunkByExportName ?? createEmptyRouteChunkByExportName())
7467
7464
  }), [
7468
7465
  key,
7469
- (({ route, assetPrefix, jsAssets, routeAnalysis, getModulePathForChunk, getCssAssetsForChunk })=>{
7470
- let routeChunkMap = routeAnalysis.hasRouteChunkByExportName, chunkModulePath = (exportName)=>routeChunkMap?.[exportName] ? getModulePathForChunk(getRouteChunkEntryName(route.id, exportName)) : void 0, cssAssets = [
7466
+ (({ route, appDirectory, assetPrefix, jsAssets, routeAnalysis, getModulePathForChunk, getCssAssetsForChunk })=>{
7467
+ let routeChunkMap = routeAnalysis.hasRouteChunkByExportName, chunkModulePath = (exportName)=>routeChunkMap?.[exportName] ? getModulePathForChunk(getRouteChunkEntryName(route, exportName, appDirectory)) : void 0, cssAssets = [
7471
7468
  ...routeAnalysis.cssAssets,
7472
- ...routeChunkExportNames.flatMap((exportName)=>routeChunkMap?.[exportName] ? getCssAssetsForChunk(getRouteChunkEntryName(route.id, exportName)) : [])
7469
+ ...routeChunkExportNames.flatMap((exportName)=>routeChunkMap?.[exportName] ? getCssAssetsForChunk(getRouteChunkEntryName(route, exportName, appDirectory)) : [])
7473
7470
  ];
7474
7471
  return {
7475
7472
  id: route.id,
@@ -7494,6 +7491,7 @@ async function generateReactRouterManifestForDev(routes, _options, clientStats,
7494
7491
  };
7495
7492
  })({
7496
7493
  route,
7494
+ appDirectory: context,
7497
7495
  assetPrefix: assetPrefix,
7498
7496
  jsAssets,
7499
7497
  routeAnalysis,
@@ -7513,7 +7511,7 @@ async function generateReactRouterManifestForDev(routes, _options, clientStats,
7513
7511
  css: entryCssAssets.map((asset)=>combineURLs(assetPrefix, asset))
7514
7512
  },
7515
7513
  routes: result
7516
- }, version = isBuild ? createHash('md5').update(JSON.stringify(fingerprintedValues)).digest('hex').slice(0, 8) : String(Math.random()), manifestPath = getReactRouterManifestPath({
7514
+ }, version = createHash('md5').update(JSON.stringify(fingerprintedValues)).digest('hex').slice(0, 8), manifestPath = getReactRouterManifestPath({
7517
7515
  version,
7518
7516
  isBuild,
7519
7517
  entryModulePath: entryJsAssets[0]
@@ -9744,7 +9742,7 @@ export {
9744
9742
  let manifestChunkNames = new Set([
9745
9743
  'entry.client'
9746
9744
  ]), webRouteEntries = Object.values(routes).reduce((acc, route)=>{
9747
- let entryName = route.file.slice(0, route.file.lastIndexOf('.')), routeFilePath = external_pathe_resolve(appDirectory, route.file);
9745
+ let entryName = getRouteEntryBaseName(route, appDirectory), routeFilePath = external_pathe_resolve(appDirectory, route.file);
9748
9746
  if (manifestChunkNames.add(entryName), acc[entryName] = {
9749
9747
  import: `${routeFilePath}${BUILD_CLIENT_ROUTE_QUERY_STRING}`,
9750
9748
  html: !1
@@ -9758,7 +9756,7 @@ export {
9758
9756
  }
9759
9757
  for (let exportName of routeChunkExportNames){
9760
9758
  if (!source.includes(exportName)) continue;
9761
- let chunkEntryName = getRouteChunkEntryName(route.id, exportName);
9759
+ let chunkEntryName = getRouteChunkEntryName(route, exportName, appDirectory);
9762
9760
  manifestChunkNames.add(chunkEntryName), acc[chunkEntryName] = {
9763
9761
  import: getRouteChunkModuleId(routeFilePath, exportName),
9764
9762
  html: !1
@@ -9926,11 +9924,18 @@ export {
9926
9924
  library: {
9927
9925
  type: 'module'
9928
9926
  },
9929
- module: !0
9927
+ module: !0,
9928
+ ...isBuild ? {
9929
+ chunkFilename: 'static/js/async/[id]-[contenthash:16].js'
9930
+ } : {}
9930
9931
  },
9931
9932
  webOptimization: {
9932
9933
  avoidEntryIife: !0,
9933
- runtimeChunk: 'single'
9934
+ runtimeChunk: 'single',
9935
+ ...isBuild ? {
9936
+ mangleExports: 'size',
9937
+ usedExports: 'global'
9938
+ } : {}
9934
9939
  },
9935
9940
  nodeExternals: Array.from(new Set([
9936
9941
  'express',
@@ -11244,13 +11249,13 @@ if (typeof window !== 'undefined' && import.meta.webpackHot) {
11244
11249
  outputClientPath,
11245
11250
  performanceProfiler
11246
11251
  })) : (!function(api, routes, pluginOptions, appDirectory, assetPrefix = '/', routeChunkOptions, options) {
11247
- let getAssetPrefix = 'function' == typeof assetPrefix ? assetPrefix : ()=>assetPrefix, manifestChunkNames = options?.manifestChunkNames ?? ((routes, splitRouteModules = !1)=>{
11252
+ let getAssetPrefix = 'function' == typeof assetPrefix ? assetPrefix : ()=>assetPrefix, manifestChunkNames = options?.manifestChunkNames ?? ((routes, appDirectory, splitRouteModules = !1)=>{
11248
11253
  let chunkNames = new Set([
11249
11254
  'entry.client'
11250
11255
  ]);
11251
- for (let route of Object.values(routes))if (chunkNames.add(getRouteEntryName(route)), splitRouteModules && 'root' !== route.id) for (let exportName of routeChunkExportNames)chunkNames.add(getRouteChunkEntryName(route.id, exportName));
11256
+ for (let route of Object.values(routes))if (chunkNames.add(getRouteEntryBaseName(route, appDirectory)), splitRouteModules && 'root' !== route.id) for (let exportName of routeChunkExportNames)chunkNames.add(getRouteChunkEntryName(route, exportName, appDirectory));
11252
11257
  return chunkNames;
11253
- })(routes, routeChunkOptions?.splitRouteModules), isBuild = !!routeChunkOptions?.isBuild, finalizeSri = !!(isBuild && (options?.subResourceIntegrity ?? options?.future?.unstable_subResourceIntegrity)), buildAndEmitManifest = async ({ assets, sources, compilation }, { withSri })=>{
11258
+ })(routes, appDirectory, routeChunkOptions?.splitRouteModules), isBuild = !!routeChunkOptions?.isBuild, finalizeSri = !!(isBuild && (options?.subResourceIntegrity ?? options?.future?.unstable_subResourceIntegrity)), buildAndEmitManifest = async ({ assets, sources, compilation }, { withSri })=>{
11254
11259
  let currentAssetPrefix = getAssetPrefix(), stats = createReactRouterManifestStats(compilation, manifestChunkNames), { manifest, moduleExportsByRouteId } = await generateReactRouterManifestForDev(routes, pluginOptions, stats, appDirectory, currentAssetPrefix, createReactRouterManifestOptions({
11255
11260
  routeChunks: routeChunkOptions,
11256
11261
  routeModuleAnalysis: options?.routeModuleAnalysis
@@ -75,7 +75,7 @@ export declare const getReactRouterManifestPath: ({ version, isBuild, entryModul
75
75
  isBuild: boolean;
76
76
  entryModulePath?: string;
77
77
  }) => string;
78
- export declare const getReactRouterManifestChunkNames: (routes: Record<string, Route>, splitRouteModules?: boolean | "enforce") => Set<string>;
78
+ export declare const getReactRouterManifestChunkNames: (routes: Record<string, Route>, appDirectory: string, splitRouteModules?: boolean | "enforce") => Set<string>;
79
79
  export declare function generateReactRouterManifestForDev(routes: Record<string, Route>, _options: PluginOptions, clientStats: ReactRouterManifestStats | undefined, context: string, assetPrefix?: string, manifestOptions?: ReactRouterManifestOptions): Promise<ReactRouterManifestGenerationResult>;
80
80
  export declare function getReactRouterManifestForDev(...args: Parameters<typeof generateReactRouterManifestForDev>): Promise<ReactRouterManifestForDev>;
81
81
  export {};
@@ -37,5 +37,10 @@ export declare const validateRouteChunks: (args: {
37
37
  id: string;
38
38
  valid: Record<RouteChunkExportName, boolean>;
39
39
  }) => void;
40
- export declare const getRouteChunkEntryName: (routeId: string, chunkName: RouteChunkExportName) => string;
40
+ export declare const getRouteEntryBaseName: (route: {
41
+ file: string;
42
+ }, appDirectory: string) => string;
43
+ export declare const getRouteChunkEntryName: (route: {
44
+ file: string;
45
+ }, chunkName: RouteChunkExportName, appDirectory: string) => string;
41
46
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rsbuild-plugin-react-router",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "description": "React Router plugin for Rsbuild",
5
5
  "repository": {
6
6
  "type": "git",
@@ -25,6 +25,7 @@ import {
25
25
  import {
26
26
  getRouteChunkEntryName,
27
27
  getRouteChunkModuleId,
28
+ getRouteEntryBaseName,
28
29
  routeChunkExportNames,
29
30
  } from './route-chunks.js';
30
31
  import type { Config } from './react-router-config.js';
@@ -144,7 +145,7 @@ export const createClassicWebRouteEntries = ({
144
145
  const manifestChunkNames = new Set<string>(['entry.client']);
145
146
  const webRouteEntries = Object.values(routes).reduce(
146
147
  (acc, route) => {
147
- const entryName = route.file.slice(0, route.file.lastIndexOf('.'));
148
+ const entryName = getRouteEntryBaseName(route, appDirectory);
148
149
  const routeFilePath = resolve(appDirectory, route.file);
149
150
  manifestChunkNames.add(entryName);
150
151
  acc[entryName] = {
@@ -166,7 +167,11 @@ export const createClassicWebRouteEntries = ({
166
167
  if (!source.includes(exportName)) {
167
168
  continue;
168
169
  }
169
- const chunkEntryName = getRouteChunkEntryName(route.id, exportName);
170
+ const chunkEntryName = getRouteChunkEntryName(
171
+ route,
172
+ exportName,
173
+ appDirectory
174
+ );
170
175
  manifestChunkNames.add(chunkEntryName);
171
176
  acc[chunkEntryName] = {
172
177
  import: getRouteChunkModuleId(routeFilePath, exportName),
package/src/manifest.ts CHANGED
@@ -13,6 +13,7 @@ import {
13
13
  createEmptyRouteChunkByExportName,
14
14
  detectRouteChunksIfEnabled,
15
15
  getRouteChunkEntryName,
16
+ getRouteEntryBaseName,
16
17
  routeChunkExportNames,
17
18
  validateRouteChunks,
18
19
  type RouteChunkCache,
@@ -412,36 +413,39 @@ export const getReactRouterManifestPath = ({
412
413
  return `${dir}/manifest-${version}.js`;
413
414
  };
414
415
 
415
- const getManifestVersion = (
416
- fingerprintedValues: { entry: unknown; routes: unknown },
417
- isBuild: boolean
418
- ): string => {
419
- if (!isBuild) {
420
- return String(Math.random());
421
- }
422
- return createHash('md5')
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')
423
432
  .update(JSON.stringify(fingerprintedValues))
424
433
  .digest('hex')
425
434
  .slice(0, 8);
426
- };
427
-
428
- const getRouteEntryName = (route: Route): string => {
429
- const extensionIndex = route.file.lastIndexOf('.');
430
- return extensionIndex >= 0 ? route.file.slice(0, extensionIndex) : route.file;
431
- };
432
435
 
433
436
  export const getReactRouterManifestChunkNames = (
434
437
  routes: Record<string, Route>,
438
+ appDirectory: string,
435
439
  splitRouteModules: boolean | 'enforce' = false
436
440
  ): Set<string> => {
437
441
  const chunkNames = new Set<string>(['entry.client']);
438
442
  for (const route of Object.values(routes)) {
439
- chunkNames.add(getRouteEntryName(route));
443
+ chunkNames.add(getRouteEntryBaseName(route, appDirectory));
440
444
  if (!splitRouteModules || route.id === 'root') {
441
445
  continue;
442
446
  }
443
447
  for (const exportName of routeChunkExportNames) {
444
- chunkNames.add(getRouteChunkEntryName(route.id, exportName));
448
+ chunkNames.add(getRouteChunkEntryName(route, exportName, appDirectory));
445
449
  }
446
450
  }
447
451
  return chunkNames;
@@ -449,6 +453,7 @@ export const getReactRouterManifestChunkNames = (
449
453
 
450
454
  const createRouteManifestItem = ({
451
455
  route,
456
+ appDirectory,
452
457
  assetPrefix,
453
458
  jsAssets,
454
459
  routeAnalysis,
@@ -456,6 +461,7 @@ const createRouteManifestItem = ({
456
461
  getCssAssetsForChunk,
457
462
  }: {
458
463
  route: Route;
464
+ appDirectory: string;
459
465
  assetPrefix: string;
460
466
  jsAssets: string[];
461
467
  routeAnalysis: RouteManifestAnalysis;
@@ -465,13 +471,17 @@ const createRouteManifestItem = ({
465
471
  const routeChunkMap = routeAnalysis.hasRouteChunkByExportName;
466
472
  const chunkModulePath = (exportName: RouteChunkExportName) =>
467
473
  routeChunkMap?.[exportName]
468
- ? getModulePathForChunk(getRouteChunkEntryName(route.id, exportName))
474
+ ? getModulePathForChunk(
475
+ getRouteChunkEntryName(route, exportName, appDirectory)
476
+ )
469
477
  : undefined;
470
478
  const cssAssets = [
471
479
  ...routeAnalysis.cssAssets,
472
480
  ...routeChunkExportNames.flatMap(exportName =>
473
481
  routeChunkMap?.[exportName]
474
- ? getCssAssetsForChunk(getRouteChunkEntryName(route.id, exportName))
482
+ ? getCssAssetsForChunk(
483
+ getRouteChunkEntryName(route, exportName, appDirectory)
484
+ )
475
485
  : []
476
486
  ),
477
487
  ];
@@ -540,7 +550,7 @@ function generateReactRouterManifestForDevEffect(
540
550
  Object.entries(routes),
541
551
  ([key, route]) =>
542
552
  Effect.gen(function* () {
543
- const routeEntryName = getRouteEntryName(route);
553
+ const routeEntryName = getRouteEntryBaseName(route, context);
544
554
  const { js: jsAssets, css: discoveredCssAssets } =
545
555
  getAssetsForChunk(routeEntryName);
546
556
  const routeFilePath = resolve(context, route.file);
@@ -571,6 +581,7 @@ function generateReactRouterManifestForDevEffect(
571
581
  key,
572
582
  createRouteManifestItem({
573
583
  route,
584
+ appDirectory: context,
574
585
  assetPrefix,
575
586
  jsAssets,
576
587
  routeAnalysis,
@@ -614,7 +625,7 @@ function generateReactRouterManifestForDevEffect(
614
625
  },
615
626
  routes: result,
616
627
  };
617
- const version = getManifestVersion(fingerprintedValues, isBuild);
628
+ const version = getManifestVersion(fingerprintedValues);
618
629
  const manifestPath = getReactRouterManifestPath({
619
630
  version,
620
631
  isBuild,
package/src/mode-plan.ts CHANGED
@@ -345,10 +345,20 @@ const createClassicModePlan = async ({
345
345
  wasmLoading: 'fetch',
346
346
  library: { type: 'module' },
347
347
  module: true,
348
+ // Async chunks are addressed by id at runtime, so the chunk name only
349
+ // adds bytes to the filename and to every place that references it.
350
+ ...(isBuild
351
+ ? { chunkFilename: 'static/js/async/[id]-[contenthash:16].js' }
352
+ : {}),
348
353
  },
349
354
  webOptimization: {
350
355
  avoidEntryIife: true,
351
356
  runtimeChunk: 'single',
357
+ // Classic mode resolves route modules through the browser manifest by
358
+ // chunk, not by export name, so production builds can mangle export
359
+ // names and drop exports nothing imports across the whole graph. RSC
360
+ // mode must keep every export name; see createRscModePlan.
361
+ ...(isBuild ? { mangleExports: 'size', usedExports: 'global' } : {}),
352
362
  },
353
363
  nodeExternals: Array.from(
354
364
  new Set(['express', ...getSsrExternals(process.cwd())])
@@ -147,6 +147,7 @@ export function registerModifyBrowserManifestAssets(
147
147
  options?.manifestChunkNames ??
148
148
  getReactRouterManifestChunkNames(
149
149
  routes,
150
+ appDirectory,
150
151
  routeChunkOptions?.splitRouteModules
151
152
  );
152
153
  const isBuild = Boolean(routeChunkOptions?.isBuild);
@@ -860,6 +860,19 @@ const normalizeRelativeFilePath = (file: string, appDirectory: string) => {
860
860
  return normalize(relativePath).split('?')[0];
861
861
  };
862
862
 
863
+ // An rspack entry name is written out as a path under `output.distPath.js`, so it
864
+ // is a filename, not an identifier. Keep it a safe, app-relative POSIX path: the
865
+ // developer's absolute checkout path must never reach `dist/` (nor the browser
866
+ // manifest), and an entry must never escape the JS output directory. `pathe`
867
+ // already normalizes separators, so only drive prefixes and `..` need handling.
868
+ const toSafeEntryPath = (relativePath: string): string =>
869
+ relativePath
870
+ .replace(/^[A-Za-z]:/, '')
871
+ .split('/')
872
+ .filter(segment => segment !== '' && segment !== '.')
873
+ .map(segment => (segment === '..' ? '__' : segment))
874
+ .join('/');
875
+
863
876
  const isRootRouteModuleId = (config: RouteChunkConfig, id: string) =>
864
877
  normalizeRelativeFilePath(id, config.appDirectory) === config.rootRouteFile;
865
878
 
@@ -967,7 +980,20 @@ export const validateRouteChunks: (args: {
967
980
  );
968
981
  };
969
982
 
983
+ export const getRouteEntryBaseName = (
984
+ route: { file: string },
985
+ appDirectory: string
986
+ ): string =>
987
+ toSafeEntryPath(normalizeRelativeFilePath(route.file, appDirectory)).replace(
988
+ /\.[^/.]+$/,
989
+ ''
990
+ );
991
+
970
992
  export const getRouteChunkEntryName = (
971
- routeId: string,
972
- chunkName: RouteChunkExportName
973
- ) => `${routeId}-${routeChunkEntrySuffix[chunkName]}`;
993
+ route: { file: string },
994
+ chunkName: RouteChunkExportName,
995
+ appDirectory: string
996
+ ): string =>
997
+ `${getRouteEntryBaseName(route, appDirectory)}-${
998
+ routeChunkEntrySuffix[chunkName]
999
+ }`;