rsbuild-plugin-react-router 0.6.6 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -343,6 +343,28 @@ If you configure `output.assetPrefix` in Rsbuild, the plugin uses that value
343
343
  for the React Router browser manifest and server build `publicPath` so asset
344
344
  URLs resolve correctly when serving from a CDN or sub-path.
345
345
 
346
+ The web environment's own `output.assetPrefix` is passed through to the browser
347
+ compiler untouched, so `environments.web.output.assetPrefix: 'auto'` lets the
348
+ browser runtime resolve async chunks and stylesheets relative to the loaded
349
+ script. The server build and browser manifest need an absolute prefix: they use
350
+ the web environment's prefix when it is usable and otherwise fall back to the
351
+ root `output.assetPrefix`. A common CDN setup is therefore:
352
+
353
+ ```ts
354
+ export default defineConfig({
355
+ output: { assetPrefix: 'https://cdn.example.com/app/' }, // server-rendered URLs
356
+ environments: {
357
+ web: { output: { assetPrefix: 'auto' } }, // browser runtime resolves itself
358
+ },
359
+ });
360
+ ```
361
+
362
+ The plugin does not set `output.filename`, `chunkFilename`, or `publicPath`
363
+ for the web environment. Production browser entries use Rsbuild's default
364
+ content-hashed filenames, and `output.filename`, `output.filenameHash`,
365
+ `output.distPath`, and `tools.rspack` output settings you configure govern
366
+ the emitted files and the manifest URLs that reference them.
367
+
346
368
  ## Custom Server Setup
347
369
 
348
370
  The plugin supports two ways to handle server-side rendering:
package/dist/511.js CHANGED
@@ -375,9 +375,16 @@ function combineURLs(baseURL, relativeURL) {
375
375
  function normalizeAssetPrefix(assetPrefix) {
376
376
  return assetPrefix && 'auto' !== assetPrefix ? assetPrefix.endsWith('/') ? assetPrefix : `${assetPrefix}/` : '/';
377
377
  }
378
- function resolveEffectiveAssetPrefix(config) {
379
- let outputPrefix = 'string' == typeof config.output?.assetPrefix ? config.output.assetPrefix : void 0;
380
- return config.isBuild ? normalizeAssetPrefix(outputPrefix) : normalizeAssetPrefix(('string' == typeof config.dev?.assetPrefix ? config.dev.assetPrefix : void 0) ?? outputPrefix);
378
+ let asString = (value)=>'string' == typeof value ? value : void 0, pickConfiguredAssetPrefix = ({ dev, output }, isBuild)=>isBuild ? asString(output?.assetPrefix) : asString(dev?.assetPrefix) ?? asString(output?.assetPrefix);
379
+ function resolveEffectiveAssetPrefix(config, ...fallbacks) {
380
+ for (let candidate of [
381
+ config,
382
+ ...fallbacks
383
+ ]){
384
+ let prefix = pickConfiguredAssetPrefix(candidate, config.isBuild);
385
+ if (prefix && 'auto' !== prefix) return normalizeAssetPrefix(prefix);
386
+ }
387
+ return '/';
381
388
  }
382
389
  function createRouteId(file) {
383
390
  return normalize(file.replace(/\.[^/.]+$/, ''));
@@ -1,6 +1,20 @@
1
- import type { RsbuildPluginAPI } from '@rsbuild/core';
2
- export declare const registerReactRouterEnvironmentOutput: ({ api, federation, resolvedServerOutput, }: {
1
+ import type { RsbuildPluginAPI, Rspack } from '@rsbuild/core';
2
+ /**
3
+ * Rspack `output` policy for the web and node environments, in two tiers:
4
+ *
5
+ * 1. Overridable defaults, registered through `modifyRspackConfig`. Rsbuild
6
+ * runs the user's `tools.rspack` (object or function form) after this hook,
7
+ * so user output settings such as `chunkFilename` take precedence
8
+ * (#129, #130). Neither `filename` nor `publicPath` is set here: Rsbuild
9
+ * derives them from `output.filename`/`output.filenameHash`/`output.distPath`
10
+ * and the environment's `output.assetPrefix`, which keeps `'auto'` intact.
11
+ * 2. Enforced invariants, registered through a `tools.rspack` function that
12
+ * runs after the user's own `tools.rspack`: the server library type must
13
+ * match the server module format, and federation builds need async startup.
14
+ */
15
+ export declare const registerReactRouterEnvironmentOutput: ({ api, federation, resolvedServerOutput, webOutput, }: {
3
16
  api: RsbuildPluginAPI;
4
17
  federation: boolean | undefined;
5
18
  resolvedServerOutput: "commonjs" | "module";
19
+ webOutput: NonNullable<Rspack.Configuration["output"]>;
6
20
  }) => void;
package/dist/index.cjs CHANGED
@@ -543,9 +543,16 @@ function combineURLs(baseURL, relativeURL) {
543
543
  function normalizeAssetPrefix(assetPrefix) {
544
544
  return assetPrefix && 'auto' !== assetPrefix ? assetPrefix.endsWith('/') ? assetPrefix : `${assetPrefix}/` : '/';
545
545
  }
546
- function resolveEffectiveAssetPrefix(config) {
547
- let outputPrefix = 'string' == typeof config.output?.assetPrefix ? config.output.assetPrefix : void 0;
548
- return config.isBuild ? normalizeAssetPrefix(outputPrefix) : normalizeAssetPrefix(('string' == typeof config.dev?.assetPrefix ? config.dev.assetPrefix : void 0) ?? outputPrefix);
546
+ const asString = (value)=>'string' == typeof value ? value : void 0, pickConfiguredAssetPrefix = ({ dev, output }, isBuild)=>isBuild ? asString(output?.assetPrefix) : asString(dev?.assetPrefix) ?? asString(output?.assetPrefix);
547
+ function resolveEffectiveAssetPrefix(config, ...fallbacks) {
548
+ for (let candidate of [
549
+ config,
550
+ ...fallbacks
551
+ ]){
552
+ let prefix = pickConfiguredAssetPrefix(candidate, config.isBuild);
553
+ if (prefix && 'auto' !== prefix) return normalizeAssetPrefix(prefix);
554
+ }
555
+ return '/';
549
556
  }
550
557
  function createRouteId(file) {
551
558
  return (0, external_pathe_namespaceObject.normalize)(file.replace(/\.[^/.]+$/, ''));
@@ -619,8 +626,27 @@ const resolveEntryWithTemplate = ({ appDirectory, entryName, templateName, templ
619
626
  asyncStartup: !0
620
627
  });
621
628
  }
622
- }, registerReactRouterEnvironmentOutput = ({ api, federation, resolvedServerOutput })=>{
623
- api.modifyEnvironmentConfig(async (config, { name, mergeEnvironmentConfig })=>'web' !== name && 'node' !== name ? config : mergeEnvironmentConfig(config, {
629
+ }, registerReactRouterEnvironmentOutput = ({ api, federation, resolvedServerOutput, webOutput })=>{
630
+ let nodeChunkLoading = 'module' === resolvedServerOutput ? 'import' : federation ? 'async-node' : 'require';
631
+ api.modifyRspackConfig((rspackConfig, { environment, mergeConfig })=>'web' === environment.name ? mergeConfig(rspackConfig, {
632
+ output: {
633
+ ...webOutput,
634
+ ...federation ? {
635
+ chunkLoading: 'import'
636
+ } : {}
637
+ }
638
+ }) : 'node' === environment.name ? mergeConfig(rspackConfig, {
639
+ output: {
640
+ chunkFormat: resolvedServerOutput,
641
+ chunkLoading: nodeChunkLoading,
642
+ devtoolModuleFilenameTemplate: '[absolute-resource-path]',
643
+ devtoolFallbackModuleFilenameTemplate: '[absolute-resource-path]?[hash]',
644
+ workerChunkLoading: nodeChunkLoading,
645
+ wasmLoading: 'fetch',
646
+ module: 'module' === resolvedServerOutput,
647
+ chunkFilename: 'static/js/async/[name].js'
648
+ }
649
+ }) : rspackConfig), api.modifyEnvironmentConfig(async (config, { name, mergeEnvironmentConfig })=>'web' !== name && 'node' !== name ? config : mergeEnvironmentConfig(config, {
624
650
  tools: {
625
651
  rspack: (rspackConfig)=>{
626
652
  if (federation && ensureFederationAsyncStartup(rspackConfig), 'node' === name) {
@@ -11790,14 +11816,7 @@ const createReactRouterManifestOptions = ({ routeChunks, routeModuleAnalysis })=
11790
11816
  routeModuleAnalysis
11791
11817
  } : {}
11792
11818
  };
11793
- }, orderChunkFiles = (chunkName, files)=>{
11794
- let ownChunkAsset = `${chunkName}.js`, ownFileIndex = files.findIndex((file)=>file.endsWith(ownChunkAsset));
11795
- return ownFileIndex <= 0 ? files : [
11796
- files[ownFileIndex],
11797
- ...files.slice(0, ownFileIndex),
11798
- ...files.slice(ownFileIndex + 1)
11799
- ];
11800
- }, collectManifestFilesByName = (items, names, getFiles)=>{
11819
+ }, isManifestJsAsset = (asset)=>/(?<!\.hot-update)\.[cm]?js(?:\?.*)?$/.test(asset), isManifestCssAsset = (asset)=>/\.css(?:\?.*)?$/.test(asset), collectManifestFilesByName = (items, names, getFiles)=>{
11801
11820
  let filesByName = {};
11802
11821
  if (!names) {
11803
11822
  for (let [name, item] of items)null != item && (filesByName[name] = getFiles(name, item));
@@ -11813,14 +11832,14 @@ const createReactRouterManifestOptions = ({ routeChunks, routeModuleAnalysis })=
11813
11832
  return filesByName;
11814
11833
  }, createReactRouterManifestStats = (compilation, chunkNames)=>{
11815
11834
  if (!compilation) return;
11816
- let assetsByChunkName = collectManifestFilesByName(compilation.namedChunks, chunkNames, (chunkName, chunk)=>orderChunkFiles(chunkName, Array.from(chunk.files ?? []))), entrypointFilesByName = compilation.entrypoints ? collectManifestFilesByName(compilation.entrypoints, chunkNames, (_name, entrypoint)=>Array.from(entrypoint.getFiles?.() ?? [])) : {};
11835
+ let assetsByChunkName = collectManifestFilesByName(compilation.namedChunks, chunkNames, (_chunkName, chunk)=>Array.from(chunk.files ?? [])), entrypointFilesByName = compilation.entrypoints ? collectManifestFilesByName(compilation.entrypoints, chunkNames, (_name, entrypoint)=>Array.from(entrypoint.getFiles?.() ?? [])) : {};
11817
11836
  return Object.keys(entrypointFilesByName).length > 0 ? {
11818
11837
  assetsByChunkName,
11819
11838
  entrypointFilesByName
11820
11839
  } : {
11821
11840
  assetsByChunkName
11822
11841
  };
11823
- }, DEFAULT_MANIFEST_DIR = DEFAULT_JS_DIST_PATH, CSS_IMPORT_RE = /\.(?:css|less|sass|scss)(?:\?[^'"`]+)?['"`]/, createChunkAssetResolver = (clientStats, includeEntrypointJs)=>{
11842
+ }, DEFAULT_MANIFEST_DIR = 'static/js', CSS_IMPORT_RE = /\.(?:css|less|sass|scss)(?:\?[^'"`]+)?['"`]/, createChunkAssetResolver = (clientStats, includeEntrypointJs)=>{
11824
11843
  let chunkAssetsByName = new Map();
11825
11844
  return (chunkName)=>{
11826
11845
  let cached = chunkAssetsByName.get(chunkName);
@@ -11829,16 +11848,16 @@ const createReactRouterManifestOptions = ({ routeChunks, routeModuleAnalysis })=
11829
11848
  if (!assets) {
11830
11849
  let result = {
11831
11850
  js: [
11832
- `${DEFAULT_JS_DIST_PATH}/${chunkName}.js`
11851
+ `${DEFAULT_MANIFEST_DIR}/${chunkName}.js`
11833
11852
  ],
11834
11853
  css: []
11835
11854
  };
11836
11855
  return chunkAssetsByName.set(chunkName, result), result;
11837
11856
  }
11838
11857
  let cssAssets = new Set(), jsAssets = new Set();
11839
- for (let asset of assets)asset.endsWith('.css') ? cssAssets.add(asset) : asset.endsWith('.js') && jsAssets.add(asset);
11840
- for (let asset of clientStats?.entrypointFilesByName?.[chunkName] ?? [])asset.endsWith('.css') ? cssAssets.add(asset) : includeEntrypointJs && asset.endsWith('.js') && jsAssets.add(asset);
11841
- 0 === jsAssets.size && jsAssets.add(`${DEFAULT_JS_DIST_PATH}/${chunkName}.js`);
11858
+ for (let asset of assets)isManifestCssAsset(asset) ? cssAssets.add(asset) : isManifestJsAsset(asset) && jsAssets.add(asset);
11859
+ for (let asset of clientStats?.entrypointFilesByName?.[chunkName] ?? [])isManifestCssAsset(asset) ? cssAssets.add(asset) : includeEntrypointJs && isManifestJsAsset(asset) && jsAssets.add(asset);
11860
+ if (0 === jsAssets.size) throw Error(`[react-router] Chunk "${chunkName}" emitted no JavaScript asset the browser manifest can reference (files: ${assets.join(', ') || 'none'}). Check the web \`output.filename.js\` scheme.`);
11842
11861
  let result = {
11843
11862
  js: [
11844
11863
  ...jsAssets
@@ -11851,7 +11870,7 @@ const createReactRouterManifestOptions = ({ routeChunks, routeModuleAnalysis })=
11851
11870
  };
11852
11871
  }, analyzeRouteForManifestEffect = ({ discoveredCssAssets, isBuild, routeChunkCache, routeChunkConfig, routeEntryName, routeFilePath, route, routeModuleAnalysis })=>tryPluginPromise(async ()=>{
11853
11872
  let { code, exports: exportNames } = await routeModuleAnalysis?.(routeFilePath, route) ?? await getRouteModuleAnalysis(routeFilePath), cssAssets = !isBuild && 0 === discoveredCssAssets.length && CSS_IMPORT_RE.test(code) ? [
11854
- `${DEFAULT_JS_DIST_PATH.replace('/js', '/css')}/${routeEntryName}.css`
11873
+ `${DEFAULT_MANIFEST_DIR.replace('/js', '/css')}/${routeEntryName}.css`
11855
11874
  ] : discoveredCssAssets, chunkInfo = isBuild && routeChunkConfig ? await detectRouteChunksIfEnabled(routeChunkCache, routeChunkConfig, routeFilePath, code) : null;
11856
11875
  return {
11857
11876
  cssAssets,
@@ -11865,9 +11884,9 @@ const createReactRouterManifestOptions = ({ routeChunks, routeModuleAnalysis })=
11865
11884
  routeModuleExports: [],
11866
11885
  hasRouteChunkByExportName: null
11867
11886
  })))), getManifestDirFromEntryAsset = (entryModulePath)=>{
11868
- if (!entryModulePath) return DEFAULT_JS_DIST_PATH;
11887
+ if (!entryModulePath) return DEFAULT_MANIFEST_DIR;
11869
11888
  let dir = (0, external_pathe_namespaceObject.dirname)(entryModulePath);
11870
- return '.' === dir ? DEFAULT_JS_DIST_PATH : dir;
11889
+ return '.' === dir ? DEFAULT_MANIFEST_DIR : dir;
11871
11890
  }, getReactRouterManifestPath = ({ version, isBuild, entryModulePath })=>{
11872
11891
  if (!isBuild) return 'static/js/virtual/react-router/browser-manifest.js';
11873
11892
  let dir = getManifestDirFromEntryAsset(entryModulePath);
@@ -12418,13 +12437,13 @@ const redirectStatusCodes = new Set([
12418
12437
  }), external_jsesc_namespaceObject = require("jsesc");
12419
12438
  var external_jsesc_default = __webpack_require__.n(external_jsesc_namespaceObject);
12420
12439
  const BROWSER_MANIFEST_ASSET = 'static/js/virtual/react-router/browser-manifest.js', ABSOLUTE_URL_RE = /^[a-zA-Z][a-zA-Z\d+\-.]*:/, toManifestAssetUrl = (assetPrefix, assetName)=>ABSOLUTE_URL_RE.test(assetName) || assetName.startsWith('//') || assetName.startsWith('/') ? assetName : combineURLs(assetPrefix, assetName), addIntegrity = (sri, assetPrefix, assetName, integrity)=>{
12421
- 'string' == typeof assetName && assetName.endsWith('.js') && 'string' == typeof integrity && (sri[toManifestAssetUrl(assetPrefix, assetName)] = integrity);
12440
+ 'string' == typeof assetName && isManifestJsAsset(assetName) && 'string' == typeof integrity && (sri[toManifestAssetUrl(assetPrefix, assetName)] = integrity);
12422
12441
  }, computeSubresourceIntegrity = (source)=>{
12423
12442
  if (source) return `sha384-${(0, external_node_crypto_namespaceObject.createHash)('sha384').update(source.source()).digest('base64')}`;
12424
12443
  }, collectSubresourceIntegrity = (stats, compilation, assetPrefix = '/')=>{
12425
12444
  let sri = {};
12426
12445
  for (let asset of stats?.assets ?? [])addIntegrity(sri, assetPrefix, asset.name, asset.integrity);
12427
- if ('function' == typeof compilation?.getAssets) for (let asset of compilation.getAssets())asset.name.endsWith('.js') && addIntegrity(sri, assetPrefix, asset.name, computeSubresourceIntegrity(asset.source) ?? asset.info?.integrity);
12446
+ if ('function' == typeof compilation?.getAssets) for (let asset of compilation.getAssets())isManifestJsAsset(asset.name) && addIntegrity(sri, assetPrefix, asset.name, computeSubresourceIntegrity(asset.source) ?? asset.info?.integrity);
12428
12447
  return Object.keys(sri).length > 0 ? sri : void 0;
12429
12448
  };
12430
12449
  function registerModifyBrowserManifestAssets(api, routes, pluginOptions, appDirectory, assetPrefix = '/', routeChunkOptions, options) {
@@ -12444,7 +12463,7 @@ function registerModifyBrowserManifestAssets(api, routes, pluginOptions, appDire
12444
12463
  compilation.updateAsset(BROWSER_MANIFEST_ASSET, new sources.RawSource(newSource));
12445
12464
  }
12446
12465
  if (isBuild) {
12447
- let entryAssets = stats?.assetsByChunkName?.['entry.client'], entryJsAssets = entryAssets?.filter((asset)=>asset.endsWith('.js')) || [], manifestPath = getReactRouterManifestPath({
12466
+ let entryAssets = stats?.assetsByChunkName?.['entry.client'], entryJsAssets = entryAssets?.filter(isManifestJsAsset) || [], manifestPath = getReactRouterManifestPath({
12448
12467
  version: manifest.version,
12449
12468
  isBuild: !0,
12450
12469
  entryModulePath: entryJsAssets[0]
@@ -14418,12 +14437,14 @@ export function EnsureClientRouteModuleForHMR___() { return ___EnsureClientRoute
14418
14437
  }, createServerRouteEntry = async (options)=>{
14419
14438
  let ast, plan = await createRscRouteExportPlan(options);
14420
14439
  validateRscRouteExportPlan(plan, options);
14421
- let lines = [], needsReactImport = !1, needsEnsureHmrImport = !1, needsStyleEntryImport = !1, streamsClientRouteCss = !plan.exportNames.some(isServerComponentExport) && plan.exportNames.includes('default') && programHasSideEffectStyleImports((ast = yuku_parse(options.code, {
14440
+ let lines = [], needsReactImport = !1, needsEnsureHmrImport = !1, needsStyleEntryImport = !1, pushStylesheetLinks = (entryCssFilesExpression)=>{
14441
+ lines.push(` ...(${entryCssFilesExpression} ?? []).map(href =>`), lines.push(' React.createElement("link", { key: href, rel: "stylesheet", href: href, precedence: "default" })),');
14442
+ }, streamsClientRouteCss = !plan.exportNames.some(isServerComponentExport) && plan.exportNames.includes('default') && programHasSideEffectStyleImports((ast = yuku_parse(options.code, {
14422
14443
  sourceType: 'module'
14423
14444
  })).program ?? ast);
14424
14445
  for (let exportName of plan.exportNames){
14425
14446
  if (streamsClientRouteCss && 'default' === exportName) {
14426
- needsReactImport = !0, needsStyleEntryImport = !0, lines.push(`import RscClientRouteDefault___ from ${JSON.stringify(plan.clientTargetFor('default'))};`), lines.push('export default function RscClientRouteWithStyles___(props) {'), lines.push(' return React.createElement(React.Fragment, null,'), lines.push(` ...(${RSC_ROUTE_STYLE_ENTRY_EXPORT}.entryCssFiles ?? []).map(href =>`), lines.push(' React.createElement("link", { key: href, rel: "stylesheet", href: href, precedence: "default" })),'), lines.push(' React.createElement(RscClientRouteDefault___, props),'), lines.push(' );'), lines.push('}');
14447
+ needsReactImport = !0, needsStyleEntryImport = !0, lines.push(`import RscClientRouteDefault___ from ${JSON.stringify(plan.clientTargetFor('default'))};`), lines.push('export default function RscClientRouteWithStyles___(props) {'), lines.push(' return React.createElement(React.Fragment, null,'), pushStylesheetLinks(`${RSC_ROUTE_STYLE_ENTRY_EXPORT}.entryCssFiles`), lines.push(' React.createElement(RscClientRouteDefault___, props),'), lines.push(' );'), lines.push('}');
14427
14448
  continue;
14428
14449
  }
14429
14450
  if (isClientRouteExport(exportName)) {
@@ -14431,7 +14452,7 @@ export function EnsureClientRouteModuleForHMR___() { return ___EnsureClientRoute
14431
14452
  continue;
14432
14453
  }
14433
14454
  if (isServerComponentExport(exportName)) {
14434
- needsReactImport = !0, needsEnsureHmrImport = !0, lines.push(`import { ${exportName} as ${exportName}WithoutClientChunk } from ${JSON.stringify(plan.serverTarget)};`), lines.push(`export function ${exportName}(props) {`), lines.push(' return React.createElement(React.Fragment, null,'), lines.push(` ...(${exportName}WithoutClientChunk.entryCssFiles ?? []).map(href =>`), lines.push(' React.createElement("link", { key: href, rel: "stylesheet", href: href, precedence: "default" })),'), lines.push(' React.createElement(EnsureClientRouteModuleForHMR___, null),'), lines.push(` React.createElement(${exportName}WithoutClientChunk, props),`), lines.push(' );'), lines.push('}');
14455
+ needsReactImport = !0, needsEnsureHmrImport = !0, lines.push(`import { ${exportName} as ${exportName}WithoutClientChunk } from ${JSON.stringify(plan.serverTarget)};`), lines.push(`export function ${exportName}(props) {`), lines.push(' return React.createElement(React.Fragment, null,'), pushStylesheetLinks(`${exportName}WithoutClientChunk.entryCssFiles`), lines.push(' React.createElement(EnsureClientRouteModuleForHMR___, null),'), lines.push(` React.createElement(${exportName}WithoutClientChunk, props),`), lines.push(' );'), lines.push('}');
14435
14456
  continue;
14436
14457
  }
14437
14458
  lines.push(createReexport(exportName, plan.serverTarget));
@@ -14689,6 +14710,7 @@ export {
14689
14710
  'allowed-action-origins',
14690
14711
  'client-version',
14691
14712
  'react-router-serve-config',
14713
+ 'manifest-prefix',
14692
14714
  "bootstrap-scripts",
14693
14715
  'server-manifest'
14694
14716
  ], createReactRouterRscResolveAliases = (rootPath, options = {})=>({
@@ -14710,8 +14732,8 @@ export {
14710
14732
  ];
14711
14733
  })),
14712
14734
  'react-router/internal/react-server-client': (0, external_pathe_namespaceObject.resolve)(rootPath, getVirtualModuleFilePath('virtual/react-router/rsc-internal-client'))
14713
- }), createReactRouterRscVirtualModules = ({ allowedActionOrigins, appDirectory, basename, buildDirectory, isBuild, jsDistPath, outputClientPath, publicPath, routeDiscovery, routes, ssr })=>{
14714
- let rscAssetsBuildDirectory = (0, external_pathe_namespaceObject.relative)((0, external_pathe_namespaceObject.resolve)(buildDirectory, 'server'), outputClientPath), bootstrapPublicPath = normalizeAssetPrefix(publicPath);
14735
+ }), createReactRouterRscVirtualModules = ({ allowedActionOrigins, appDirectory, basename, buildDirectory, isBuild, outputClientPath, publicPath, routeDiscovery, routes, ssr })=>{
14736
+ let rscAssetsBuildDirectory = (0, external_pathe_namespaceObject.relative)((0, external_pathe_namespaceObject.resolve)(buildDirectory, 'server'), outputClientPath), serverPublicPath = normalizeAssetPrefix(publicPath);
14715
14737
  return {
14716
14738
  'virtual/react-router/unstable_rsc/routes': createRscRouteConfig({
14717
14739
  appDirectory,
@@ -14733,9 +14755,33 @@ export {
14733
14755
  assetsBuildDirectory: rscAssetsBuildDirectory,
14734
14756
  publicPath
14735
14757
  }),
14736
- "virtual/react-router/unstable_rsc/bootstrap-scripts": defaultExport([
14737
- combineURLs(bootstrapPublicPath, `${jsDistPath}/index.js`)
14738
- ]),
14758
+ 'virtual/react-router/unstable_rsc/manifest-prefix': `const manifest = __webpack_require__.rscM;
14759
+ const serverPrefix = ${JSON.stringify(serverPublicPath)};
14760
+ const appliedPrefix = manifest?.moduleLoading?.prefix;
14761
+ if (appliedPrefix && appliedPrefix !== serverPrefix) {
14762
+ const rewrite = url =>
14763
+ typeof url === "string" && url.startsWith(appliedPrefix)
14764
+ ? serverPrefix + url.slice(appliedPrefix.length)
14765
+ : url;
14766
+ const rewriteAll = list => {
14767
+ if (Array.isArray(list)) for (let i = 0; i < list.length; i++) list[i] = rewrite(list[i]);
14768
+ };
14769
+ manifest.moduleLoading.prefix = serverPrefix;
14770
+ rewriteAll(manifest.entryJsFiles);
14771
+ for (const files of Object.values(manifest.entryCssFiles ?? {})) rewriteAll(files);
14772
+ for (const reference of Object.values(manifest.clientManifest ?? {})) rewriteAll(reference.cssFiles);
14773
+ }
14774
+ export const rscManifest = manifest;
14775
+ `,
14776
+ "virtual/react-router/unstable_rsc/bootstrap-scripts": `import { rscManifest } from "virtual/react-router/unstable_rsc/manifest-prefix";
14777
+ const entryJsFiles = rscManifest?.entryJsFiles;
14778
+ if (!entryJsFiles?.length) {
14779
+ throw new Error(
14780
+ "[rsbuild-plugin-react-router] The rspack RSC manifest lists no browser entry script (entryJsFiles is empty), so the server cannot render bootstrap scripts. Rspack only records entry files whose name ends in \\".js\\"; web output.filename.js values with a query (for example \\"[name].js?v=[contenthash:8]\\") or another extension are not supported in RSC mode."
14781
+ );
14782
+ }
14783
+ export default entryJsFiles;
14784
+ `,
14739
14785
  'virtual/react-router/unstable_rsc/server-manifest': `export default function getServerManifest() {
14740
14786
  return __webpack_require__.rscM?.serverManifest;
14741
14787
  }
@@ -15591,13 +15637,12 @@ export {
15591
15637
  layer: RSC_LAYERS.rsc
15592
15638
  }
15593
15639
  },
15594
- createVirtualModules: (publicPath, jsDistPath)=>createReactRouterRscVirtualModules({
15640
+ createVirtualModules: (publicPath)=>createReactRouterRscVirtualModules({
15595
15641
  allowedActionOrigins: allowedActionOriginsForBuild,
15596
15642
  appDirectory,
15597
15643
  basename,
15598
15644
  buildDirectory,
15599
15645
  isBuild,
15600
- jsDistPath,
15601
15646
  outputClientPath,
15602
15647
  publicPath,
15603
15648
  routeDiscovery,
@@ -15691,7 +15736,7 @@ export {
15691
15736
  defaultEntryName,
15692
15737
  serverBundleEntries: artifacts.serverBundleEntries
15693
15738
  }),
15694
- createVirtualModules: (publicPath, _jsDistPath)=>createClassicVirtualModules({
15739
+ createVirtualModules: (publicPath)=>createClassicVirtualModules({
15695
15740
  allowedActionOrigins: allowedActionOriginsForBuild,
15696
15741
  appDirectory,
15697
15742
  assetsBuildDirectory,
@@ -15726,10 +15771,7 @@ export {
15726
15771
  library: {
15727
15772
  type: 'module'
15728
15773
  },
15729
- module: !0,
15730
- ...isBuild ? {
15731
- chunkFilename: 'static/js/async/[id]-[contenthash:16].js'
15732
- } : {}
15774
+ module: !0
15733
15775
  },
15734
15776
  webOptimization: {
15735
15777
  avoidEntryIife: !0,
@@ -15811,11 +15853,14 @@ export {
15811
15853
  }), api.onBeforeBuild(()=>{
15812
15854
  warnOnClientSourceMaps(api.getNormalizedConfig(), (msg)=>api.logger.warn(msg), 'web');
15813
15855
  }), api.onBeforeCreateCompiler(()=>{
15814
- let normalized = api.getNormalizedConfig();
15856
+ let root = api.getNormalizedConfig(), web = root.environments.web;
15815
15857
  assetPrefix = resolveEffectiveAssetPrefix({
15816
- dev: normalized.dev,
15817
- output: normalized.output,
15858
+ dev: web?.dev,
15859
+ output: web?.output,
15818
15860
  isBuild: 'build' === api.context.action
15861
+ }, {
15862
+ dev: root.dev,
15863
+ output: root.output
15819
15864
  });
15820
15865
  });
15821
15866
  let configPath = findEntryFile((0, external_pathe_namespaceObject.resolve)('react-router.config')), configExists = (0, external_node_fs_namespaceObject.existsSync)(configPath), configWatchPaths = configExists ? configPath : JS_EXTENSIONS.map((extension)=>(0, external_pathe_namespaceObject.resolve)(`react-router.config${extension}`)), reactRouterUserConfig = {};
@@ -16083,13 +16128,16 @@ export {
16083
16128
  prerenderPaths: modePlan.prerenderPaths,
16084
16129
  basename
16085
16130
  })))), api.modifyRsbuildConfig(async (config, { mergeRsbuildConfig })=>{
16086
- let webDistPath = config.environments?.web?.output?.distPath, rootDistPath = config.output?.distPath, jsDistPath = ('object' == typeof webDistPath ? webDistPath.js : void 0) ?? ('object' == typeof rootDistPath ? rootDistPath.js : void 0) ?? DEFAULT_JS_DIST_PATH, assetPrefix = resolveEffectiveAssetPrefix({
16087
- dev: config.dev,
16088
- output: config.output,
16131
+ let publicPath, webConfig = config.environments?.web, webJsFilename = webConfig?.output?.filename?.js ?? config.output?.filename?.js;
16132
+ if (isRscMode && 'string' == typeof webJsFilename && !/\.js$/.test(webJsFilename)) throw Error(`[${PLUGIN_NAME}] RSC mode requires web \`output.filename.js\` to end in ".js" (got ${JSON.stringify(webJsFilename)}): rspack's RSC manifest omits entry files with a query or another extension, so the server could not render bootstrap scripts.`);
16133
+ let vmodPlugin = (publicPath = resolveEffectiveAssetPrefix({
16134
+ dev: webConfig?.dev,
16135
+ output: webConfig?.output,
16089
16136
  isBuild
16090
- }), vmodPlugin = new core_namespaceObject.rspack.experiments.VirtualModulesPlugin(mapVirtualModules(modePlan.createVirtualModules(assetPrefix, jsDistPath))), useAsyncNodeChunkLoading = options.federation && 'commonjs' === resolvedServerOutput, nodeChunkLoading = 'require';
16091
- 'module' === resolvedServerOutput ? nodeChunkLoading = 'import' : useAsyncNodeChunkLoading && (nodeChunkLoading = 'async-node');
16092
- let guardedLazyCompilation = guardReactRouterLazyCompilation({
16137
+ }, {
16138
+ dev: config.dev,
16139
+ output: config.output
16140
+ }), new core_namespaceObject.rspack.experiments.VirtualModulesPlugin(mapVirtualModules(modePlan.createVirtualModules(publicPath)))), guardedLazyCompilation = guardReactRouterLazyCompilation({
16093
16141
  lazyCompilation: Object.prototype.hasOwnProperty.call(options, 'lazyCompilation') ? pluginOptions.lazyCompilation : config.dev?.lazyCompilation ?? pluginOptions.lazyCompilation,
16094
16142
  entryClientPath: isRscMode ? finalEntryRscClientPath : finalEntryClientPath,
16095
16143
  prewarmReactRouterModules: !!pluginOptions.unstableLazyCompilationPrewarm
@@ -16143,9 +16191,6 @@ export {
16143
16191
  }
16144
16192
  },
16145
16193
  output: {
16146
- filename: {
16147
- js: '[name].js'
16148
- },
16149
16194
  distPath: {
16150
16195
  root: outputClientPath
16151
16196
  }
@@ -16164,13 +16209,6 @@ export {
16164
16209
  ]
16165
16210
  },
16166
16211
  externalsType: modePlan.webExternalsType,
16167
- output: {
16168
- ...modePlan.webOutput,
16169
- publicPath: assetPrefix,
16170
- ...options.federation ? {
16171
- chunkLoading: 'import'
16172
- } : {}
16173
- },
16174
16212
  optimization: modePlan.webOptimization
16175
16213
  }
16176
16214
  }
@@ -16208,17 +16246,7 @@ export {
16208
16246
  },
16209
16247
  externals: modePlan.nodeExternals,
16210
16248
  ...modePlan.nodeDependencies,
16211
- externalsType: resolvedServerOutput,
16212
- output: {
16213
- chunkFormat: resolvedServerOutput,
16214
- chunkLoading: nodeChunkLoading,
16215
- devtoolModuleFilenameTemplate: '[absolute-resource-path]',
16216
- devtoolFallbackModuleFilenameTemplate: '[absolute-resource-path]?[hash]',
16217
- workerChunkLoading: nodeChunkLoading,
16218
- wasmLoading: 'fetch',
16219
- module: 'module' === resolvedServerOutput,
16220
- chunkFilename: 'static/js/async/[name].js'
16221
- }
16249
+ externalsType: resolvedServerOutput
16222
16250
  }
16223
16251
  }
16224
16252
  }
@@ -16227,7 +16255,8 @@ export {
16227
16255
  }), registerReactRouterEnvironmentOutput({
16228
16256
  api,
16229
16257
  federation: pluginOptions.federation,
16230
- resolvedServerOutput
16258
+ resolvedServerOutput,
16259
+ webOutput: modePlan.webOutput
16231
16260
  }), 'classic' === modePlan.kind && useRouteModuleTransformLoader && api.modifyEnvironmentConfig(async (config, { name, mergeEnvironmentConfig })=>'web' !== name && 'node' !== name ? config : mergeEnvironmentConfig(config, {
16232
16261
  tools: {
16233
16262
  rspack: (rspackConfig)=>{