rsbuild-plugin-react-router 0.6.5 → 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/dist/index.js CHANGED
@@ -7356,7 +7356,7 @@ let createReactRouterManifestOptions = ({ routeChunks, routeModuleAnalysis })=>{
7356
7356
  routeModuleAnalysis
7357
7357
  } : {}
7358
7358
  };
7359
- }, collectManifestFilesByName = (items, names, getFiles)=>{
7359
+ }, isManifestJsAsset = (asset)=>/(?<!\.hot-update)\.[cm]?js(?:\?.*)?$/.test(asset), isManifestCssAsset = (asset)=>/\.css(?:\?.*)?$/.test(asset), collectManifestFilesByName = (items, names, getFiles)=>{
7360
7360
  let filesByName = {};
7361
7361
  if (!names) {
7362
7362
  for (let [name, item] of items)null != item && (filesByName[name] = getFiles(name, item));
@@ -7372,15 +7372,7 @@ let createReactRouterManifestOptions = ({ routeChunks, routeModuleAnalysis })=>{
7372
7372
  return filesByName;
7373
7373
  }, createReactRouterManifestStats = (compilation, chunkNames)=>{
7374
7374
  if (!compilation) return;
7375
- let assetsByChunkName = collectManifestFilesByName(compilation.namedChunks, chunkNames, (chunkName, chunk)=>{
7376
- var files;
7377
- let ownChunkAsset, ownFileIndex;
7378
- return files = Array.from(chunk.files ?? []), ownChunkAsset = `${chunkName}.js`, (ownFileIndex = files.findIndex((file)=>file.endsWith(ownChunkAsset))) <= 0 ? files : [
7379
- files[ownFileIndex],
7380
- ...files.slice(0, ownFileIndex),
7381
- ...files.slice(ownFileIndex + 1)
7382
- ];
7383
- }), entrypointFilesByName = compilation.entrypoints ? collectManifestFilesByName(compilation.entrypoints, chunkNames, (_name, entrypoint)=>Array.from(entrypoint.getFiles?.() ?? [])) : {};
7375
+ 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?.() ?? [])) : {};
7384
7376
  return Object.keys(entrypointFilesByName).length > 0 ? {
7385
7377
  assetsByChunkName,
7386
7378
  entrypointFilesByName
@@ -7416,9 +7408,9 @@ async function generateReactRouterManifestForDev(routes, _options, clientStats,
7416
7408
  return chunkAssetsByName.set(chunkName, result), result;
7417
7409
  }
7418
7410
  let cssAssets = new Set(), jsAssets = new Set();
7419
- for (let asset of assets)asset.endsWith('.css') ? cssAssets.add(asset) : asset.endsWith('.js') && jsAssets.add(asset);
7420
- for (let asset of clientStats?.entrypointFilesByName?.[chunkName] ?? [])asset.endsWith('.css') ? cssAssets.add(asset) : isBuild && asset.endsWith('.js') && jsAssets.add(asset);
7421
- 0 === jsAssets.size && jsAssets.add(`${DEFAULT_JS_DIST_PATH}/${chunkName}.js`);
7411
+ for (let asset of assets)isManifestCssAsset(asset) ? cssAssets.add(asset) : isManifestJsAsset(asset) && jsAssets.add(asset);
7412
+ for (let asset of clientStats?.entrypointFilesByName?.[chunkName] ?? [])isManifestCssAsset(asset) ? cssAssets.add(asset) : isBuild && isManifestJsAsset(asset) && jsAssets.add(asset);
7413
+ 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.`);
7422
7414
  let result = {
7423
7415
  js: [
7424
7416
  ...jsAssets
@@ -7906,7 +7898,7 @@ let redirectStatusCodes = new Set([
7906
7898
  }
7907
7899
  };
7908
7900
  }, BROWSER_MANIFEST_ASSET = 'static/js/virtual/react-router/browser-manifest.js', ABSOLUTE_URL_RE = /^[a-zA-Z][a-zA-Z\d+\-.]*:/, addIntegrity = (sri, assetPrefix, assetName, integrity)=>{
7909
- 'string' == typeof assetName && assetName.endsWith('.js') && 'string' == typeof integrity && (sri[ABSOLUTE_URL_RE.test(assetName) || assetName.startsWith('//') || assetName.startsWith('/') ? assetName : combineURLs(assetPrefix, assetName)] = integrity);
7901
+ 'string' == typeof assetName && isManifestJsAsset(assetName) && 'string' == typeof integrity && (sri[ABSOLUTE_URL_RE.test(assetName) || assetName.startsWith('//') || assetName.startsWith('/') ? assetName : combineURLs(assetPrefix, assetName)] = integrity);
7910
7902
  }, computeSubresourceIntegrity = (source)=>{
7911
7903
  if (source) return `sha384-${createHash('sha384').update(source.source()).digest('base64')}`;
7912
7904
  };
@@ -8596,12 +8588,14 @@ export function EnsureClientRouteModuleForHMR___() { return ___EnsureClientRoute
8596
8588
  }, createServerRouteEntry = async (options)=>{
8597
8589
  let plan = await createRscRouteExportPlan(options);
8598
8590
  validateRscRouteExportPlan(plan, options);
8599
- let lines = [], needsReactImport = !1, needsEnsureHmrImport = !1, needsStyleEntryImport = !1, streamsClientRouteCss = !plan.exportNames.some(isServerComponentExport) && plan.exportNames.includes('default') && programHasSideEffectStyleImports(getProgram(yuku_parse(options.code, {
8591
+ let lines = [], needsReactImport = !1, needsEnsureHmrImport = !1, needsStyleEntryImport = !1, pushStylesheetLinks = (entryCssFilesExpression)=>{
8592
+ lines.push(` ...(${entryCssFilesExpression} ?? []).map(href =>`), lines.push(' React.createElement("link", { key: href, rel: "stylesheet", href: href, precedence: "default" })),');
8593
+ }, streamsClientRouteCss = !plan.exportNames.some(isServerComponentExport) && plan.exportNames.includes('default') && programHasSideEffectStyleImports(getProgram(yuku_parse(options.code, {
8600
8594
  sourceType: 'module'
8601
8595
  })));
8602
8596
  for (let exportName of plan.exportNames){
8603
8597
  if (streamsClientRouteCss && 'default' === exportName) {
8604
- 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('}');
8598
+ 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('}');
8605
8599
  continue;
8606
8600
  }
8607
8601
  if (isClientRouteExport(exportName)) {
@@ -8609,7 +8603,7 @@ export function EnsureClientRouteModuleForHMR___() { return ___EnsureClientRoute
8609
8603
  continue;
8610
8604
  }
8611
8605
  if (isServerComponentExport(exportName)) {
8612
- 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('}');
8606
+ 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('}');
8613
8607
  continue;
8614
8608
  }
8615
8609
  lines.push(createReexport(exportName, plan.serverTarget));
@@ -8803,6 +8797,7 @@ export function EnsureClientRouteModuleForHMR___() { return ___EnsureClientRoute
8803
8797
  'allowed-action-origins',
8804
8798
  'client-version',
8805
8799
  'react-router-serve-config',
8800
+ 'manifest-prefix',
8806
8801
  "bootstrap-scripts",
8807
8802
  'server-manifest'
8808
8803
  ], setupReactRouterRscPlugin = async ({ api, entryRscPath, entrySsrPath, pluginName, rsc })=>{
@@ -9500,7 +9495,7 @@ export function EnsureClientRouteModuleForHMR___() { return ___EnsureClientRoute
9500
9495
  routesByServerBundleId,
9501
9496
  serverBundleEntries: serverBuildPlan.serverBundleEntries
9502
9497
  };
9503
- }, RSC_LAYERS = rspack.experiments.rsc.Layers, createRscModePlan = async ({ allowedActionOriginsForBuild, api, appDirectory, basename, buildDirectory, customServer, finalEntryRscClientPath, finalEntryRscPath, isBuild, outputClientPath, pluginName, prerenderConfig, routeConfig, routeDiscovery, routes, rootRouteFile, serverBuildFile, splitRouteModules, ssr })=>{
9498
+ }, RSC_LAYERS = rspack.experiments.rsc.Layers, createRscModePlan = async ({ allowedActionOriginsForBuild, api, appDirectory, basename, buildDirectory, customServer, finalEntryRscClientPath, finalEntryRscPath, finalEntryRscSsrPath, isBuild, outputClientPath, pluginName, prerenderConfig, routeConfig, routeDiscovery, routes, rootRouteFile, serverBuildFile, splitRouteModules, ssr })=>{
9504
9499
  let rscServerEntryName = (serverBuildFile || 'index.js').replace(/\.js$/, '');
9505
9500
  return {
9506
9501
  kind: 'rsc',
@@ -9528,8 +9523,8 @@ export function EnsureClientRouteModuleForHMR___() { return ___EnsureClientRoute
9528
9523
  layer: RSC_LAYERS.rsc
9529
9524
  }
9530
9525
  },
9531
- createVirtualModules: (publicPath, jsDistPath)=>(({ allowedActionOrigins, appDirectory, basename, buildDirectory, isBuild, jsDistPath, outputClientPath, publicPath, routeDiscovery, routes, ssr })=>{
9532
- let rscAssetsBuildDirectory = relative(external_pathe_resolve(buildDirectory, 'server'), outputClientPath), bootstrapPublicPath = normalizeAssetPrefix(publicPath);
9526
+ createVirtualModules: (publicPath)=>(({ allowedActionOrigins, appDirectory, basename, buildDirectory, isBuild, outputClientPath, publicPath, routeDiscovery, routes, ssr })=>{
9527
+ let rscAssetsBuildDirectory = relative(external_pathe_resolve(buildDirectory, 'server'), outputClientPath), serverPublicPath = normalizeAssetPrefix(publicPath);
9533
9528
  return {
9534
9529
  'virtual/react-router/unstable_rsc/routes': (({ appDirectory, routes })=>{
9535
9530
  let componentResolutionCode = RSC_ROUTE_COMPONENT_EXPORTS.map(({ routeProperty, clientExport, serverExport })=>{
@@ -9625,9 +9620,33 @@ export default [`;
9625
9620
  assetsBuildDirectory: rscAssetsBuildDirectory,
9626
9621
  publicPath
9627
9622
  }),
9628
- "virtual/react-router/unstable_rsc/bootstrap-scripts": defaultExport([
9629
- combineURLs(bootstrapPublicPath, `${jsDistPath}/index.js`)
9630
- ]),
9623
+ 'virtual/react-router/unstable_rsc/manifest-prefix': `const manifest = __webpack_require__.rscM;
9624
+ const serverPrefix = ${JSON.stringify(serverPublicPath)};
9625
+ const appliedPrefix = manifest?.moduleLoading?.prefix;
9626
+ if (appliedPrefix && appliedPrefix !== serverPrefix) {
9627
+ const rewrite = url =>
9628
+ typeof url === "string" && url.startsWith(appliedPrefix)
9629
+ ? serverPrefix + url.slice(appliedPrefix.length)
9630
+ : url;
9631
+ const rewriteAll = list => {
9632
+ if (Array.isArray(list)) for (let i = 0; i < list.length; i++) list[i] = rewrite(list[i]);
9633
+ };
9634
+ manifest.moduleLoading.prefix = serverPrefix;
9635
+ rewriteAll(manifest.entryJsFiles);
9636
+ for (const files of Object.values(manifest.entryCssFiles ?? {})) rewriteAll(files);
9637
+ for (const reference of Object.values(manifest.clientManifest ?? {})) rewriteAll(reference.cssFiles);
9638
+ }
9639
+ export const rscManifest = manifest;
9640
+ `,
9641
+ "virtual/react-router/unstable_rsc/bootstrap-scripts": `import { rscManifest } from "virtual/react-router/unstable_rsc/manifest-prefix";
9642
+ const entryJsFiles = rscManifest?.entryJsFiles;
9643
+ if (!entryJsFiles?.length) {
9644
+ throw new Error(
9645
+ "[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."
9646
+ );
9647
+ }
9648
+ export default entryJsFiles;
9649
+ `,
9631
9650
  'virtual/react-router/unstable_rsc/server-manifest': `export default function getServerManifest() {
9632
9651
  return __webpack_require__.rscM?.serverManifest;
9633
9652
  }
@@ -9667,7 +9686,6 @@ export {
9667
9686
  basename,
9668
9687
  buildDirectory,
9669
9688
  isBuild,
9670
- jsDistPath,
9671
9689
  outputClientPath,
9672
9690
  publicPath,
9673
9691
  routeDiscovery,
@@ -9679,22 +9697,28 @@ export {
9679
9697
  external_pathe_resolve(rootPath, 'node_modules'),
9680
9698
  'node_modules'
9681
9699
  ],
9682
- alias: {
9683
- ...Object.fromEntries(RSC_VIRTUAL_ALIAS_IDS.flatMap((id)=>{
9684
- let moduleId = `virtual/react-router/unstable_rsc/${id}`, modulePath = external_pathe_resolve(rootPath, getVirtualModuleFilePath(moduleId));
9685
- return [
9686
- [
9687
- `virtual:react-router/unstable_rsc/${id}`,
9688
- modulePath
9689
- ],
9690
- [
9691
- moduleId,
9692
- modulePath
9693
- ]
9694
- ];
9695
- })),
9696
- 'react-router/internal/react-server-client': external_pathe_resolve(rootPath, getVirtualModuleFilePath('virtual/react-router/rsc-internal-client'))
9697
- }
9700
+ alias: ((rootPath, options = {})=>({
9701
+ ...options.entrySsrPath ? {
9702
+ 'virtual:react-router/unstable_rsc/entry-ssr': options.entrySsrPath,
9703
+ 'virtual/react-router/unstable_rsc/entry-ssr': options.entrySsrPath
9704
+ } : {},
9705
+ ...Object.fromEntries(RSC_VIRTUAL_ALIAS_IDS.flatMap((id)=>{
9706
+ let moduleId = `virtual/react-router/unstable_rsc/${id}`, modulePath = external_pathe_resolve(rootPath, getVirtualModuleFilePath(moduleId));
9707
+ return [
9708
+ [
9709
+ `virtual:react-router/unstable_rsc/${id}`,
9710
+ modulePath
9711
+ ],
9712
+ [
9713
+ moduleId,
9714
+ modulePath
9715
+ ]
9716
+ ];
9717
+ })),
9718
+ 'react-router/internal/react-server-client': external_pathe_resolve(rootPath, getVirtualModuleFilePath('virtual/react-router/rsc-internal-client'))
9719
+ }))(rootPath, {
9720
+ entrySsrPath: finalEntryRscSsrPath
9721
+ })
9698
9722
  }),
9699
9723
  server: customServer ? void 0 : {
9700
9724
  setup: function({ entryName, pluginName }) {
@@ -9843,7 +9867,7 @@ export {
9843
9867
  defaultEntryName,
9844
9868
  serverBundleEntries: artifacts.serverBundleEntries
9845
9869
  }),
9846
- createVirtualModules: (publicPath, _jsDistPath)=>(({ allowedActionOrigins, appDirectory, assetsBuildDirectory, basename, devHmrRuntimeModule, entryServerPath, future, isSpaMode, prerenderPaths, publicPath, routeDiscovery, routes, routesByServerBundleId, ssr })=>{
9870
+ createVirtualModules: (publicPath)=>(({ allowedActionOrigins, appDirectory, assetsBuildDirectory, basename, devHmrRuntimeModule, entryServerPath, future, isSpaMode, prerenderPaths, publicPath, routeDiscovery, routes, routesByServerBundleId, ssr })=>{
9847
9871
  let serverBuildOptions = {
9848
9872
  entryServerPath,
9849
9873
  assetsBuildDirectory,
@@ -9932,10 +9956,7 @@ export {
9932
9956
  library: {
9933
9957
  type: 'module'
9934
9958
  },
9935
- module: !0,
9936
- ...isBuild ? {
9937
- chunkFilename: 'static/js/async/[id]-[contenthash:16].js'
9938
- } : {}
9959
+ module: !0
9939
9960
  },
9940
9961
  webOptimization: {
9941
9962
  avoidEntryIife: !0,
@@ -10099,11 +10120,14 @@ export {
10099
10120
  (isSourceMapEnabled(sourceMapSetting) || !0 === devtoolSetting || ('string' == typeof devtoolSetting ? devtoolSetting.includes('source-map') : null !== devtoolSetting && 'object' == typeof devtoolSetting)) && warn("\n WARNING: Source maps are enabled in production\n This makes your server code publicly visible in the browser.\n This is highly discouraged! If you insist, ensure that you are using\n environment variables for secrets and not hard-coding them in your source code.\n");
10100
10121
  }(api.getNormalizedConfig(), (msg)=>api.logger.warn(msg), 'web');
10101
10122
  }), api.onBeforeCreateCompiler(()=>{
10102
- let normalized = api.getNormalizedConfig();
10123
+ let root = api.getNormalizedConfig(), web = root.environments.web;
10103
10124
  assetPrefix = resolveEffectiveAssetPrefix({
10104
- dev: normalized.dev,
10105
- output: normalized.output,
10125
+ dev: web?.dev,
10126
+ output: web?.output,
10106
10127
  isBuild: 'build' === api.context.action
10128
+ }, {
10129
+ dev: root.dev,
10130
+ output: root.output
10107
10131
  });
10108
10132
  });
10109
10133
  let configPath = findEntryFile(external_pathe_resolve('react-router.config')), configExists = existsSync(configPath), configWatchPaths = configExists ? configPath : JS_EXTENSIONS.map((extension)=>external_pathe_resolve(`react-router.config${extension}`)), reactRouterUserConfig1 = {};
@@ -10501,6 +10525,7 @@ export {
10501
10525
  buildDirectory,
10502
10526
  finalEntryRscClientPath,
10503
10527
  finalEntryRscPath,
10528
+ finalEntryRscSsrPath,
10504
10529
  outputClientPath,
10505
10530
  pluginName: PLUGIN_NAME,
10506
10531
  serverBuildFile
@@ -10927,16 +10952,19 @@ if (typeof window !== 'undefined' && import.meta.webpackHot) {
10927
10952
  basename
10928
10953
  })))), api.modifyRsbuildConfig(async (config, { mergeRsbuildConfig })=>{
10929
10954
  var existing;
10930
- let publicPath, jsDistPath, webDistPath = config.environments?.web?.output?.distPath, rootDistPath = config.output?.distPath, jsDistPath1 = ('object' == typeof webDistPath ? webDistPath.js : void 0) ?? ('object' == typeof rootDistPath ? rootDistPath.js : void 0) ?? DEFAULT_JS_DIST_PATH, assetPrefix = resolveEffectiveAssetPrefix({
10931
- dev: config.dev,
10932
- output: config.output,
10955
+ let publicPath, webConfig = config.environments?.web, webJsFilename = webConfig?.output?.filename?.js ?? config.output?.filename?.js;
10956
+ 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.`);
10957
+ let vmodPlugin = (publicPath = resolveEffectiveAssetPrefix({
10958
+ dev: webConfig?.dev,
10959
+ output: webConfig?.output,
10933
10960
  isBuild
10934
- }), vmodPlugin = (publicPath = assetPrefix, jsDistPath = jsDistPath1, new rspack.experiments.VirtualModulesPlugin(Object.fromEntries(Object.entries(modePlan.createVirtualModules(publicPath, jsDistPath)).map(([moduleId, contents])=>[
10961
+ }, {
10962
+ dev: config.dev,
10963
+ output: config.output
10964
+ }), new rspack.experiments.VirtualModulesPlugin(Object.fromEntries(Object.entries(modePlan.createVirtualModules(publicPath)).map(([moduleId, contents])=>[
10935
10965
  getVirtualModuleFilePath(moduleId),
10936
10966
  contents
10937
- ])))), useAsyncNodeChunkLoading = options.federation && 'commonjs' === resolvedServerOutput, nodeChunkLoading = 'require';
10938
- 'module' === resolvedServerOutput ? nodeChunkLoading = 'import' : useAsyncNodeChunkLoading && (nodeChunkLoading = 'async-node');
10939
- let guardedLazyCompilation = (({ lazyCompilation, entryClientPath, prewarmReactRouterModules = !1 })=>{
10967
+ ])))), guardedLazyCompilation = (({ lazyCompilation, entryClientPath, prewarmReactRouterModules = !1 })=>{
10940
10968
  if (void 0 === lazyCompilation || !1 === lazyCompilation) return lazyCompilation;
10941
10969
  let options = !0 === lazyCompilation ? {
10942
10970
  entries: !0,
@@ -11028,9 +11056,6 @@ if (typeof window !== 'undefined' && import.meta.webpackHot) {
11028
11056
  }
11029
11057
  },
11030
11058
  output: {
11031
- filename: {
11032
- js: '[name].js'
11033
- },
11034
11059
  distPath: {
11035
11060
  root: outputClientPath
11036
11061
  }
@@ -11049,13 +11074,6 @@ if (typeof window !== 'undefined' && import.meta.webpackHot) {
11049
11074
  ]
11050
11075
  },
11051
11076
  externalsType: modePlan.webExternalsType,
11052
- output: {
11053
- ...modePlan.webOutput,
11054
- publicPath: assetPrefix,
11055
- ...options.federation ? {
11056
- chunkLoading: 'import'
11057
- } : {}
11058
- },
11059
11077
  optimization: modePlan.webOptimization
11060
11078
  }
11061
11079
  }
@@ -11093,24 +11111,33 @@ if (typeof window !== 'undefined' && import.meta.webpackHot) {
11093
11111
  },
11094
11112
  externals: modePlan.nodeExternals,
11095
11113
  ...modePlan.nodeDependencies,
11096
- externalsType: resolvedServerOutput,
11097
- output: {
11098
- chunkFormat: resolvedServerOutput,
11099
- chunkLoading: nodeChunkLoading,
11100
- devtoolModuleFilenameTemplate: '[absolute-resource-path]',
11101
- devtoolFallbackModuleFilenameTemplate: '[absolute-resource-path]?[hash]',
11102
- workerChunkLoading: nodeChunkLoading,
11103
- wasmLoading: 'fetch',
11104
- module: 'module' === resolvedServerOutput,
11105
- chunkFilename: 'static/js/async/[name].js'
11106
- }
11114
+ externalsType: resolvedServerOutput
11107
11115
  }
11108
11116
  }
11109
11117
  }
11110
11118
  }
11111
11119
  });
11112
- }), (({ api, federation, resolvedServerOutput })=>{
11113
- api.modifyEnvironmentConfig(async (config, { name, mergeEnvironmentConfig })=>'web' !== name && 'node' !== name ? config : mergeEnvironmentConfig(config, {
11120
+ }), (({ api, federation, resolvedServerOutput, webOutput })=>{
11121
+ let nodeChunkLoading = 'module' === resolvedServerOutput ? 'import' : federation ? 'async-node' : 'require';
11122
+ api.modifyRspackConfig((rspackConfig, { environment, mergeConfig })=>'web' === environment.name ? mergeConfig(rspackConfig, {
11123
+ output: {
11124
+ ...webOutput,
11125
+ ...federation ? {
11126
+ chunkLoading: 'import'
11127
+ } : {}
11128
+ }
11129
+ }) : 'node' === environment.name ? mergeConfig(rspackConfig, {
11130
+ output: {
11131
+ chunkFormat: resolvedServerOutput,
11132
+ chunkLoading: nodeChunkLoading,
11133
+ devtoolModuleFilenameTemplate: '[absolute-resource-path]',
11134
+ devtoolFallbackModuleFilenameTemplate: '[absolute-resource-path]?[hash]',
11135
+ workerChunkLoading: nodeChunkLoading,
11136
+ wasmLoading: 'fetch',
11137
+ module: 'module' === resolvedServerOutput,
11138
+ chunkFilename: 'static/js/async/[name].js'
11139
+ }
11140
+ }) : rspackConfig), api.modifyEnvironmentConfig(async (config, { name, mergeEnvironmentConfig })=>'web' !== name && 'node' !== name ? config : mergeEnvironmentConfig(config, {
11114
11141
  tools: {
11115
11142
  rspack: (rspackConfig)=>{
11116
11143
  if (federation && ((rspackConfig)=>{
@@ -11142,7 +11169,8 @@ if (typeof window !== 'undefined' && import.meta.webpackHot) {
11142
11169
  })({
11143
11170
  api,
11144
11171
  federation: pluginOptions.federation,
11145
- resolvedServerOutput
11172
+ resolvedServerOutput,
11173
+ webOutput: modePlan.webOutput
11146
11174
  }), 'classic' === modePlan.kind && useRouteModuleTransformLoader && api.modifyEnvironmentConfig(async (config, { name, mergeEnvironmentConfig })=>'web' !== name && 'node' !== name ? config : mergeEnvironmentConfig(config, {
11147
11175
  tools: {
11148
11176
  rspack: (rspackConfig)=>{
@@ -11279,7 +11307,7 @@ if (typeof window !== 'undefined' && import.meta.webpackHot) {
11279
11307
  compilation.updateAsset(BROWSER_MANIFEST_ASSET, new sources.RawSource(newSource));
11280
11308
  }
11281
11309
  if (isBuild) {
11282
- let entryAssets = stats?.assetsByChunkName?.['entry.client'], entryJsAssets = entryAssets?.filter((asset)=>asset.endsWith('.js')) || [], manifestPath = getReactRouterManifestPath({
11310
+ let entryAssets = stats?.assetsByChunkName?.['entry.client'], entryJsAssets = entryAssets?.filter(isManifestJsAsset) || [], manifestPath = getReactRouterManifestPath({
11283
11311
  version: manifest.version,
11284
11312
  isBuild: !0,
11285
11313
  entryModulePath: entryJsAssets[0]
@@ -11291,7 +11319,7 @@ if (typeof window !== 'undefined' && import.meta.webpackHot) {
11291
11319
  let sri = withSri ? ((stats, compilation, assetPrefix = '/')=>{
11292
11320
  let sri = {};
11293
11321
  for (let asset of stats?.assets ?? [])addIntegrity(sri, assetPrefix, asset.name, asset.integrity);
11294
- 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);
11322
+ 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);
11295
11323
  return Object.keys(sri).length > 0 ? sri : void 0;
11296
11324
  })(compilation.getStats().toJson({
11297
11325
  all: !1,
@@ -64,6 +64,8 @@ type ReactRouterManifestStatsCompilation = {
64
64
  namedChunks: ReactRouterManifestStatsLookup<ReactRouterManifestStatsChunk>;
65
65
  entrypoints?: ReactRouterManifestStatsLookup<ReactRouterManifestStatsEntrypoint>;
66
66
  };
67
+ export declare const isManifestJsAsset: (asset: string) => boolean;
68
+ export declare const isManifestCssAsset: (asset: string) => boolean;
67
69
  export declare const createReactRouterManifestStats: (compilation: ReactRouterManifestStatsCompilation | undefined, chunkNames?: ReadonlySet<string>) => ReactRouterManifestStats | undefined;
68
70
  export type RouteManifestModuleExports = Record<string, readonly string[]>;
69
71
  export type ReactRouterManifestGenerationResult = {
@@ -10,7 +10,7 @@ type CommonModePlan = {
10
10
  manifestChunkNames: Set<string>;
11
11
  webEntries: Record<string, string | RsbuildEntryDescription>;
12
12
  nodeEntries: Record<string, string | RsbuildEntryDescription>;
13
- createVirtualModules(publicPath: string, jsDistPath: string): Record<string, string>;
13
+ createVirtualModules(publicPath: string): Record<string, string>;
14
14
  createResolveConfig(rootPath: string): Rspack.Configuration['resolve'];
15
15
  server: RsbuildConfig['server'] | undefined;
16
16
  webExternalsType: 'module' | undefined;
@@ -69,6 +69,7 @@ type CreateRscModePlanOptions = ModePlanContext & {
69
69
  buildDirectory: string;
70
70
  finalEntryRscClientPath: string;
71
71
  finalEntryRscPath: string;
72
+ finalEntryRscSsrPath: string;
72
73
  outputClientPath: string;
73
74
  pluginName: string;
74
75
  serverBuildFile: string | undefined;
@@ -7,26 +7,32 @@ export declare const getPackageVersion: (packageName: string, resolvePackagePath
7
7
  export declare const escapeHtml: (value: string) => string;
8
8
  export declare function combineURLs(baseURL: string, relativeURL: string): string;
9
9
  export declare function normalizeAssetPrefix(assetPrefix?: string): string;
10
- /**
11
- * Resolve the asset prefix Rsbuild applies to emitted asset URLs for the given
12
- * mode. In development the effective prefix is `dev.assetPrefix` (which Rsbuild
13
- * defaults from `server.base`, falling back to `output.assetPrefix`); in a
14
- * production build it is `output.assetPrefix`. Both fields are already resolved
15
- * on the normalized config, so this mirrors Rsbuild's own precedence rather than
16
- * re-deriving it from `server.base`.
17
- *
18
- * `dev.assetPrefix` may be a boolean on the raw config (`false` disables it);
19
- * boolean/`'auto'`/empty values normalize to the root prefix `'/'`.
20
- */
21
- export declare function resolveEffectiveAssetPrefix(config: {
10
+ type AssetPrefixConfig = {
22
11
  dev?: {
23
12
  assetPrefix?: unknown;
24
13
  };
25
14
  output?: {
26
15
  assetPrefix?: unknown;
27
16
  };
17
+ };
18
+ /**
19
+ * Resolve the absolute asset prefix the server build and browser manifest use
20
+ * for asset URLs. In development the effective prefix is `dev.assetPrefix`
21
+ * (which Rsbuild defaults from `server.base`, falling back to
22
+ * `output.assetPrefix`); in a production build it is `output.assetPrefix`.
23
+ *
24
+ * `fallbacks` are consulted in order (e.g. the root config after the web
25
+ * environment) when the preceding config only offers a prefix the server
26
+ * cannot use: `'auto'` and empty values are browser-runtime-only, so a root
27
+ * CDN prefix must survive a web `'auto'`. The choice happens before
28
+ * normalization so that `'auto'` is not first folded into `'/'`.
29
+ *
30
+ * `dev.assetPrefix` may be a boolean on the raw config (`false` disables it);
31
+ * boolean/`'auto'`/empty values ultimately normalize to the root prefix `'/'`.
32
+ */
33
+ export declare function resolveEffectiveAssetPrefix(config: AssetPrefixConfig & {
28
34
  isBuild: boolean;
29
- }): string;
35
+ }, ...fallbacks: AssetPrefixConfig[]): string;
30
36
  export declare function createRouteId(file: string): string;
31
37
  export declare function findEntryFile(basePath: string): string;
32
38
  export declare function generateWithProps(): string;
@@ -6,14 +6,14 @@ type RscVirtualModulesOptions = {
6
6
  basename: string;
7
7
  buildDirectory: string;
8
8
  isBuild: boolean;
9
- /** Resolved web `output.distPath.js` segment, e.g. `static/js`. */
10
- jsDistPath: string;
11
9
  outputClientPath: string;
12
10
  publicPath: string;
13
11
  routeDiscovery: Config['routeDiscovery'];
14
12
  routes: Record<string, Route>;
15
13
  ssr: boolean;
16
14
  };
17
- export declare const createReactRouterRscResolveAliases: (rootPath: string) => Record<string, string>;
18
- export declare const createReactRouterRscVirtualModules: ({ allowedActionOrigins, appDirectory, basename, buildDirectory, isBuild, jsDistPath, outputClientPath, publicPath, routeDiscovery, routes, ssr, }: RscVirtualModulesOptions) => Record<string, string>;
15
+ export declare const createReactRouterRscResolveAliases: (rootPath: string, options?: {
16
+ entrySsrPath?: string;
17
+ }) => Record<string, string>;
18
+ export declare const createReactRouterRscVirtualModules: ({ allowedActionOrigins, appDirectory, basename, buildDirectory, isBuild, outputClientPath, publicPath, routeDiscovery, routes, ssr, }: RscVirtualModulesOptions) => Record<string, string>;
19
19
  export {};
@@ -5,9 +5,9 @@ import route_discovery from "virtual/react-router/unstable_rsc/route-discovery";
5
5
  import basename from "virtual/react-router/unstable_rsc/basename";
6
6
  import allowed_action_origins from "virtual/react-router/unstable_rsc/allowed-action-origins";
7
7
  import client_version from "virtual/react-router/unstable_rsc/client-version";
8
- import server_manifest from "virtual/react-router/unstable_rsc/server-manifest";
8
+ import { generateHTML } from "virtual/react-router/unstable_rsc/entry-ssr";
9
9
  import bootstrap_scripts from "virtual/react-router/unstable_rsc/bootstrap-scripts";
10
- import { generateHTML } from "./entry.rsc.ssr.js";
10
+ import server_manifest from "virtual/react-router/unstable_rsc/server-manifest";
11
11
  function fetchServer(request, requestContext) {
12
12
  return unstable_matchRSCServerRequest({
13
13
  allowedActionOrigins: allowed_action_origins,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rsbuild-plugin-react-router",
3
- "version": "0.6.5",
3
+ "version": "0.7.0",
4
4
  "description": "React Router plugin for Rsbuild",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,15 +1,64 @@
1
- import type { RsbuildPluginAPI } from '@rsbuild/core';
1
+ import type { RsbuildPluginAPI, Rspack } from '@rsbuild/core';
2
2
  import { ensureFederationAsyncStartup } from './federation.js';
3
3
 
4
+ /**
5
+ * Rspack `output` policy for the web and node environments, in two tiers:
6
+ *
7
+ * 1. Overridable defaults, registered through `modifyRspackConfig`. Rsbuild
8
+ * runs the user's `tools.rspack` (object or function form) after this hook,
9
+ * so user output settings such as `chunkFilename` take precedence
10
+ * (#129, #130). Neither `filename` nor `publicPath` is set here: Rsbuild
11
+ * derives them from `output.filename`/`output.filenameHash`/`output.distPath`
12
+ * and the environment's `output.assetPrefix`, which keeps `'auto'` intact.
13
+ * 2. Enforced invariants, registered through a `tools.rspack` function that
14
+ * runs after the user's own `tools.rspack`: the server library type must
15
+ * match the server module format, and federation builds need async startup.
16
+ */
4
17
  export const registerReactRouterEnvironmentOutput = ({
5
18
  api,
6
19
  federation,
7
20
  resolvedServerOutput,
21
+ webOutput,
8
22
  }: {
9
23
  api: RsbuildPluginAPI;
10
24
  federation: boolean | undefined;
11
25
  resolvedServerOutput: 'commonjs' | 'module';
26
+ webOutput: NonNullable<Rspack.Configuration['output']>;
12
27
  }): void => {
28
+ const nodeChunkLoading =
29
+ resolvedServerOutput === 'module'
30
+ ? 'import'
31
+ : federation
32
+ ? 'async-node'
33
+ : 'require';
34
+
35
+ api.modifyRspackConfig((rspackConfig, { environment, mergeConfig }) => {
36
+ if (environment.name === 'web') {
37
+ return mergeConfig(rspackConfig, {
38
+ output: {
39
+ ...webOutput,
40
+ ...(federation ? { chunkLoading: 'import' } : {}),
41
+ },
42
+ });
43
+ }
44
+ if (environment.name === 'node') {
45
+ return mergeConfig(rspackConfig, {
46
+ output: {
47
+ chunkFormat: resolvedServerOutput,
48
+ chunkLoading: nodeChunkLoading,
49
+ devtoolModuleFilenameTemplate: '[absolute-resource-path]',
50
+ devtoolFallbackModuleFilenameTemplate:
51
+ '[absolute-resource-path]?[hash]',
52
+ workerChunkLoading: nodeChunkLoading,
53
+ wasmLoading: 'fetch',
54
+ module: resolvedServerOutput === 'module',
55
+ chunkFilename: 'static/js/async/[name].js',
56
+ },
57
+ });
58
+ }
59
+ return rspackConfig;
60
+ });
61
+
13
62
  api.modifyEnvironmentConfig(
14
63
  async (config, { name, mergeEnvironmentConfig }) => {
15
64
  if (name !== 'web' && name !== 'node') {