rspack_core/stats/
utils.rs1use std::borrow::Cow;
2
3use itertools::Itertools;
4use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
5use rspack_collections::Identifier;
6use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet};
7
8use super::{
9 Stats, StatsChunkGroup, StatsErrorModuleTraceDependency, StatsErrorModuleTraceModule,
10 StatsModule, StatsModuleTrace,
11};
12use crate::{
13 BoxModule, Chunk, ChunkByUkey, ChunkGraph, ChunkGroupByUkey, ChunkGroupOrderKey, ChunkGroupUkey,
14 Compilation, CompilerOptions, ModuleGraph, ModuleId,
15};
16
17pub fn get_asset_size(file: &str, compilation: &Compilation) -> usize {
18 compilation
19 .assets()
20 .get(file)
21 .and_then(|asset| asset.get_source().map(|s| s.size()))
22 .unwrap_or(0)
23}
24
25pub fn sort_modules(modules: &mut [StatsModule]) {
26 modules.sort_unstable_by(|a, b| {
27 if a.depth != b.depth {
30 a.depth.cmp(&b.depth)
31 } else if a.pre_order_index != b.pre_order_index {
32 a.pre_order_index.cmp(&b.pre_order_index)
33 } else if let (Some(a_name), Some(b_name)) = (&a.name, &b.name)
34 && a_name.len() != b_name.len()
35 {
36 a_name.len().cmp(&b_name.len())
37 } else {
38 a.name.cmp(&b.name)
39 }
40 });
41}
42
43pub fn get_stats_module_name_and_id<'s>(
44 module: &'s BoxModule,
45 compilation: &Compilation,
46) -> (Cow<'s, str>, Option<ModuleId>) {
47 let identifier = module.identifier();
48 let name = module.readable_identifier(&compilation.options.context);
49 let id = ChunkGraph::get_module_id(&compilation.module_ids_artifact, identifier).cloned();
50 (name, id)
51}
52
53pub fn get_chunk_group_ordered_children<'a>(
54 stats: &'a Stats,
55 ordered_children: &HashMap<ChunkGroupOrderKey, Vec<ChunkGroupUkey>>,
56 order_key: &'a ChunkGroupOrderKey,
57 chunk_group_by_ukey: &'a ChunkGroupByUkey,
58 chunk_group_auxiliary: bool,
59) -> Vec<StatsChunkGroup<'a>> {
60 ordered_children
61 .get(order_key)
62 .unwrap_or_else(|| panic!("should have {order_key} chunk groups"))
63 .par_iter()
64 .map(|ukey| {
65 let cg = chunk_group_by_ukey.expect_get(ukey);
66 stats.get_chunk_group(
67 cg.name().unwrap_or_default(),
68 ukey,
69 chunk_group_auxiliary,
70 false,
71 )
72 })
73 .collect::<Vec<_>>()
74}
75
76pub fn get_chunk_group_oreded_child_assets<'a>(
77 ordered_children: &HashMap<ChunkGroupOrderKey, Vec<ChunkGroupUkey>>,
78 order_key: &ChunkGroupOrderKey,
79 chunk_group_by_ukey: &ChunkGroupByUkey,
80 chunk_by_ukey: &'a ChunkByUkey,
81) -> Vec<&'a str> {
82 ordered_children
83 .get(&ChunkGroupOrderKey::Preload)
84 .unwrap_or_else(|| panic!("should have {order_key} chunk groups"))
85 .iter()
86 .flat_map(|ukey| {
87 chunk_group_by_ukey
88 .expect_get(ukey)
89 .chunks
90 .iter()
91 .flat_map(|c| {
92 chunk_by_ukey
93 .expect_get(c)
94 .files()
95 .iter()
96 .map(|file| file.as_str())
97 })
98 .collect::<Vec<_>>()
99 })
100 .unique()
101 .collect::<Vec<_>>()
102}
103
104pub fn get_chunk_relations<'a>(
105 chunk: &Chunk,
106 compilation: &'a Compilation,
107) -> (Vec<&'a str>, Vec<&'a str>, Vec<&'a str>) {
108 let mut parents = HashSet::default();
109 let mut children = HashSet::default();
110 let mut siblings = HashSet::default();
111
112 for cg in chunk.groups() {
113 if let Some(cg) = compilation.chunk_group_by_ukey.get(cg) {
114 for p in &cg.parents {
115 if let Some(pg) = compilation.chunk_group_by_ukey.get(p) {
116 for c in &pg.chunks {
117 if let Some(c) = compilation.chunk_by_ukey.get(c)
118 && let Some(id) = c.id()
119 {
120 parents.insert(id.as_str());
121 }
122 }
123 }
124 }
125
126 for p in &cg.children {
127 if let Some(pg) = compilation.chunk_group_by_ukey.get(p) {
128 for c in &pg.chunks {
129 if let Some(c) = compilation.chunk_by_ukey.get(c)
130 && let Some(id) = c.id()
131 {
132 children.insert(id.as_str());
133 }
134 }
135 }
136 }
137
138 for c in &cg.chunks {
139 if let Some(c) = compilation.chunk_by_ukey.get(c)
140 && c.id() != chunk.id()
141 && let Some(id) = c.id()
142 {
143 siblings.insert(id.as_str());
144 }
145 }
146 }
147 }
148
149 let mut parents = Vec::from_iter(parents);
150 let mut children = Vec::from_iter(children);
151 let mut siblings = Vec::from_iter(siblings);
152
153 parents.sort_unstable();
154 children.sort_unstable();
155 siblings.sort_unstable();
156
157 (parents, children, siblings)
158}
159
160pub fn get_module_trace<'a>(
161 module_identifier: Option<Identifier>,
162 module_graph: &'a ModuleGraph,
163 compilation: &'a Compilation,
164 options: &CompilerOptions,
165) -> Vec<StatsModuleTrace<'a>> {
166 let mut module_trace = vec![];
167 let mut visited_modules = HashSet::<Identifier>::default();
168 let mut current_module_identifier = module_identifier;
169 while let Some(module_identifier) = current_module_identifier {
170 if visited_modules.contains(&module_identifier) {
171 break;
172 }
173 visited_modules.insert(module_identifier);
174 let Some(origin_module) = module_graph.get_issuer(&module_identifier) else {
175 break;
176 };
177 let Some(current_module) = compilation.module_by_identifier(&module_identifier) else {
178 break;
179 };
180 let origin_stats_module = StatsErrorModuleTraceModule {
181 identifier: origin_module.identifier(),
182 name: origin_module.readable_identifier(&options.context),
183 id: ChunkGraph::get_module_id(&compilation.module_ids_artifact, origin_module.identifier())
184 .cloned(),
185 };
186
187 let current_stats_module = StatsErrorModuleTraceModule {
188 identifier: current_module.identifier(),
189 name: current_module.readable_identifier(&options.context),
190 id: ChunkGraph::get_module_id(
191 &compilation.module_ids_artifact,
192 current_module.identifier(),
193 )
194 .cloned(),
195 };
196 let dependencies = module_graph
197 .get_incoming_connections(&module_identifier)
198 .filter_map(|c| {
199 let dep = module_graph.dependency_by_id(&c.dependency_id);
200 let loc = dep.loc().map(|loc| loc.to_string())?;
201 Some(StatsErrorModuleTraceDependency { loc })
202 })
203 .collect::<Vec<_>>();
204
205 module_trace.push(StatsModuleTrace {
206 origin: origin_stats_module,
207 module: current_stats_module,
208 dependencies,
209 });
210
211 current_module_identifier = Some(origin_module.identifier());
212 }
213
214 module_trace
215}