Describe the bug
Reproduces on
"@module-federation/rsbuild-plugin": "2.8.0"
If plugin config exposes entry points with the same base name, but different extensions, like these:
exposes: {
'.': './src/index.tsx',
'./css': './src/index.css',
}
then resulting mf-manifest.json will contain duplicated entries in exposes/assets fields:
"exposes": [
{
"id": "App:.",
"name": ".",
"assets": {
"js": {
"sync": [
"static/js/async/__federation_expose_default_export.js",
"static/js/async/__federation_expose_css.js"
],
"async": []
},
"css": {
"sync": [
"static/css/async/__federation_expose_default_export.css",
"static/css/async/__federation_expose_css.css"
],
"async": []
}
},
"path": "."
},
{
"id": "App:css",
"name": "css",
"assets": {
"js": {
"sync": [
"static/js/async/__federation_expose_default_export.js",
"static/js/async/__federation_expose_css.js"
],
"async": []
},
"css": {
"sync": [
"static/css/async/__federation_expose_default_export.css",
"static/css/async/__federation_expose_css.css"
],
"async": []
}
},
"path": "./css"
}
Here is AI report of the investigation (if it helps):
This is a bug in @module-federation/manifest v2.8.0, not intentional
behavior.
The plugin uses getFileNameWithOutExt() — which strips the file extension — as
a map key when grouping expose chunks to expose entries:
// @module-federation/manifest/dist/utils.js
function getFileNameWithOutExt(str) {
return str.replace(path.extname(str), '');
}
When both expose inputs share the same filename stem:
"packages/design-system/src/index.ts" → key: "packages/design-system/src/index"
"packages/design-system/src/index.css" → key: "packages/design-system/src/index"
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// COLLISION — same key, different files
The collision chain:
| Step |
Location |
What happens |
_getModuleAssets() assigns chunk assets to a bucket map |
StatsManager.js:167–220 |
Both input paths reduce to the same stem key → assets from both chunks are merged into one bucket |
fileExposeKeyMap groups expose names by file stem |
ContainerManager.js:116–128 |
Both "." and "./css" map to the same key → Set([".", "./css"]) |
Final stats generation iterates fileExposeKeyMap |
StatsManager.js:410–443 |
For every expose name in the set, pushes the same merged asset list |
mf-stats.json "file" field is also wrong |
ModuleHandler.js:386 |
The ./css expose overwrites the . expose in exposesMap (same stem key) |
The strategy was designed for the case documented in the plugin source:
multiple expose aliases pointing to the same file (e.g.
"." → Button.jsx, "./backup" → Button.jsx). It breaks when two
different files happen to share the same stem (index.ts and index.css).
Reproduction
https://github.com/dalafik/module-federation-bug.git
Used Package Manager
npm
System Info
System:
OS: Linux 6.11 Ubuntu 24.04.2 LTS 24.04.2 LTS (Noble Numbat)
CPU: (20) x64 13th Gen Intel(R) Core(TM) i7-13700H
Memory: 18.82 GB / 30.87 GB
Container: Yes
Shell: 5.2.21 - /bin/bash
Binaries:
Node: 22.17.1
Yarn: 1.22.22
npm: 10.9.2
pnpm: 9.15.4
bun: 1.3.13
Browsers:
Chrome: 148.0.7778.167
Firefox: 152.0.5
Firefox Developer Edition: 152.0.5
Validations
Describe the bug
Reproduces on
If plugin config exposes entry points with the same base name, but different extensions, like these:
then resulting
mf-manifest.jsonwill contain duplicated entries inexposes/assetsfields:Here is AI report of the investigation (if it helps):
This is a bug in
@module-federation/manifestv2.8.0, not intentionalbehavior.
The plugin uses
getFileNameWithOutExt()— which strips the file extension — asa map key when grouping expose chunks to expose entries:
When both expose inputs share the same filename stem:
The collision chain:
_getModuleAssets()assigns chunk assets to a bucket mapStatsManager.js:167–220fileExposeKeyMapgroups expose names by file stemContainerManager.js:116–128"."and"./css"map to the same key →Set([".", "./css"])fileExposeKeyMapStatsManager.js:410–443mf-stats.json"file"field is also wrongModuleHandler.js:386./cssexpose overwrites the.expose inexposesMap(same stem key)The strategy was designed for the case documented in the plugin source:
multiple expose aliases pointing to the same file (e.g.
"." → Button.jsx,"./backup" → Button.jsx). It breaks when twodifferent files happen to share the same stem (
index.tsandindex.css).Reproduction
https://github.com/dalafik/module-federation-bug.git
Used Package Manager
npm
System Info
System: OS: Linux 6.11 Ubuntu 24.04.2 LTS 24.04.2 LTS (Noble Numbat) CPU: (20) x64 13th Gen Intel(R) Core(TM) i7-13700H Memory: 18.82 GB / 30.87 GB Container: Yes Shell: 5.2.21 - /bin/bash Binaries: Node: 22.17.1 Yarn: 1.22.22 npm: 10.9.2 pnpm: 9.15.4 bun: 1.3.13 Browsers: Chrome: 148.0.7778.167 Firefox: 152.0.5 Firefox Developer Edition: 152.0.5Validations