Skip to content

Commit 671e649

Browse files
committed
perf: use module_graphe instead of stats
1 parent 53d488b commit 671e649

File tree

6 files changed

+146
-172
lines changed

6 files changed

+146
-172
lines changed

crates/rspack_plugin_mf/src/manifest/mod.rs

Lines changed: 95 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ mod data;
55
mod options;
66
mod utils;
77

8-
use std::cell::RefCell;
9-
108
use asset::{
119
collect_assets_for_module, collect_assets_from_chunk, collect_usage_files_for_module,
1210
empty_assets_group, merge_assets_group, normalize_assets_group, promote_primary_assets_to_sync,
@@ -22,8 +20,8 @@ pub use options::{
2220
RemoteAliasTarget,
2321
};
2422
use rspack_core::{
25-
Compilation, CompilationAsset, CompilationProcessAssets, ExtendedStatsOptions, ModuleIdentifier,
26-
Plugin, PublicPath, Stats as CoreStats,
23+
Compilation, CompilationAsset, CompilationProcessAssets, ModuleIdentifier, ModuleType, Plugin,
24+
PublicPath,
2725
rspack_sources::{RawStringSource, SourceExt},
2826
};
2927
use rspack_error::Result;
@@ -199,138 +197,109 @@ async fn process_assets(&self, compilation: &mut Compilation) -> Result<()> {
199197
.collect::<Vec<_>>();
200198
(exposes, shared, remote_list)
201199
} else {
202-
// Collect stats from module graph via Stats API
203-
let stats = CoreStats::new(&*compilation);
204-
let options: ExtendedStatsOptions = ExtendedStatsOptions {
205-
modules: true,
206-
reasons: true,
207-
ids: true,
208-
assets: false,
209-
chunks: false,
210-
entrypoints: rspack_core::EntrypointsStatsOption::Bool(true),
211-
cached_modules: true,
212-
hash: true,
213-
chunk_relations: false,
214-
chunk_groups: false,
215-
chunk_group_auxiliary: false,
216-
chunk_group_children: false,
217-
chunk_modules: false,
218-
depth: false,
219-
module_assets: false,
220-
nested_modules: false,
221-
optimization_bailout: false,
222-
provided_exports: false,
223-
source: false,
224-
used_exports: false,
225-
warnings: false,
226-
errors: false,
227-
};
228-
// Gather modules
229-
let exposes_map = RefCell::new(HashMap::<String, StatsExpose>::default());
230-
let shared_map = RefCell::new(HashMap::<String, StatsShared>::default());
231-
let shared_usage_links = RefCell::new(Vec::<(String, String)>::new());
232-
let provide_module_ids = RefCell::new(HashMap::<String, Vec<ModuleIdentifier>>::default());
233-
let consume_module_ids = RefCell::new(HashMap::<String, Vec<ModuleIdentifier>>::default());
234-
let remote_module_ids = RefCell::new(Vec::<ModuleIdentifier>::new());
235-
let container_entry_module = RefCell::new(None::<ModuleIdentifier>);
236-
let module_ids_by_name = RefCell::new(HashMap::<String, ModuleIdentifier>::default());
237-
let self_issued_module_ids = RefCell::new(HashMap::<String, ModuleIdentifier>::default());
238-
stats.get_modules(&options, |modules| {
239-
for m in modules {
240-
let module_identifier = match m.identifier {
241-
Some(id) => id.clone(),
242-
None => continue,
243-
};
244-
let identifier = module_identifier.to_string();
245-
let module_type = m.module_type.as_str();
246-
if let Some(name) = m.name.as_ref() {
247-
module_ids_by_name
248-
.borrow_mut()
249-
.insert(name.to_string(), module_identifier.clone());
250-
if let Some(issuer_name) = m.issuer_name.as_ref()
251-
&& issuer_name.as_ref() == name.as_ref()
252-
{
253-
self_issued_module_ids
254-
.borrow_mut()
255-
.insert(name.to_string(), module_identifier.clone());
200+
let module_graph = compilation.get_module_graph();
201+
let context = &compilation.options.context;
202+
203+
let mut exposes_map: HashMap<String, StatsExpose> = HashMap::default();
204+
let mut shared_map: HashMap<String, StatsShared> = HashMap::default();
205+
let mut shared_usage_links: Vec<(String, String)> = Vec::new();
206+
let mut consume_module_ids: HashMap<String, Vec<ModuleIdentifier>> = HashMap::default();
207+
let mut remote_module_ids: Vec<ModuleIdentifier> = Vec::new();
208+
let mut container_entry_module: Option<ModuleIdentifier> = None;
209+
let mut module_ids_by_name: HashMap<String, ModuleIdentifier> = HashMap::default();
210+
let mut self_issued_module_ids: HashMap<String, ModuleIdentifier> = HashMap::default();
211+
212+
for (module_id, module) in module_graph.modules().into_iter() {
213+
let module_identifier = module_id;
214+
let module_name = module.readable_identifier(context).to_string();
215+
if !module_name.is_empty() {
216+
module_ids_by_name.insert(module_name.clone(), module_identifier);
217+
if let Some(issuer_module) = module_graph.get_issuer(&module_identifier) {
218+
let issuer_name = issuer_module.readable_identifier(context).to_string();
219+
if issuer_name == module_name {
220+
self_issued_module_ids.insert(issuer_name, module_identifier);
256221
}
257222
}
258-
if identifier.starts_with("container entry") {
259-
*container_entry_module.borrow_mut() = Some(module_identifier.clone());
260-
if let Some(exposes) = parse_container_exposes_from_identifier(&identifier) {
261-
let mut exposes_map_ref = exposes_map.borrow_mut();
262-
for (expose_key, import_name, import_file) in exposes {
263-
let name =
264-
import_name.unwrap_or_else(|| expose_key.trim_start_matches("./").to_string());
265-
let id_comp = compose_id_with_separator(&container_name, &name);
266-
let expose_file_key = strip_ext(&import_file);
267-
exposes_map_ref
268-
.entry(expose_file_key.clone())
269-
.or_insert(StatsExpose {
270-
path: expose_key.clone(),
271-
id: id_comp,
272-
name: name.clone(),
273-
requires: Vec::new(),
274-
assets: StatsAssetsGroup::default(),
275-
});
276-
}
223+
}
224+
225+
let module_type = module.module_type();
226+
let identifier = module_identifier.to_string();
227+
228+
if identifier.starts_with("container entry") {
229+
container_entry_module = Some(module_identifier);
230+
if let Some(exposes) = parse_container_exposes_from_identifier(&identifier) {
231+
for (expose_key, import_name, import_file) in exposes {
232+
let expose_name = import_name
233+
.filter(|name| !name.is_empty())
234+
.unwrap_or_else(|| expose_key.trim_start_matches("./").to_string());
235+
let id_comp = compose_id_with_separator(&container_name, &expose_name);
236+
let expose_file_key = strip_ext(&import_file);
237+
exposes_map.entry(expose_file_key).or_insert(StatsExpose {
238+
path: expose_key.clone(),
239+
id: id_comp,
240+
name: expose_name,
241+
requires: Vec::new(),
242+
assets: StatsAssetsGroup::default(),
243+
});
277244
}
278245
}
279-
if identifier.starts_with("remote ") {
280-
remote_module_ids
281-
.borrow_mut()
282-
.push(module_identifier.clone());
246+
continue;
247+
}
248+
249+
if matches!(module_type, ModuleType::Remote) {
250+
remote_module_ids.push(module_identifier);
251+
}
252+
253+
if matches!(module_type, ModuleType::ProvideShared) {
254+
if let Some((pkg, ver)) = parse_provide_shared_identifier(&identifier) {
255+
let entry = ensure_shared_entry(&mut shared_map, &container_name, &pkg);
256+
if entry.version.is_empty() {
257+
entry.version = ver;
258+
}
259+
record_shared_usage(
260+
&mut shared_usage_links,
261+
&pkg,
262+
&module_identifier,
263+
&module_graph,
264+
compilation,
265+
);
283266
}
284-
if module_type == "provide-module" {
285-
if let Some((pkg, ver)) = parse_provide_shared_identifier(&identifier) {
286-
provide_module_ids
287-
.borrow_mut()
288-
.entry(pkg.clone())
289-
.or_default()
290-
.push(module_identifier.clone());
291-
let mut shared_map_ref = shared_map.borrow_mut();
292-
let entry = ensure_shared_entry(&mut *shared_map_ref, &container_name, &pkg);
293-
if entry.version.is_empty() {
294-
entry.version = ver;
267+
continue;
268+
}
269+
270+
if matches!(module_type, ModuleType::ConsumeShared) {
271+
if let Some((pkg, required)) = parse_consume_shared_identifier(&identifier) {
272+
let mut target_ids: Vec<ModuleIdentifier> = Vec::new();
273+
if let Some(issuer_module) = module_graph.get_issuer(&module_identifier) {
274+
let issuer_name = issuer_module.readable_identifier(context).to_string();
275+
if let Some(target) = self_issued_module_ids.get(&issuer_name) {
276+
target_ids.push(*target);
277+
} else if let Some(target) = module_ids_by_name.get(&issuer_name) {
278+
target_ids.push(*target);
295279
}
296-
drop(shared_map_ref);
297-
record_shared_usage(&shared_usage_links, &pkg, &m);
298280
}
299-
} else if module_type == "consume-shared-module" {
300-
if let Some((pkg, required)) = parse_consume_shared_identifier(&identifier) {
301-
let mut target_ids: Vec<ModuleIdentifier> = Vec::new();
302-
if let Some(issuer_name) = m.issuer_name.as_ref() {
303-
if let Some(target) = self_issued_module_ids.borrow().get(issuer_name.as_ref()) {
304-
target_ids.push(target.clone());
305-
} else if let Some(target) = module_ids_by_name.borrow().get(issuer_name.as_ref()) {
306-
target_ids.push(target.clone());
307-
}
308-
}
309-
if target_ids.is_empty() {
310-
target_ids.push(module_identifier.clone());
311-
}
312-
consume_module_ids
313-
.borrow_mut()
314-
.entry(pkg.clone())
315-
.or_default()
316-
.extend(target_ids);
317-
let mut shared_map_ref = shared_map.borrow_mut();
318-
let entry = ensure_shared_entry(&mut *shared_map_ref, &container_name, &pkg);
319-
if entry.requiredVersion.is_none() && required.is_some() {
320-
entry.requiredVersion = required;
321-
}
322-
drop(shared_map_ref);
323-
record_shared_usage(&shared_usage_links, &pkg, &m);
281+
if target_ids.is_empty() {
282+
target_ids.push(module_identifier);
324283
}
284+
consume_module_ids
285+
.entry(pkg.clone())
286+
.or_default()
287+
.extend(target_ids);
288+
let entry = ensure_shared_entry(&mut shared_map, &container_name, &pkg);
289+
if entry.requiredVersion.is_none() && required.is_some() {
290+
entry.requiredVersion = required;
291+
}
292+
record_shared_usage(
293+
&mut shared_usage_links,
294+
&pkg,
295+
&module_identifier,
296+
&module_graph,
297+
compilation,
298+
);
325299
}
326300
}
327-
})?;
328-
let mut exposes_map = exposes_map.into_inner();
329-
let mut shared_map = shared_map.into_inner();
330-
let consume_module_ids = consume_module_ids.into_inner();
331-
let remote_module_ids = remote_module_ids.into_inner();
332-
let container_entry_module = container_entry_module.into_inner();
333-
let shared_usage_links = shared_usage_links.into_inner();
301+
}
302+
334303
collect_expose_requirements(&mut shared_map, &mut exposes_map, shared_usage_links);
335304

336305
let mut aggregated_shared_assets: HashMap<String, StatsAssetsGroup> = HashMap::default();

crates/rspack_plugin_mf/src/manifest/utils.rs

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
use std::{cell::RefCell, path::Path};
1+
use std::path::Path;
22

3-
use rspack_core::StatsModule;
3+
use rspack_core::{Compilation, ModuleGraph, ModuleIdentifier};
44
use rspack_util::fx_hash::FxHashMap as HashMap;
5+
use serde_json::Value;
56

67
use super::data::{StatsExpose, StatsShared};
78

@@ -53,7 +54,7 @@ pub fn parse_container_exposes_from_identifier(
5354
}
5455
let end = end_idx?;
5556
let json_str = &slice[..=end];
56-
let val: serde_json::Value = serde_json::from_str(json_str).ok()?;
57+
let val: Value = serde_json::from_str(json_str).ok()?;
5758
let arr = val.as_array()?;
5859
let mut ret: Vec<(String, Option<String>, String)> = Vec::new();
5960
for item in arr {
@@ -98,20 +99,41 @@ pub fn ensure_shared_entry<'a>(
9899
})
99100
}
100101

101-
pub fn record_shared_usage<'a>(
102-
shared_usage_links: &RefCell<Vec<(String, String)>>,
102+
pub fn record_shared_usage(
103+
shared_usage_links: &mut Vec<(String, String)>,
103104
pkg: &str,
104-
module: &StatsModule<'a>,
105+
module_identifier: &ModuleIdentifier,
106+
module_graph: &ModuleGraph,
107+
compilation: &Compilation,
105108
) {
106-
if let Some(issuer_name) = module.issuer_name.as_ref() {
107-
let key = strip_ext(issuer_name);
108-
shared_usage_links.borrow_mut().push((pkg.to_string(), key));
109+
if let Some(issuer_module) = module_graph.get_issuer(module_identifier) {
110+
let issuer_name = issuer_module
111+
.readable_identifier(&compilation.options.context)
112+
.to_string();
113+
if !issuer_name.is_empty() {
114+
let key = strip_ext(&issuer_name);
115+
shared_usage_links.push((pkg.to_string(), key));
116+
}
109117
}
110-
if let Some(reasons) = module.reasons.as_ref() {
111-
for reason in reasons {
112-
if let Some(module_name) = reason.user_request {
113-
let key = strip_ext(module_name);
114-
shared_usage_links.borrow_mut().push((pkg.to_string(), key));
118+
if let Some(mgm) = module_graph.module_graph_module_by_identifier(module_identifier) {
119+
for dep_id in mgm.incoming_connections() {
120+
let Some(connection) = module_graph.connection_by_dependency_id(dep_id) else {
121+
continue;
122+
};
123+
let Some(dependency) = module_graph.dependency_by_id(&connection.dependency_id) else {
124+
continue;
125+
};
126+
let maybe_request = dependency
127+
.as_module_dependency()
128+
.map(|dep| dep.user_request().to_string())
129+
.or_else(|| {
130+
dependency
131+
.as_context_dependency()
132+
.map(|dep| dep.request().to_string())
133+
});
134+
if let Some(request) = maybe_request {
135+
let key = strip_ext(&request);
136+
shared_usage_links.push((pkg.to_string(), key));
115137
}
116138
}
117139
}

packages/rspack/src/container/ModuleFederationManifestPlugin.ts

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,8 @@ export class ModuleFederationManifestPlugin extends RspackBuiltinPlugin {
256256

257257
compiler.hooks.thisCompilation.tap(this.name, compilation => {
258258
compilation.hooks.afterProcessAssets.tap(this.name, () => {
259+
if (typeof this.opts.additionalData !== "function") return;
260+
259261
const manifestAsset = compilation.getAsset(manifestFileName);
260262
const statsAsset = compilation.getAsset(statsFileName);
261263
if (!manifestAsset || !statsAsset) {
@@ -264,26 +266,16 @@ export class ModuleFederationManifestPlugin extends RspackBuiltinPlugin {
264266
const manifestStr = toStringSource(manifestAsset.source);
265267
const statsStr = toStringSource(statsAsset.source);
266268
if (!manifestStr || !statsStr) return;
267-
let manifest: Manifest;
268-
let stats: Stats;
269-
try {
270-
manifest = JSON.parse(manifestStr);
271-
stats = JSON.parse(statsStr);
272-
} catch (_e) {
273-
return;
274-
}
275-
if (typeof this.opts.additionalData !== "function") return;
276-
try {
277-
this.opts.additionalData({
278-
stats,
279-
manifest,
280-
compilation,
281-
compiler,
282-
bundler: "rspack"
283-
});
284-
} catch (_e) {
285-
return;
286-
}
269+
270+
const manifest: Manifest = JSON.parse(manifestStr);
271+
const stats: Stats = JSON.parse(statsStr);
272+
this.opts.additionalData({
273+
stats,
274+
manifest,
275+
compilation,
276+
compiler,
277+
bundler: "rspack"
278+
});
287279

288280
compilation.updateAsset(
289281
manifestFileName,

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

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,7 @@ module.exports = {
2727
manifest: {
2828
disableAssetsAnalyze: true,
2929
additionalData({ manifest }) {
30-
return {
31-
...manifest,
32-
extra: true
33-
};
30+
manifest.extra = true
3431
}
3532
}
3633
})

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

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,7 @@ module.exports = {
2828
fileName: "custom-manifest.json",
2929
filePath:'custom-path',
3030
additionalData({ manifest }) {
31-
return {
32-
...manifest,
33-
extra: true
34-
};
31+
manifest.extra = true
3532
}
3633
}
3734
})

0 commit comments

Comments
 (0)