Skip to content

Commit cd790ee

Browse files
committed
plugin(mf/manifest): supplement remotes in manifest and stats; derive moduleName; normalize usedIn; add tests for moduleName and usedIn
1 parent 3faa835 commit cd790ee

File tree

5 files changed

+140
-17
lines changed

5 files changed

+140
-17
lines changed

crates/rspack_plugin_mf/src/manifest/mod.rs

Lines changed: 75 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,31 @@ fn get_remote_entry_name(compilation: &Compilation, container_name: &str) -> Opt
8484
}
8585
None
8686
}
87+
fn derive_module_name(alias: &str, internal_request: Option<&str>) -> String {
88+
if let Some(req) = internal_request {
89+
let trimmed = req.trim_start_matches("./");
90+
if trimmed.is_empty() {
91+
req.to_string()
92+
} else {
93+
trimmed.to_string()
94+
}
95+
} else {
96+
let seg = alias.rsplit('/').next().unwrap_or("");
97+
if seg.is_empty() || seg == alias {
98+
".".to_string()
99+
} else {
100+
seg.to_string()
101+
}
102+
}
103+
}
104+
fn normalize_used_in_entry(name: &str) -> String {
105+
let base = name.split(" + ").next().unwrap_or(name);
106+
std::path::Path::new(base)
107+
.file_name()
108+
.and_then(|f| f.to_str())
109+
.unwrap_or(base)
110+
.to_string()
111+
}
87112
#[plugin_hook(CompilationProcessAssets for ModuleFederationManifestPlugin)]
88113
async fn process_assets(&self, compilation: &mut Compilation) -> Result<()> {
89114
// Prepare entrypoint names
@@ -141,7 +166,7 @@ async fn process_assets(&self, compilation: &mut Compilation) -> Result<()> {
141166
},
142167
r#type: None,
143168
};
144-
let (exposes, shared, remote_list) = if self.options.disable_assets_analyze {
169+
let (exposes, shared, mut remote_list) = if self.options.disable_assets_analyze {
145170
let exposes = self
146171
.options
147172
.exposes
@@ -181,11 +206,12 @@ async fn process_assets(&self, compilation: &mut Compilation) -> Result<()> {
181206
} else {
182207
target.name.clone()
183208
};
209+
let module_name = derive_module_name(alias, None);
184210
StatsRemote {
185211
alias: alias.clone(),
186212
consumingFederationContainerName: container_name.clone(),
187213
federationContainerName: remote_container_name.clone(),
188-
moduleName: remote_container_name,
214+
moduleName: module_name,
189215
entry: target.entry.clone(),
190216
usedIn: vec!["UNKNOWN".to_string()],
191217
}
@@ -464,14 +490,7 @@ async fn process_assets(&self, compilation: &mut Compilation) -> Result<()> {
464490
continue;
465491
};
466492
let alias = remote_module.remote_key.clone();
467-
let module_name = {
468-
let trimmed = remote_module.internal_request.trim_start_matches("./");
469-
if trimmed.is_empty() {
470-
remote_module.internal_request.clone()
471-
} else {
472-
trimmed.to_string()
473-
}
474-
};
493+
let module_name = derive_module_name(&alias, Some(remote_module.internal_request.as_str()));
475494
let (entry, federation_container_name) =
476495
if let Some(target) = provided_remote_alias_map.get(&alias) {
477496
let remote_container_name = if target.name.is_empty() {
@@ -487,7 +506,10 @@ async fn process_assets(&self, compilation: &mut Compilation) -> Result<()> {
487506
(None, alias.clone())
488507
};
489508
let used_in =
490-
collect_usage_files_for_module(compilation, &module_graph, &module_id, &entry_point_names);
509+
collect_usage_files_for_module(compilation, &module_graph, &module_id, &entry_point_names)
510+
.into_iter()
511+
.map(|s| normalize_used_in_entry(&s))
512+
.collect();
491513
remote_list.push(StatsRemote {
492514
alias: alias.clone(),
493515
consumingFederationContainerName: container_name.clone(),
@@ -502,13 +524,36 @@ async fn process_assets(&self, compilation: &mut Compilation) -> Result<()> {
502524
let shared = shared_map
503525
.into_values()
504526
.map(|mut v| {
527+
v.usedIn = v
528+
.usedIn
529+
.into_iter()
530+
.map(|s| normalize_used_in_entry(&s))
531+
.collect();
505532
v.usedIn.sort();
506533
v.usedIn.dedup();
507534
v
508535
})
509536
.collect::<Vec<_>>();
510537
(exposes, shared, remote_list)
511538
};
539+
for (alias, target) in self.options.remote_alias_map.iter() {
540+
let exists = remote_list.iter().any(|r| r.alias == *alias);
541+
if !exists {
542+
let remote_container_name = if target.name.is_empty() {
543+
alias.clone()
544+
} else {
545+
target.name.clone()
546+
};
547+
remote_list.push(StatsRemote {
548+
alias: alias.clone(),
549+
consumingFederationContainerName: container_name.clone(),
550+
federationContainerName: remote_container_name.clone(),
551+
moduleName: "UNKNOWN".to_string(),
552+
entry: target.entry.clone().filter(|e| !e.is_empty()),
553+
usedIn: vec!["UNKNOWN".to_string()],
554+
});
555+
}
556+
}
512557
let stats_root = StatsRoot {
513558
id: container_name.clone(),
514559
name: container_name.clone(),
@@ -527,7 +572,7 @@ async fn process_assets(&self, compilation: &mut Compilation) -> Result<()> {
527572
),
528573
);
529574
// Build manifest from stats
530-
let manifest = ManifestRoot {
575+
let mut manifest = ManifestRoot {
531576
id: stats_root.id.clone(),
532577
name: stats_root.name.clone(),
533578
metaData: stats_root.metaData.clone(),
@@ -562,6 +607,24 @@ async fn process_assets(&self, compilation: &mut Compilation) -> Result<()> {
562607
})
563608
.collect(),
564609
};
610+
// Supplement manifest.remotes with registered options if missing
611+
for (alias, target) in self.options.remote_alias_map.iter() {
612+
let exists = manifest.remotes.iter().any(|r| r.alias == *alias);
613+
if !exists {
614+
let remote_container_name = if target.name.is_empty() {
615+
alias.clone()
616+
} else {
617+
target.name.clone()
618+
};
619+
let module_name = derive_module_name(alias, None);
620+
manifest.remotes.push(ManifestRemote {
621+
federationContainerName: remote_container_name.clone(),
622+
moduleName: module_name,
623+
alias: alias.clone(),
624+
entry: target.entry.clone().filter(|e| !e.is_empty()),
625+
});
626+
}
627+
}
565628
let manifest_json: String = serde_json::to_string_pretty(&manifest).expect("serialize manifest");
566629
compilation.emit_asset(
567630
self.options.manifest_file_name.clone(),

tests/rspack-test/configCases/container-1-5/manifest/index.js

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,41 @@ it("should record remote usage", () => {
7777
consumingFederationContainerName: "container",
7878
federationContainerName: "remote",
7979
moduleName: ".",
80-
usedIn: expect.arrayContaining([
80+
usedIn: [
8181
"module.js"
82-
]),
82+
],
8383
entry: 'http://localhost:8000/remoteEntry.js'
84-
})
84+
}),
85+
expect.objectContaining({
86+
alias: "@remote/alias",
87+
consumingFederationContainerName: "container",
88+
federationContainerName: "remote",
89+
moduleName: "List",
90+
usedIn: [
91+
"module.js"
92+
],
93+
entry: 'http://localhost:8000/remoteEntry.js'
94+
}),
95+
expect.objectContaining({
96+
alias: "@dynamic-remote/alias",
97+
consumingFederationContainerName: "container",
98+
federationContainerName: "dynamic_remote",
99+
moduleName: "UNKNOWN",
100+
usedIn: [
101+
"UNKNOWN"
102+
],
103+
entry: 'http://localhost:8001/remoteEntry.js'
104+
}),
105+
expect.objectContaining({
106+
alias: "@scope-scope/ui",
107+
consumingFederationContainerName: "container",
108+
federationContainerName: "ui",
109+
moduleName: "Button",
110+
usedIn: [
111+
"module.js"
112+
],
113+
entry: 'http://localhost:8002/remoteEntry.js'
114+
}),
85115
])
86116
);
87117
});
@@ -92,7 +122,26 @@ it("should persist remote metadata in manifest", () => {
92122
expect.objectContaining({
93123
alias: "@remote/alias",
94124
federationContainerName: "remote",
95-
moduleName: "."
125+
moduleName: ".",
126+
entry: "http://localhost:8000/remoteEntry.js"
127+
}),
128+
expect.objectContaining({
129+
alias: "@remote/alias",
130+
federationContainerName: "remote",
131+
moduleName: "List",
132+
entry: "http://localhost:8000/remoteEntry.js"
133+
}),
134+
expect.objectContaining({
135+
alias: "@dynamic-remote/alias",
136+
federationContainerName: "dynamic_remote",
137+
moduleName: "UNKNOWN",
138+
entry: "http://localhost:8001/remoteEntry.js"
139+
}),
140+
expect.objectContaining({
141+
alias: "@scope-scope/ui",
142+
federationContainerName: "ui",
143+
moduleName: "Button",
144+
entry: "http://localhost:8002/remoteEntry.js"
96145
})
97146
])
98147
);

tests/rspack-test/configCases/container-1-5/manifest/module.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
import react from 'react';
2+
import { loadRemote } from 'mf';
23
import remote from '@remote/alias';
4+
import List from '@remote/alias/List';
5+
import Button from '@scope-scope/ui/Button';
36

47
global.react = react;
58
global.remote = remote;
9+
global.dynamicRemote = loadRemote('@dynamic-remote/alias');
10+
global.Button = Button;
11+
global.List = List
612

713
import('./lazy-module').then(r=>{
814
console.log('lazy module: ',r)

tests/rspack-test/configCases/container-1-5/manifest/node_modules/mf.js

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/rspack-test/configCases/container-1-5/manifest/rspack.config.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ module.exports = {
2323
},
2424
remoteType:'script',
2525
remotes: {
26-
'@remote/alias': 'remote@http://localhost:8000/remoteEntry.js'
26+
'@remote/alias': 'remote@http://localhost:8000/remoteEntry.js',
27+
'@dynamic-remote/alias': 'dynamic_remote@http://localhost:8001/remoteEntry.js',
28+
'@scope-scope/ui': 'ui@http://localhost:8002/remoteEntry.js'
2729
},
2830
shared: {
2931
react: {}

0 commit comments

Comments
 (0)