rsbuild-plugin-react-router 0.6.6 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -2
- package/dist/511.js +10 -3
- package/dist/environment-output.d.ts +16 -2
- package/dist/federation.d.ts +26 -0
- package/dist/index.cjs +160 -76
- package/dist/index.js +149 -70
- package/dist/manifest.d.ts +31 -0
- package/dist/mode-plan.d.ts +1 -1
- package/dist/plugin-utils.d.ts +19 -13
- package/dist/rsc-virtual-modules.d.ts +1 -3
- package/package.json +1 -1
- package/src/environment-output.ts +60 -2
- package/src/federation.ts +93 -14
- package/src/index.ts +75 -62
- package/src/manifest.ts +96 -17
- package/src/mode-plan.ts +6 -12
- package/src/modify-browser-manifest.ts +4 -4
- package/src/plugin-utils.ts +37 -23
- package/src/rsc-route-transforms.ts +8 -12
- package/src/rsc-virtual-modules.ts +59 -8
package/dist/index.js
CHANGED
|
@@ -38,6 +38,8 @@ let getAvailableCpuCount = ()=>'function' == typeof availableParallelism ? avail
|
|
|
38
38
|
}, resolveEntryWithTemplate = ({ appDirectory, entryName, templateName, templatesDirectory })=>{
|
|
39
39
|
let userEntryPath = findEntryFile(external_pathe_resolve(appDirectory, entryName));
|
|
40
40
|
return existsSync(userEntryPath) ? userEntryPath : external_pathe_resolve(templatesDirectory, templateName);
|
|
41
|
+
}, getModuleFederationOptions = (plugin)=>{
|
|
42
|
+
if (plugin && 'object' == typeof plugin && ('ModuleFederationPlugin' === plugin.name || 'RspackModuleFederationPlugin' === plugin.name)) return plugin._options ?? plugin.options;
|
|
41
43
|
}, Function_dual = function(arity, body) {
|
|
42
44
|
if ("function" == typeof arity) return function() {
|
|
43
45
|
return arity(arguments) ? body.apply(this, arguments) : (self)=>body(self, ...arguments);
|
|
@@ -7356,6 +7358,9 @@ let createReactRouterManifestOptions = ({ routeChunks, routeModuleAnalysis })=>{
|
|
|
7356
7358
|
routeModuleAnalysis
|
|
7357
7359
|
} : {}
|
|
7358
7360
|
};
|
|
7361
|
+
}, isManifestJsAsset = (asset)=>/(?<!\.hot-update)\.[cm]?js(?:\?.*)?$/.test(asset), isManifestCssAsset = (asset)=>/\.css(?:\?.*)?$/.test(asset), hasSome = (iterable)=>{
|
|
7362
|
+
for (let _ of iterable)return !0;
|
|
7363
|
+
return !1;
|
|
7359
7364
|
}, collectManifestFilesByName = (items, names, getFiles)=>{
|
|
7360
7365
|
let filesByName = {};
|
|
7361
7366
|
if (!names) {
|
|
@@ -7372,15 +7377,7 @@ let createReactRouterManifestOptions = ({ routeChunks, routeModuleAnalysis })=>{
|
|
|
7372
7377
|
return filesByName;
|
|
7373
7378
|
}, createReactRouterManifestStats = (compilation, chunkNames)=>{
|
|
7374
7379
|
if (!compilation) return;
|
|
7375
|
-
let assetsByChunkName = collectManifestFilesByName(compilation.namedChunks, chunkNames, (
|
|
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?.() ?? [])) : {};
|
|
7380
|
+
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
7381
|
return Object.keys(entrypointFilesByName).length > 0 ? {
|
|
7385
7382
|
assetsByChunkName,
|
|
7386
7383
|
entrypointFilesByName
|
|
@@ -7416,9 +7413,9 @@ async function generateReactRouterManifestForDev(routes, _options, clientStats,
|
|
|
7416
7413
|
return chunkAssetsByName.set(chunkName, result), result;
|
|
7417
7414
|
}
|
|
7418
7415
|
let cssAssets = new Set(), jsAssets = new Set();
|
|
7419
|
-
for (let asset of assets)asset
|
|
7420
|
-
for (let asset of clientStats?.entrypointFilesByName?.[chunkName] ?? [])asset
|
|
7421
|
-
0 === jsAssets.size
|
|
7416
|
+
for (let asset of assets)isManifestCssAsset(asset) ? cssAssets.add(asset) : isManifestJsAsset(asset) && jsAssets.add(asset);
|
|
7417
|
+
for (let asset of clientStats?.entrypointFilesByName?.[chunkName] ?? [])isManifestCssAsset(asset) ? cssAssets.add(asset) : isBuild && isManifestJsAsset(asset) && jsAssets.add(asset);
|
|
7418
|
+
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
7419
|
let result = {
|
|
7423
7420
|
js: [
|
|
7424
7421
|
...jsAssets
|
|
@@ -7906,7 +7903,7 @@ let redirectStatusCodes = new Set([
|
|
|
7906
7903
|
}
|
|
7907
7904
|
};
|
|
7908
7905
|
}, 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
|
|
7906
|
+
'string' == typeof assetName && isManifestJsAsset(assetName) && 'string' == typeof integrity && (sri[ABSOLUTE_URL_RE.test(assetName) || assetName.startsWith('//') || assetName.startsWith('/') ? assetName : combineURLs(assetPrefix, assetName)] = integrity);
|
|
7910
7907
|
}, computeSubresourceIntegrity = (source)=>{
|
|
7911
7908
|
if (source) return `sha384-${createHash('sha384').update(source.source()).digest('base64')}`;
|
|
7912
7909
|
};
|
|
@@ -8596,12 +8593,14 @@ export function EnsureClientRouteModuleForHMR___() { return ___EnsureClientRoute
|
|
|
8596
8593
|
}, createServerRouteEntry = async (options)=>{
|
|
8597
8594
|
let plan = await createRscRouteExportPlan(options);
|
|
8598
8595
|
validateRscRouteExportPlan(plan, options);
|
|
8599
|
-
let lines = [], needsReactImport = !1, needsEnsureHmrImport = !1, needsStyleEntryImport = !1,
|
|
8596
|
+
let lines = [], needsReactImport = !1, needsEnsureHmrImport = !1, needsStyleEntryImport = !1, pushStylesheetLinks = (entryCssFilesExpression)=>{
|
|
8597
|
+
lines.push(` ...(${entryCssFilesExpression} ?? []).map(href =>`), lines.push(' React.createElement("link", { key: href, rel: "stylesheet", href: href, precedence: "default" })),');
|
|
8598
|
+
}, streamsClientRouteCss = !plan.exportNames.some(isServerComponentExport) && plan.exportNames.includes('default') && programHasSideEffectStyleImports(getProgram(yuku_parse(options.code, {
|
|
8600
8599
|
sourceType: 'module'
|
|
8601
8600
|
})));
|
|
8602
8601
|
for (let exportName of plan.exportNames){
|
|
8603
8602
|
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,'),
|
|
8603
|
+
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
8604
|
continue;
|
|
8606
8605
|
}
|
|
8607
8606
|
if (isClientRouteExport(exportName)) {
|
|
@@ -8609,7 +8608,7 @@ export function EnsureClientRouteModuleForHMR___() { return ___EnsureClientRoute
|
|
|
8609
8608
|
continue;
|
|
8610
8609
|
}
|
|
8611
8610
|
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,'),
|
|
8611
|
+
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
8612
|
continue;
|
|
8614
8613
|
}
|
|
8615
8614
|
lines.push(createReexport(exportName, plan.serverTarget));
|
|
@@ -8803,6 +8802,7 @@ export function EnsureClientRouteModuleForHMR___() { return ___EnsureClientRoute
|
|
|
8803
8802
|
'allowed-action-origins',
|
|
8804
8803
|
'client-version',
|
|
8805
8804
|
'react-router-serve-config',
|
|
8805
|
+
'manifest-prefix',
|
|
8806
8806
|
"bootstrap-scripts",
|
|
8807
8807
|
'server-manifest'
|
|
8808
8808
|
], setupReactRouterRscPlugin = async ({ api, entryRscPath, entrySsrPath, pluginName, rsc })=>{
|
|
@@ -9528,8 +9528,8 @@ export function EnsureClientRouteModuleForHMR___() { return ___EnsureClientRoute
|
|
|
9528
9528
|
layer: RSC_LAYERS.rsc
|
|
9529
9529
|
}
|
|
9530
9530
|
},
|
|
9531
|
-
createVirtualModules: (publicPath
|
|
9532
|
-
let rscAssetsBuildDirectory = relative(external_pathe_resolve(buildDirectory, 'server'), outputClientPath),
|
|
9531
|
+
createVirtualModules: (publicPath)=>(({ allowedActionOrigins, appDirectory, basename, buildDirectory, isBuild, outputClientPath, publicPath, routeDiscovery, routes, ssr })=>{
|
|
9532
|
+
let rscAssetsBuildDirectory = relative(external_pathe_resolve(buildDirectory, 'server'), outputClientPath), serverPublicPath = normalizeAssetPrefix(publicPath);
|
|
9533
9533
|
return {
|
|
9534
9534
|
'virtual/react-router/unstable_rsc/routes': (({ appDirectory, routes })=>{
|
|
9535
9535
|
let componentResolutionCode = RSC_ROUTE_COMPONENT_EXPORTS.map(({ routeProperty, clientExport, serverExport })=>{
|
|
@@ -9625,9 +9625,41 @@ export default [`;
|
|
|
9625
9625
|
assetsBuildDirectory: rscAssetsBuildDirectory,
|
|
9626
9626
|
publicPath
|
|
9627
9627
|
}),
|
|
9628
|
-
|
|
9629
|
-
|
|
9630
|
-
|
|
9628
|
+
'virtual/react-router/unstable_rsc/manifest-prefix': `const manifest = __webpack_require__.rscM;
|
|
9629
|
+
const serverPrefix = ${JSON.stringify(serverPublicPath)};
|
|
9630
|
+
const appliedPrefix = manifest?.moduleLoading?.prefix;
|
|
9631
|
+
// An empty applied prefix (web \`assetPrefix: ''\`) yields relative references
|
|
9632
|
+
// such as "static/js/index.js"; those are rebased too, while absolute and
|
|
9633
|
+
// protocol-relative URLs are left alone.
|
|
9634
|
+
const isAbsoluteUrl = url => /^(?:[a-z][a-z\\d+.-]*:|\\/\\/|\\/)/i.test(url);
|
|
9635
|
+
if (typeof appliedPrefix === "string" && appliedPrefix !== serverPrefix) {
|
|
9636
|
+
const rewrite = url =>
|
|
9637
|
+
typeof url !== "string"
|
|
9638
|
+
? url
|
|
9639
|
+
: appliedPrefix !== "" && url.startsWith(appliedPrefix)
|
|
9640
|
+
? serverPrefix + url.slice(appliedPrefix.length)
|
|
9641
|
+
: appliedPrefix === "" && !isAbsoluteUrl(url)
|
|
9642
|
+
? serverPrefix + url
|
|
9643
|
+
: url;
|
|
9644
|
+
const rewriteAll = list => {
|
|
9645
|
+
if (Array.isArray(list)) for (let i = 0; i < list.length; i++) list[i] = rewrite(list[i]);
|
|
9646
|
+
};
|
|
9647
|
+
manifest.moduleLoading.prefix = serverPrefix;
|
|
9648
|
+
rewriteAll(manifest.entryJsFiles);
|
|
9649
|
+
for (const files of Object.values(manifest.entryCssFiles ?? {})) rewriteAll(files);
|
|
9650
|
+
for (const reference of Object.values(manifest.clientManifest ?? {})) rewriteAll(reference.cssFiles);
|
|
9651
|
+
}
|
|
9652
|
+
export const rscManifest = manifest;
|
|
9653
|
+
`,
|
|
9654
|
+
"virtual/react-router/unstable_rsc/bootstrap-scripts": `import { rscManifest } from "virtual/react-router/unstable_rsc/manifest-prefix";
|
|
9655
|
+
const entryJsFiles = rscManifest?.entryJsFiles;
|
|
9656
|
+
if (!entryJsFiles?.length) {
|
|
9657
|
+
throw new Error(
|
|
9658
|
+
"[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."
|
|
9659
|
+
);
|
|
9660
|
+
}
|
|
9661
|
+
export default entryJsFiles;
|
|
9662
|
+
`,
|
|
9631
9663
|
'virtual/react-router/unstable_rsc/server-manifest': `export default function getServerManifest() {
|
|
9632
9664
|
return __webpack_require__.rscM?.serverManifest;
|
|
9633
9665
|
}
|
|
@@ -9667,7 +9699,6 @@ export {
|
|
|
9667
9699
|
basename,
|
|
9668
9700
|
buildDirectory,
|
|
9669
9701
|
isBuild,
|
|
9670
|
-
jsDistPath,
|
|
9671
9702
|
outputClientPath,
|
|
9672
9703
|
publicPath,
|
|
9673
9704
|
routeDiscovery,
|
|
@@ -9849,7 +9880,7 @@ export {
|
|
|
9849
9880
|
defaultEntryName,
|
|
9850
9881
|
serverBundleEntries: artifacts.serverBundleEntries
|
|
9851
9882
|
}),
|
|
9852
|
-
createVirtualModules: (publicPath
|
|
9883
|
+
createVirtualModules: (publicPath)=>(({ allowedActionOrigins, appDirectory, assetsBuildDirectory, basename, devHmrRuntimeModule, entryServerPath, future, isSpaMode, prerenderPaths, publicPath, routeDiscovery, routes, routesByServerBundleId, ssr })=>{
|
|
9853
9884
|
let serverBuildOptions = {
|
|
9854
9885
|
entryServerPath,
|
|
9855
9886
|
assetsBuildDirectory,
|
|
@@ -9938,10 +9969,7 @@ export {
|
|
|
9938
9969
|
library: {
|
|
9939
9970
|
type: 'module'
|
|
9940
9971
|
},
|
|
9941
|
-
module: !0
|
|
9942
|
-
...isBuild ? {
|
|
9943
|
-
chunkFilename: 'static/js/async/[id]-[contenthash:16].js'
|
|
9944
|
-
} : {}
|
|
9972
|
+
module: !0
|
|
9945
9973
|
},
|
|
9946
9974
|
webOptimization: {
|
|
9947
9975
|
avoidEntryIife: !0,
|
|
@@ -10105,11 +10133,14 @@ export {
|
|
|
10105
10133
|
(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");
|
|
10106
10134
|
}(api.getNormalizedConfig(), (msg)=>api.logger.warn(msg), 'web');
|
|
10107
10135
|
}), api.onBeforeCreateCompiler(()=>{
|
|
10108
|
-
let
|
|
10136
|
+
let root = api.getNormalizedConfig(), web = root.environments.web;
|
|
10109
10137
|
assetPrefix = resolveEffectiveAssetPrefix({
|
|
10110
|
-
dev:
|
|
10111
|
-
output:
|
|
10138
|
+
dev: web?.dev,
|
|
10139
|
+
output: web?.output,
|
|
10112
10140
|
isBuild: 'build' === api.context.action
|
|
10141
|
+
}, {
|
|
10142
|
+
dev: root.dev,
|
|
10143
|
+
output: root.output
|
|
10113
10144
|
});
|
|
10114
10145
|
});
|
|
10115
10146
|
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 = {};
|
|
@@ -10889,8 +10920,27 @@ if (typeof window !== 'undefined' && import.meta.webpackHot) {
|
|
|
10889
10920
|
initialRouteTopology: routeTopology.initialRouteTopology,
|
|
10890
10921
|
onRouteTopologyChange: pluginOptions.onRouteTopologyChange
|
|
10891
10922
|
});
|
|
10892
|
-
api.onAfterEnvironmentCompile(({ stats, environment })=>{
|
|
10893
|
-
if ('web' === environment.name && (clientStats = createReactRouterManifestStats(stats?.compilation, manifestChunkNames)
|
|
10923
|
+
if (api.onAfterEnvironmentCompile(({ stats, environment })=>{
|
|
10924
|
+
if ('web' === environment.name && (clientStats = createReactRouterManifestStats(stats?.compilation, manifestChunkNames), isRscMode && stats)) {
|
|
10925
|
+
let unsupported = ((compilation)=>{
|
|
10926
|
+
let unsupported = new Set();
|
|
10927
|
+
for (let chunk of compilation.chunks){
|
|
10928
|
+
if (!(chunk.contentHash?.javascript !== void 0 || hasSome(compilation.chunkGraph.getChunkModulesIterableBySourceType(chunk, "javascript")))) continue;
|
|
10929
|
+
let pathData = {
|
|
10930
|
+
chunk,
|
|
10931
|
+
contentHashType: "javascript"
|
|
10932
|
+
}, template = chunk.canBeInitial() ? compilation.outputOptions.filename : compilation.outputOptions.chunkFilename, resolvedTemplate = 'function' == typeof template ? template(pathData) : template;
|
|
10933
|
+
if ('string' != typeof resolvedTemplate) continue;
|
|
10934
|
+
let file = compilation.getPath(resolvedTemplate, pathData);
|
|
10935
|
+
file.endsWith('.js') || unsupported.add(file);
|
|
10936
|
+
}
|
|
10937
|
+
return [
|
|
10938
|
+
...unsupported
|
|
10939
|
+
];
|
|
10940
|
+
})(stats.compilation);
|
|
10941
|
+
if (unsupported.length > 0) throw Error(`[${PLUGIN_NAME}] RSC mode requires every browser JavaScript asset to be named "*.js" (no query, no other extension): rspack's RSC manifest omits ${unsupported.slice(0, 5).map((asset)=>JSON.stringify(asset)).join(', ')}${unsupported.length > 5 ? ` and ${unsupported.length - 5} more` : ''}. Adjust web \`output.filename.js\` / \`chunkFilename\`.`);
|
|
10942
|
+
}
|
|
10943
|
+
if (pluginOptions.federation && ssr) {
|
|
10894
10944
|
let serverBuildDir = external_pathe_resolve(buildDirectory, 'server'), clientBuildDir = external_pathe_resolve(buildDirectory, 'client');
|
|
10895
10945
|
if (existsSync(serverBuildDir)) {
|
|
10896
10946
|
let ssrDir = external_pathe_resolve(clientBuildDir, 'static');
|
|
@@ -10934,16 +10984,17 @@ if (typeof window !== 'undefined' && import.meta.webpackHot) {
|
|
|
10934
10984
|
basename
|
|
10935
10985
|
})))), api.modifyRsbuildConfig(async (config, { mergeRsbuildConfig })=>{
|
|
10936
10986
|
var existing;
|
|
10937
|
-
let publicPath,
|
|
10938
|
-
dev:
|
|
10939
|
-
output:
|
|
10987
|
+
let publicPath, webConfig = config.environments?.web, vmodPlugin = (publicPath = resolveEffectiveAssetPrefix({
|
|
10988
|
+
dev: webConfig?.dev,
|
|
10989
|
+
output: webConfig?.output,
|
|
10940
10990
|
isBuild
|
|
10941
|
-
}
|
|
10991
|
+
}, {
|
|
10992
|
+
dev: config.dev,
|
|
10993
|
+
output: config.output
|
|
10994
|
+
}), new rspack.experiments.VirtualModulesPlugin(Object.fromEntries(Object.entries(modePlan.createVirtualModules(publicPath)).map(([moduleId, contents])=>[
|
|
10942
10995
|
getVirtualModuleFilePath(moduleId),
|
|
10943
10996
|
contents
|
|
10944
|
-
])))),
|
|
10945
|
-
'module' === resolvedServerOutput ? nodeChunkLoading = 'import' : useAsyncNodeChunkLoading && (nodeChunkLoading = 'async-node');
|
|
10946
|
-
let guardedLazyCompilation = (({ lazyCompilation, entryClientPath, prewarmReactRouterModules = !1 })=>{
|
|
10997
|
+
])))), guardedLazyCompilation = (({ lazyCompilation, entryClientPath, prewarmReactRouterModules = !1 })=>{
|
|
10947
10998
|
if (void 0 === lazyCompilation || !1 === lazyCompilation) return lazyCompilation;
|
|
10948
10999
|
let options = !0 === lazyCompilation ? {
|
|
10949
11000
|
entries: !0,
|
|
@@ -11035,9 +11086,6 @@ if (typeof window !== 'undefined' && import.meta.webpackHot) {
|
|
|
11035
11086
|
}
|
|
11036
11087
|
},
|
|
11037
11088
|
output: {
|
|
11038
|
-
filename: {
|
|
11039
|
-
js: '[name].js'
|
|
11040
|
-
},
|
|
11041
11089
|
distPath: {
|
|
11042
11090
|
root: outputClientPath
|
|
11043
11091
|
}
|
|
@@ -11056,13 +11104,6 @@ if (typeof window !== 'undefined' && import.meta.webpackHot) {
|
|
|
11056
11104
|
]
|
|
11057
11105
|
},
|
|
11058
11106
|
externalsType: modePlan.webExternalsType,
|
|
11059
|
-
output: {
|
|
11060
|
-
...modePlan.webOutput,
|
|
11061
|
-
publicPath: assetPrefix,
|
|
11062
|
-
...options.federation ? {
|
|
11063
|
-
chunkLoading: 'import'
|
|
11064
|
-
} : {}
|
|
11065
|
-
},
|
|
11066
11107
|
optimization: modePlan.webOptimization
|
|
11067
11108
|
}
|
|
11068
11109
|
}
|
|
@@ -11100,36 +11141,60 @@ if (typeof window !== 'undefined' && import.meta.webpackHot) {
|
|
|
11100
11141
|
},
|
|
11101
11142
|
externals: modePlan.nodeExternals,
|
|
11102
11143
|
...modePlan.nodeDependencies,
|
|
11103
|
-
externalsType: resolvedServerOutput
|
|
11104
|
-
output: {
|
|
11105
|
-
chunkFormat: resolvedServerOutput,
|
|
11106
|
-
chunkLoading: nodeChunkLoading,
|
|
11107
|
-
devtoolModuleFilenameTemplate: '[absolute-resource-path]',
|
|
11108
|
-
devtoolFallbackModuleFilenameTemplate: '[absolute-resource-path]?[hash]',
|
|
11109
|
-
workerChunkLoading: nodeChunkLoading,
|
|
11110
|
-
wasmLoading: 'fetch',
|
|
11111
|
-
module: 'module' === resolvedServerOutput,
|
|
11112
|
-
chunkFilename: 'static/js/async/[name].js'
|
|
11113
|
-
}
|
|
11144
|
+
externalsType: resolvedServerOutput
|
|
11114
11145
|
}
|
|
11115
11146
|
}
|
|
11116
11147
|
}
|
|
11117
11148
|
}
|
|
11118
11149
|
});
|
|
11119
|
-
}), (({ api, federation, resolvedServerOutput })=>{
|
|
11120
|
-
|
|
11150
|
+
}), (({ api, federation, resolvedServerOutput, webOutput })=>{
|
|
11151
|
+
let nodeChunkLoading = 'module' === resolvedServerOutput ? 'import' : federation ? 'async-node' : 'require';
|
|
11152
|
+
api.modifyRspackConfig((rspackConfig, { environment, mergeConfig })=>'web' === environment.name ? mergeConfig(rspackConfig, {
|
|
11153
|
+
output: {
|
|
11154
|
+
...webOutput,
|
|
11155
|
+
...federation ? {
|
|
11156
|
+
chunkLoading: 'import'
|
|
11157
|
+
} : {}
|
|
11158
|
+
}
|
|
11159
|
+
}) : 'node' === environment.name ? mergeConfig(rspackConfig, {
|
|
11160
|
+
output: {
|
|
11161
|
+
chunkFormat: resolvedServerOutput,
|
|
11162
|
+
chunkLoading: nodeChunkLoading,
|
|
11163
|
+
devtoolModuleFilenameTemplate: '[absolute-resource-path]',
|
|
11164
|
+
devtoolFallbackModuleFilenameTemplate: '[absolute-resource-path]?[hash]',
|
|
11165
|
+
workerChunkLoading: nodeChunkLoading,
|
|
11166
|
+
wasmLoading: 'fetch',
|
|
11167
|
+
module: 'module' === resolvedServerOutput,
|
|
11168
|
+
chunkFilename: 'static/js/async/[name].js'
|
|
11169
|
+
}
|
|
11170
|
+
}) : rspackConfig), api.modifyEnvironmentConfig(async (config, { name, mergeEnvironmentConfig })=>'web' !== name && 'node' !== name ? config : mergeEnvironmentConfig(config, {
|
|
11121
11171
|
tools: {
|
|
11122
11172
|
rspack: (rspackConfig)=>{
|
|
11123
|
-
if (federation
|
|
11173
|
+
if (federation) {
|
|
11124
11174
|
if (rspackConfig?.plugins?.length) for (let plugin of rspackConfig.plugins){
|
|
11125
|
-
|
|
11126
|
-
let pluginOptions = plugin._options ?? plugin.options;
|
|
11175
|
+
let pluginOptions = getModuleFederationOptions(plugin);
|
|
11127
11176
|
pluginOptions && (pluginOptions.experiments = {
|
|
11128
11177
|
...pluginOptions.experiments,
|
|
11129
11178
|
asyncStartup: !0
|
|
11130
11179
|
});
|
|
11131
11180
|
}
|
|
11132
|
-
|
|
11181
|
+
if ('web' === name) ((rspackConfig)=>{
|
|
11182
|
+
let containers = new Set((rspackConfig?.plugins ?? []).map(getModuleFederationOptions).map((options)=>options?.name).filter((name)=>'string' == typeof name));
|
|
11183
|
+
if (!rspackConfig || 0 === containers.size) return;
|
|
11184
|
+
let current = rspackConfig.optimization?.runtimeChunk, appRuntimeName = 'object' == typeof current && 'string' == typeof current?.name ? current.name : 'runtime';
|
|
11185
|
+
rspackConfig.optimization = {
|
|
11186
|
+
...rspackConfig.optimization,
|
|
11187
|
+
runtimeChunk: {
|
|
11188
|
+
name: (entrypoint)=>containers.has(entrypoint.name) ? `runtime-${entrypoint.name}` : appRuntimeName
|
|
11189
|
+
}
|
|
11190
|
+
};
|
|
11191
|
+
})(rspackConfig);
|
|
11192
|
+
else {
|
|
11193
|
+
let splitChunks = rspackConfig?.optimization?.splitChunks;
|
|
11194
|
+
if (splitChunks) for (let group of (splitChunks.chunks = 'async', Object.values(splitChunks.cacheGroups ?? {})))group && 'object' == typeof group && 'chunks' in group && (group.chunks = 'async');
|
|
11195
|
+
}
|
|
11196
|
+
}
|
|
11197
|
+
if ('node' === name) {
|
|
11133
11198
|
let output = rspackConfig.output;
|
|
11134
11199
|
if (output) {
|
|
11135
11200
|
let library = output.library, libraryOptions = library && 'object' == typeof library && !Array.isArray(library) ? library : {};
|
|
@@ -11149,8 +11214,22 @@ if (typeof window !== 'undefined' && import.meta.webpackHot) {
|
|
|
11149
11214
|
})({
|
|
11150
11215
|
api,
|
|
11151
11216
|
federation: pluginOptions.federation,
|
|
11152
|
-
resolvedServerOutput
|
|
11153
|
-
|
|
11217
|
+
resolvedServerOutput,
|
|
11218
|
+
webOutput: modePlan.webOutput
|
|
11219
|
+
}), pluginOptions.federation && 'classic' === modePlan.kind) {
|
|
11220
|
+
let browserEntryModules = new Set([
|
|
11221
|
+
finalEntryClientPath,
|
|
11222
|
+
...routeByFilePath.keys()
|
|
11223
|
+
]);
|
|
11224
|
+
api.transform({
|
|
11225
|
+
environments: [
|
|
11226
|
+
'web'
|
|
11227
|
+
],
|
|
11228
|
+
order: 'post',
|
|
11229
|
+
test: (resourcePath)=>browserEntryModules.has(resourcePath)
|
|
11230
|
+
}, ({ code })=>`${code}\nexport {};\nawait Promise.resolve();\n`);
|
|
11231
|
+
}
|
|
11232
|
+
'classic' === modePlan.kind && useRouteModuleTransformLoader && api.modifyEnvironmentConfig(async (config, { name, mergeEnvironmentConfig })=>'web' !== name && 'node' !== name ? config : mergeEnvironmentConfig(config, {
|
|
11154
11233
|
tools: {
|
|
11155
11234
|
rspack: (rspackConfig)=>{
|
|
11156
11235
|
let environmentDevHmrEnabled = 'web' === name && !isBuild && void 0 !== devHmrRefreshRuntimePath && 'development' === config.mode && config.dev?.hmr !== !1 && isRspackSwcReactRefreshEnabled(rspackConfig);
|
|
@@ -11286,7 +11365,7 @@ if (typeof window !== 'undefined' && import.meta.webpackHot) {
|
|
|
11286
11365
|
compilation.updateAsset(BROWSER_MANIFEST_ASSET, new sources.RawSource(newSource));
|
|
11287
11366
|
}
|
|
11288
11367
|
if (isBuild) {
|
|
11289
|
-
let entryAssets = stats?.assetsByChunkName?.['entry.client'], entryJsAssets = entryAssets?.filter(
|
|
11368
|
+
let entryAssets = stats?.assetsByChunkName?.['entry.client'], entryJsAssets = entryAssets?.filter(isManifestJsAsset) || [], manifestPath = getReactRouterManifestPath({
|
|
11290
11369
|
version: manifest.version,
|
|
11291
11370
|
isBuild: !0,
|
|
11292
11371
|
entryModulePath: entryJsAssets[0]
|
|
@@ -11298,7 +11377,7 @@ if (typeof window !== 'undefined' && import.meta.webpackHot) {
|
|
|
11298
11377
|
let sri = withSri ? ((stats, compilation, assetPrefix = '/')=>{
|
|
11299
11378
|
let sri = {};
|
|
11300
11379
|
for (let asset of stats?.assets ?? [])addIntegrity(sri, assetPrefix, asset.name, asset.integrity);
|
|
11301
|
-
if ('function' == typeof compilation?.getAssets) for (let asset of compilation.getAssets())asset.name
|
|
11380
|
+
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);
|
|
11302
11381
|
return Object.keys(sri).length > 0 ? sri : void 0;
|
|
11303
11382
|
})(compilation.getStats().toJson({
|
|
11304
11383
|
all: !1,
|
package/dist/manifest.d.ts
CHANGED
|
@@ -64,6 +64,37 @@ 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;
|
|
69
|
+
/**
|
|
70
|
+
* The minimal compilation surface for `collectUnsupportedRscScriptAssets`.
|
|
71
|
+
* Chunks are classified as JavaScript-emitting from compilation metadata (their
|
|
72
|
+
* `javascript` content hash / modules), never from a filename.
|
|
73
|
+
*/
|
|
74
|
+
export type RscScriptAssetCompilation = {
|
|
75
|
+
chunks: Iterable<RscScriptAssetChunk>;
|
|
76
|
+
chunkGraph: {
|
|
77
|
+
getChunkModulesIterableBySourceType(chunk: RscScriptAssetChunk, sourceType: string): Iterable<unknown>;
|
|
78
|
+
};
|
|
79
|
+
outputOptions: {
|
|
80
|
+
filename?: unknown;
|
|
81
|
+
chunkFilename?: unknown;
|
|
82
|
+
};
|
|
83
|
+
getPath(filename: string, data: Record<string, unknown>): string;
|
|
84
|
+
};
|
|
85
|
+
export type RscScriptAssetChunk = {
|
|
86
|
+
contentHash?: Record<string, string>;
|
|
87
|
+
canBeInitial(): boolean;
|
|
88
|
+
};
|
|
89
|
+
/**
|
|
90
|
+
* Browser JavaScript assets rspack's RSC manifest would drop: it only records
|
|
91
|
+
* chunk files whose emitted name ends in ".js", so `.mjs` names, query-hash
|
|
92
|
+
* names (`[name].js?v=...`), or any other extension vanish from
|
|
93
|
+
* `entryJsFiles` and the client manifest. The emitted script name is derived
|
|
94
|
+
* from the chunk's own filename template (entry or async) the same way rspack
|
|
95
|
+
* emits it, so function templates and `tools.rspack` overrides are covered.
|
|
96
|
+
*/
|
|
97
|
+
export declare const collectUnsupportedRscScriptAssets: (compilation: RscScriptAssetCompilation) => string[];
|
|
67
98
|
export declare const createReactRouterManifestStats: (compilation: ReactRouterManifestStatsCompilation | undefined, chunkNames?: ReadonlySet<string>) => ReactRouterManifestStats | undefined;
|
|
68
99
|
export type RouteManifestModuleExports = Record<string, readonly string[]>;
|
|
69
100
|
export type ReactRouterManifestGenerationResult = {
|
package/dist/mode-plan.d.ts
CHANGED
|
@@ -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
|
|
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;
|
package/dist/plugin-utils.d.ts
CHANGED
|
@@ -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,8 +6,6 @@ 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'];
|
|
@@ -17,5 +15,5 @@ type RscVirtualModulesOptions = {
|
|
|
17
15
|
export declare const createReactRouterRscResolveAliases: (rootPath: string, options?: {
|
|
18
16
|
entrySsrPath?: string;
|
|
19
17
|
}) => Record<string, string>;
|
|
20
|
-
export declare const createReactRouterRscVirtualModules: ({ allowedActionOrigins, appDirectory, basename, buildDirectory, isBuild,
|
|
18
|
+
export declare const createReactRouterRscVirtualModules: ({ allowedActionOrigins, appDirectory, basename, buildDirectory, isBuild, outputClientPath, publicPath, routeDiscovery, routes, ssr, }: RscVirtualModulesOptions) => Record<string, string>;
|
|
21
19
|
export {};
|
package/package.json
CHANGED
|
@@ -1,15 +1,68 @@
|
|
|
1
|
-
import type { RsbuildPluginAPI } from '@rsbuild/core';
|
|
2
|
-
import {
|
|
1
|
+
import type { RsbuildPluginAPI, Rspack } from '@rsbuild/core';
|
|
2
|
+
import {
|
|
3
|
+
enforceAsyncOnlyServerSplitChunks,
|
|
4
|
+
ensureFederationAsyncStartup,
|
|
5
|
+
isolateFederationContainerRuntime,
|
|
6
|
+
} from './federation.js';
|
|
3
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Rspack `output` policy for the web and node environments, in two tiers:
|
|
10
|
+
*
|
|
11
|
+
* 1. Overridable defaults, registered through `modifyRspackConfig`. Rsbuild
|
|
12
|
+
* runs the user's `tools.rspack` (object or function form) after this hook,
|
|
13
|
+
* so user output settings such as `chunkFilename` take precedence
|
|
14
|
+
* (#129, #130). Neither `filename` nor `publicPath` is set here: Rsbuild
|
|
15
|
+
* derives them from `output.filename`/`output.filenameHash`/`output.distPath`
|
|
16
|
+
* and the environment's `output.assetPrefix`, which keeps `'auto'` intact.
|
|
17
|
+
* 2. Enforced invariants, registered through a `tools.rspack` function that
|
|
18
|
+
* runs after the user's own `tools.rspack`: the server library type must
|
|
19
|
+
* match the server module format, and federation builds need async startup.
|
|
20
|
+
*/
|
|
4
21
|
export const registerReactRouterEnvironmentOutput = ({
|
|
5
22
|
api,
|
|
6
23
|
federation,
|
|
7
24
|
resolvedServerOutput,
|
|
25
|
+
webOutput,
|
|
8
26
|
}: {
|
|
9
27
|
api: RsbuildPluginAPI;
|
|
10
28
|
federation: boolean | undefined;
|
|
11
29
|
resolvedServerOutput: 'commonjs' | 'module';
|
|
30
|
+
webOutput: NonNullable<Rspack.Configuration['output']>;
|
|
12
31
|
}): void => {
|
|
32
|
+
const nodeChunkLoading =
|
|
33
|
+
resolvedServerOutput === 'module'
|
|
34
|
+
? 'import'
|
|
35
|
+
: federation
|
|
36
|
+
? 'async-node'
|
|
37
|
+
: 'require';
|
|
38
|
+
|
|
39
|
+
api.modifyRspackConfig((rspackConfig, { environment, mergeConfig }) => {
|
|
40
|
+
if (environment.name === 'web') {
|
|
41
|
+
return mergeConfig(rspackConfig, {
|
|
42
|
+
output: {
|
|
43
|
+
...webOutput,
|
|
44
|
+
...(federation ? { chunkLoading: 'import' } : {}),
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
if (environment.name === 'node') {
|
|
49
|
+
return mergeConfig(rspackConfig, {
|
|
50
|
+
output: {
|
|
51
|
+
chunkFormat: resolvedServerOutput,
|
|
52
|
+
chunkLoading: nodeChunkLoading,
|
|
53
|
+
devtoolModuleFilenameTemplate: '[absolute-resource-path]',
|
|
54
|
+
devtoolFallbackModuleFilenameTemplate:
|
|
55
|
+
'[absolute-resource-path]?[hash]',
|
|
56
|
+
workerChunkLoading: nodeChunkLoading,
|
|
57
|
+
wasmLoading: 'fetch',
|
|
58
|
+
module: resolvedServerOutput === 'module',
|
|
59
|
+
chunkFilename: 'static/js/async/[name].js',
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
return rspackConfig;
|
|
64
|
+
});
|
|
65
|
+
|
|
13
66
|
api.modifyEnvironmentConfig(
|
|
14
67
|
async (config, { name, mergeEnvironmentConfig }) => {
|
|
15
68
|
if (name !== 'web' && name !== 'node') {
|
|
@@ -21,6 +74,11 @@ export const registerReactRouterEnvironmentOutput = ({
|
|
|
21
74
|
rspack: rspackConfig => {
|
|
22
75
|
if (federation) {
|
|
23
76
|
ensureFederationAsyncStartup(rspackConfig);
|
|
77
|
+
if (name === 'web') {
|
|
78
|
+
isolateFederationContainerRuntime(rspackConfig);
|
|
79
|
+
} else {
|
|
80
|
+
enforceAsyncOnlyServerSplitChunks(rspackConfig);
|
|
81
|
+
}
|
|
24
82
|
}
|
|
25
83
|
|
|
26
84
|
if (name === 'node') {
|