1pub mod internal;
2pub mod rollback;
3
4use std::hash::BuildHasherDefault;
5
6use internal::try_get_module_graph_module_mut_by_identifier;
7use rayon::prelude::*;
8use rspack_collections::{IdentifierHasher, IdentifierMap};
9use rspack_error::Result;
10use rspack_hash::RspackHashDigest;
11use rustc_hash::{FxHashMap as HashMap, FxHasher};
12use swc_core::ecma::atoms::Atom;
13
14use crate::{
15 AsyncDependenciesBlock, AsyncDependenciesBlockIdentifier, AsyncDependenciesBlockIdentifierMap,
16 AsyncModulesArtifact, Compilation, DependenciesBlock, Dependency, ExportInfo,
17 ImportedByDeferModulesArtifact, ModuleGraphCacheArtifact, RuntimeSpec, SideEffectsStateArtifact,
18 UsedNameItem,
19};
20mod module;
21pub use module::*;
22mod connection;
23pub use connection::*;
24
25use crate::{
26 BoxDependency, BoxModule, DependencyCondition, DependencyId, ExportsInfoArtifact,
27 ModuleIdentifier,
28};
29
30pub type ImportVarMap = HashMap<(Option<ModuleIdentifier>, bool), String >;
32
33pub type BuildDependency = (
34 DependencyId,
35 Option<ModuleIdentifier>, );
37
38#[derive(Debug, Clone)]
40pub struct DependencyExtraMeta {
41 pub ids: Vec<Atom>,
42 pub explanation: Option<&'static str>,
43}
44
45#[derive(Debug, Default, Clone)]
46pub struct DependencyParents {
47 pub block: Option<AsyncDependenciesBlockIdentifier>,
48 pub module: ModuleIdentifier,
49 pub index_in_block: usize,
50}
51
52#[derive(Debug, Default)]
53pub struct IncomingConnectionsByOriginModule<'a> {
54 non_modules: Vec<&'a ModuleGraphConnection>,
55 modules: IdentifierMap<Vec<&'a ModuleGraphConnection>>,
56}
57
58impl<'a> IncomingConnectionsByOriginModule<'a> {
59 fn with_capacity(capacity: usize) -> Self {
60 Self {
61 non_modules: Vec::new(),
62 modules: IdentifierMap::with_capacity_and_hasher(capacity, Default::default()),
63 }
64 }
65
66 fn push(
67 &mut self,
68 origin_module: Option<ModuleIdentifier>,
69 connection: &'a ModuleGraphConnection,
70 ) {
71 if let Some(origin_module) = origin_module {
72 self
73 .modules
74 .entry(origin_module)
75 .or_default()
76 .push(connection);
77 } else {
78 self.non_modules.push(connection);
79 }
80 }
81
82 pub fn non_modules(&self) -> &[&'a ModuleGraphConnection] {
83 &self.non_modules
84 }
85
86 pub fn modules(&self) -> &IdentifierMap<Vec<&'a ModuleGraphConnection>> {
87 &self.modules
88 }
89
90 pub fn into_parts(
91 self,
92 ) -> (
93 Vec<&'a ModuleGraphConnection>,
94 IdentifierMap<Vec<&'a ModuleGraphConnection>>,
95 ) {
96 (self.non_modules, self.modules)
97 }
98}
99
100#[derive(Debug, Default)]
108pub(crate) struct ModuleGraphData {
109 pub(crate) modules:
112 rollback::RollbackMap<ModuleIdentifier, BoxModule, BuildHasherDefault<IdentifierHasher>>,
113
114 dependencies: HashMap<DependencyId, BoxDependency>,
116 blocks: AsyncDependenciesBlockIdentifierMap<Box<AsyncDependenciesBlock>>,
118
119 dependency_id_to_parents: HashMap<DependencyId, DependencyParents>,
137 connection_to_condition: HashMap<DependencyId, DependencyCondition>,
139
140 module_graph_modules:
144 rollback::OverlayMap<ModuleIdentifier, ModuleGraphModule, BuildHasherDefault<IdentifierHasher>>,
145
146 connections:
149 rollback::OverlayMap<DependencyId, ModuleGraphConnection, BuildHasherDefault<FxHasher>>,
150
151 dep_meta_map: HashMap<DependencyId, DependencyExtraMeta>,
154}
155impl ModuleGraphData {
156 fn checkpoint(&mut self) {
157 self.modules.checkpoint();
158 self.module_graph_modules.checkpoint();
159 self.connections.checkpoint();
160 }
162 fn recover(&mut self) {
164 self.modules.reset();
165 self.module_graph_modules.reset();
166 self.connections.reset();
167 self.dep_meta_map.clear();
169 }
170}
171
172#[derive(Debug, Default)]
173pub struct ModuleGraph {
174 pub(super) inner: ModuleGraphData,
175}
176impl ModuleGraph {
177 pub fn checkpoint(&mut self) {
179 self.inner.checkpoint()
180 }
181 pub fn reset(&mut self) {
183 self.inner.recover()
184 }
185}
186
187impl ModuleGraph {
188 #[inline]
189 pub fn modules_len(&self) -> usize {
190 self.inner.modules.len()
191 }
192
193 #[inline]
194 pub fn modules(&self) -> impl Iterator<Item = (&ModuleIdentifier, &BoxModule)> {
195 self.inner.modules.iter()
196 }
197
198 #[inline]
199 pub fn modules_par(
200 &self,
201 ) -> impl rayon::prelude::ParallelIterator<Item = (&ModuleIdentifier, &BoxModule)> {
202 self.inner.modules.par_iter()
203 }
204
205 #[inline]
206 pub fn modules_keys(&self) -> impl Iterator<Item = &ModuleIdentifier> {
207 self.inner.modules.iter().map(|(k, _)| k)
208 }
209
210 #[inline]
211 pub fn module_graph_modules(
212 &self,
213 ) -> impl Iterator<Item = (&ModuleIdentifier, &ModuleGraphModule)> {
214 self.inner.module_graph_modules.iter()
215 }
216
217 pub fn get_outcoming_connections_by_module(
219 &self,
220 module_id: &ModuleIdentifier,
221 ) -> IdentifierMap<Vec<&ModuleGraphConnection>> {
222 let connections = self
223 .module_graph_module_by_identifier(module_id)
224 .expect("should have mgm")
225 .outgoing_connections();
226
227 let mut map: IdentifierMap<Vec<&ModuleGraphConnection>> =
228 IdentifierMap::with_capacity_and_hasher(connections.len(), Default::default());
229 for dep_id in connections {
230 let con = self
231 .connection_by_dependency_id(dep_id)
232 .expect("should have connection");
233 map.entry(*con.module_identifier()).or_default().push(con);
234 }
235 map
236 }
237
238 pub fn get_active_outcoming_connections_by_module(
239 &self,
240 module_id: &ModuleIdentifier,
241 runtime: Option<&RuntimeSpec>,
242 module_graph: &ModuleGraph,
243 module_graph_cache: &ModuleGraphCacheArtifact,
244 side_effects_state_artifact: &SideEffectsStateArtifact,
245 exports_info_artifact: &ExportsInfoArtifact,
246 ) -> IdentifierMap<Vec<&ModuleGraphConnection>> {
247 let connections = self
248 .module_graph_module_by_identifier(module_id)
249 .expect("should have mgm")
250 .outgoing_connections();
251
252 let mut map: IdentifierMap<Vec<&ModuleGraphConnection>> =
253 IdentifierMap::with_capacity_and_hasher(connections.len(), Default::default());
254 for dep_id in connections {
255 let con = self
256 .connection_by_dependency_id(dep_id)
257 .expect("should have connection");
258 if !con.is_active(
259 module_graph,
260 runtime,
261 module_graph_cache,
262 side_effects_state_artifact,
263 exports_info_artifact,
264 ) {
265 continue;
266 }
267 map.entry(*con.module_identifier()).or_default().push(con);
268 }
269 map
270 }
271
272 pub fn get_incoming_connections_by_origin_module(
274 &self,
275 module_id: &ModuleIdentifier,
276 ) -> IncomingConnectionsByOriginModule<'_> {
277 let connections = self
278 .module_graph_module_by_identifier(module_id)
279 .expect("should have mgm")
280 .incoming_connections();
281
282 let mut map = IncomingConnectionsByOriginModule::with_capacity(connections.len());
283 for dep_id in connections {
284 let con = self
285 .connection_by_dependency_id(dep_id)
286 .expect("should have connection");
287 map.push(con.original_module_identifier, con);
288 }
289 map
290 }
291
292 pub fn revoke_dependency(
296 &mut self,
297 dep_id: &DependencyId,
298 force: bool,
299 ) -> Option<BuildDependency> {
300 let original_module_identifier = self.get_parent_module(dep_id).copied();
301 let module_identifier = self.module_identifier_by_dependency_id(dep_id).copied();
302 let parent_block = self.get_parent_block(dep_id).copied();
303
304 if module_identifier.is_some() {
305 self.inner.connections.remove(dep_id);
306 }
307 if force {
308 self.inner.dependencies.remove(dep_id);
309 self.inner.dependency_id_to_parents.remove(dep_id);
310 self.inner.connection_to_condition.remove(dep_id);
311 if let Some(m_id) = original_module_identifier
312 && let Some(module) = self.inner.modules.get_mut(&m_id)
313 {
314 module.remove_dependency_id(*dep_id);
315 }
316 if let Some(b_id) = parent_block
317 && let Some(block) = self.inner.blocks.get_mut(&b_id)
318 {
319 block.remove_dependency_id(*dep_id);
320 }
321 }
322
323 if let Some(original_module_identifier) = &original_module_identifier
325 && let Some(mgm) =
326 try_get_module_graph_module_mut_by_identifier(self, original_module_identifier)
327 {
328 mgm.remove_outgoing_connection(dep_id);
329 if force {
330 mgm.all_dependencies_mut().retain(|id| id != dep_id);
331 }
332 }
333 if let Some(module_identifier) = &module_identifier
335 && let Some(mgm) = try_get_module_graph_module_mut_by_identifier(self, module_identifier)
336 {
337 mgm.remove_incoming_connection(dep_id);
338 }
339
340 Some((*dep_id, original_module_identifier))
341 }
342
343 pub fn revoke_module(&mut self, module_id: &ModuleIdentifier) -> Vec<BuildDependency> {
344 let blocks = self
345 .module_by_identifier(module_id)
346 .map(|m| Vec::from(m.get_blocks()))
347 .unwrap_or_default();
348
349 let (incoming_connections, all_dependencies) = self
350 .module_graph_module_by_identifier(module_id)
351 .map(|mgm| {
352 (
353 mgm.incoming_connections().clone(),
354 mgm.all_dependencies().to_vec(),
355 )
356 })
357 .unwrap_or_default();
358
359 self.inner.modules.remove(module_id);
360 self.inner.module_graph_modules.remove(module_id);
361
362 for block in blocks {
363 self.inner.blocks.remove(&block);
364 }
365
366 for dep_id in all_dependencies {
367 self.revoke_dependency(&dep_id, true);
368 }
369
370 incoming_connections
371 .iter()
372 .filter_map(|dep_id| self.revoke_dependency(dep_id, false))
373 .collect()
374 }
375
376 pub fn add_module_graph_module(&mut self, module_graph_module: ModuleGraphModule) {
377 self
378 .inner
379 .module_graph_modules
380 .insert(module_graph_module.module_identifier, module_graph_module);
381 }
382
383 pub fn clone_module_attributes(
385 compilation: &mut Compilation,
386 source_module: &ModuleIdentifier,
387 target_module: &ModuleIdentifier,
388 ) {
389 let module_graph = compilation.get_module_graph_mut();
390 let old_mgm = module_graph
391 .module_graph_module_by_identifier(source_module)
392 .expect("should have mgm");
393
394 let assign_tuple = (
396 old_mgm.post_order_index,
397 old_mgm.pre_order_index,
398 old_mgm.depth,
399 );
400 let new_mgm = module_graph.module_graph_module_by_identifier_mut(target_module);
401 new_mgm.post_order_index = assign_tuple.0;
402 new_mgm.pre_order_index = assign_tuple.1;
403 new_mgm.depth = assign_tuple.2;
404
405 let exports_info = compilation
406 .exports_info_artifact
407 .get_exports_info(source_module);
408 compilation
409 .exports_info_artifact
410 .set_exports_info(*target_module, exports_info);
411
412 let is_async = ModuleGraph::is_async(&compilation.async_modules_artifact, source_module);
413 ModuleGraph::set_async(
414 &mut compilation.async_modules_artifact,
415 *target_module,
416 is_async,
417 );
418 }
419
420 pub fn move_module_connections(
421 &mut self,
422 old_module: &ModuleIdentifier,
423 new_module: &ModuleIdentifier,
424 filter_connection: impl Fn(&ModuleGraphConnection, &Box<dyn Dependency>) -> bool,
425 ) {
426 if old_module == new_module {
427 return;
428 }
429
430 let outgoing_connections = self
432 .module_graph_module_by_identifier(old_module)
433 .expect("should have mgm")
434 .outgoing_connections()
435 .clone();
436 let mut affected_outgoing_connection = vec![];
437 for dep_id in outgoing_connections {
438 let connection = self
439 .connection_by_dependency_id(&dep_id)
440 .expect("should have connection");
441 let dependency = self.dependency_by_id(&dep_id);
442 if filter_connection(connection, dependency) {
443 let connection = self
444 .connection_by_dependency_id_mut(&dep_id)
445 .expect("should have connection");
446 connection.original_module_identifier = Some(*new_module);
447 affected_outgoing_connection.push(dep_id);
448 }
449 }
450
451 let old_mgm = self.module_graph_module_by_identifier_mut(old_module);
452 for dep_id in &affected_outgoing_connection {
453 old_mgm.remove_outgoing_connection(dep_id);
454 }
455
456 let new_mgm = self.module_graph_module_by_identifier_mut(new_module);
457 for dep_id in affected_outgoing_connection {
458 new_mgm.add_outgoing_connection(dep_id);
459 }
460
461 let incoming_connections = self
463 .module_graph_module_by_identifier(old_module)
464 .expect("should have mgm")
465 .incoming_connections()
466 .clone();
467 let mut affected_incoming_connection = vec![];
468 for dep_id in incoming_connections {
469 let connection = self
470 .connection_by_dependency_id(&dep_id)
471 .expect("should have connection");
472 let dependency = self.dependency_by_id(&dep_id);
473 if filter_connection(connection, dependency) {
474 let connection = self
475 .connection_by_dependency_id_mut(&dep_id)
476 .expect("should have connection");
477 connection.set_module_identifier(*new_module);
478 affected_incoming_connection.push(dep_id);
479 }
480 }
481
482 let old_mgm = self.module_graph_module_by_identifier_mut(old_module);
483 for dep_id in &affected_incoming_connection {
484 old_mgm.remove_incoming_connection(dep_id);
485 }
486
487 let new_mgm = self.module_graph_module_by_identifier_mut(new_module);
488 for dep_id in affected_incoming_connection {
489 new_mgm.add_incoming_connection(dep_id);
490 }
491 }
492
493 pub fn copy_outgoing_module_connections<F>(
494 &mut self,
495 old_module: &ModuleIdentifier,
496 new_module: &ModuleIdentifier,
497 filter_connection: F,
498 ) where
499 F: Fn(&ModuleGraphConnection, &BoxDependency) -> bool,
500 {
501 if old_module == new_module {
502 return;
503 }
504
505 let old_mgm_connections = self
506 .module_graph_module_by_identifier(old_module)
507 .expect("should have mgm")
508 .outgoing_connections()
509 .clone();
510
511 let mut affected_outgoing_connections = vec![];
513 for dep_id in old_mgm_connections {
514 let connection = self
515 .connection_by_dependency_id(&dep_id)
516 .expect("should have connection");
517 let dep = self.dependency_by_id(&dep_id);
518 if filter_connection(connection, dep) {
519 let con = self
520 .connection_by_dependency_id_mut(&dep_id)
521 .expect("should have connection");
522 con.original_module_identifier = Some(*new_module);
523 affected_outgoing_connections.push(dep_id);
524 }
525 }
526
527 let new_mgm = self.module_graph_module_by_identifier_mut(new_module);
528 for dep_id in affected_outgoing_connections {
529 new_mgm.add_outgoing_connection(dep_id);
530 }
531 }
532
533 pub fn get_depth(&self, module_id: &ModuleIdentifier) -> Option<usize> {
534 self
535 .module_graph_module_by_identifier(module_id)
536 .and_then(|mgm| mgm.depth)
537 }
538
539 pub fn set_depth_if_lower(&mut self, module_id: &ModuleIdentifier, depth: usize) -> bool {
540 let mgm = self.module_graph_module_by_identifier_mut(module_id);
541 match mgm.depth {
542 Some(cur_depth) if cur_depth <= depth => false,
543 _ => {
544 mgm.depth = Some(depth);
545 true
546 }
547 }
548 }
549
550 pub fn add_module(&mut self, module: BoxModule) {
551 self.inner.modules.insert(module.identifier(), module);
552 }
553
554 pub fn add_block(&mut self, block: Box<AsyncDependenciesBlock>) {
555 self.inner.blocks.insert(block.identifier(), block);
556 }
557
558 pub fn set_parents(&mut self, dependency_id: DependencyId, parents: DependencyParents) {
559 self
560 .inner
561 .dependency_id_to_parents
562 .insert(dependency_id, parents);
563 }
564
565 pub fn get_parent_module(&self, dependency_id: &DependencyId) -> Option<&ModuleIdentifier> {
566 self
567 .inner
568 .dependency_id_to_parents
569 .get(dependency_id)
570 .map(|p| &p.module)
571 }
572
573 pub fn get_parent_block(
574 &self,
575 dependency_id: &DependencyId,
576 ) -> Option<&AsyncDependenciesBlockIdentifier> {
577 self
578 .inner
579 .dependency_id_to_parents
580 .get(dependency_id)
581 .and_then(|p| p.block.as_ref())
582 }
583
584 pub fn get_parent_block_index(&self, dependency_id: &DependencyId) -> Option<usize> {
585 self
586 .inner
587 .dependency_id_to_parents
588 .get(dependency_id)
589 .map(|p| p.index_in_block)
590 }
591
592 pub fn block_by_id(
593 &self,
594 block_id: &AsyncDependenciesBlockIdentifier,
595 ) -> Option<&AsyncDependenciesBlock> {
596 self.inner.blocks.get(block_id).map(AsRef::as_ref)
597 }
598
599 pub fn block_by_id_expect(
600 &self,
601 block_id: &AsyncDependenciesBlockIdentifier,
602 ) -> &AsyncDependenciesBlock {
603 self
604 .inner
605 .blocks
606 .get(block_id)
607 .expect("should insert block before get it")
608 }
609
610 pub fn blocks(&self) -> &AsyncDependenciesBlockIdentifierMap<Box<AsyncDependenciesBlock>> {
611 &self.inner.blocks
612 }
613
614 pub fn dependencies(&self) -> impl Iterator<Item = (&DependencyId, &BoxDependency)> {
615 self.inner.dependencies.iter()
616 }
617
618 pub fn add_dependency(&mut self, dependency: BoxDependency) {
619 self.inner.dependencies.insert(*dependency.id(), dependency);
620 }
621
622 pub fn dependency_by_id(&self, dependency_id: &DependencyId) -> &BoxDependency {
638 self
639 .inner
640 .dependencies
641 .get(dependency_id)
642 .unwrap_or_else(|| panic!("Dependency with ID {dependency_id:?} not found"))
643 }
644
645 pub fn dependency_by_id_mut(&mut self, dependency_id: &DependencyId) -> &mut BoxDependency {
651 self
652 .inner
653 .dependencies
654 .get_mut(dependency_id)
655 .unwrap_or_else(|| panic!("Dependency with ID {dependency_id:?} not found"))
656 }
657
658 pub fn module_graph_module_by_dependency_id(
660 &self,
661 id: &DependencyId,
662 ) -> Option<&ModuleGraphModule> {
663 self
664 .module_identifier_by_dependency_id(id)
665 .and_then(|module_identifier| self.module_graph_module_by_identifier(module_identifier))
666 }
667
668 pub fn module_identifier_by_dependency_id(
669 &self,
670 dep_id: &DependencyId,
671 ) -> Option<&ModuleIdentifier> {
672 self
673 .inner
674 .connections
675 .get(dep_id)
676 .map(|con| con.module_identifier())
677 }
678
679 pub fn get_module_by_dependency_id(&self, dep_id: &DependencyId) -> Option<&BoxModule> {
680 self
681 .module_identifier_by_dependency_id(dep_id)
682 .and_then(|module_id| self.inner.modules.get(module_id))
683 }
684
685 fn add_connection(
686 &mut self,
687 connection: ModuleGraphConnection,
688 condition: Option<DependencyCondition>,
689 ) {
690 if self
691 .connection_by_dependency_id(&connection.dependency_id)
692 .is_some()
693 {
694 return;
695 }
696
697 if let Some(condition) = condition {
698 self
699 .inner
700 .connection_to_condition
701 .insert(connection.dependency_id, condition);
702 }
703
704 let module_id = *connection.module_identifier();
705 let origin_module_id = connection.original_module_identifier;
706 let dependency_id = connection.dependency_id;
707
708 self
710 .inner
711 .connections
712 .insert(connection.dependency_id, connection);
713
714 {
716 let mgm = self.module_graph_module_by_identifier_mut(&module_id);
717
718 mgm.add_incoming_connection(dependency_id);
719 }
720
721 if let Some(identifier) = origin_module_id {
723 let original_mgm = self.module_graph_module_by_identifier_mut(&identifier);
724 original_mgm.add_outgoing_connection(dependency_id);
725 };
726 }
727
728 pub fn set_resolved_module(
730 &mut self,
731 original_module_identifier: Option<ModuleIdentifier>,
732 dependency_id: DependencyId,
733 module_identifier: ModuleIdentifier,
734 ) -> Result<()> {
735 let dependency = self.dependency_by_id(&dependency_id);
736 let is_module_dependency =
737 dependency.as_module_dependency().is_some() || dependency.as_context_dependency().is_some();
738 let condition = dependency
739 .as_module_dependency()
740 .and_then(|dep| dep.get_condition());
741 if !is_module_dependency {
742 return Ok(());
743 }
744
745 let conditional = condition.is_some();
746 let new_connection = ModuleGraphConnection::new(
747 dependency_id,
748 original_module_identifier,
749 module_identifier,
750 conditional,
751 );
752 self.add_connection(new_connection, condition);
753
754 Ok(())
755 }
756
757 pub fn module_by_identifier(&self, identifier: &ModuleIdentifier) -> Option<&BoxModule> {
759 self.inner.modules.get(identifier)
760 }
761
762 pub fn module_by_identifier_mut(
763 &mut self,
764 identifier: &ModuleIdentifier,
765 ) -> Option<&mut BoxModule> {
766 self.inner.modules.get_mut(identifier)
767 }
768
769 pub fn module_graph_module_by_identifier(
771 &self,
772 identifier: &ModuleIdentifier,
773 ) -> Option<&ModuleGraphModule> {
774 self.inner.module_graph_modules.get(identifier)
775 }
776
777 pub fn module_graph_module_by_identifier_mut(
784 &mut self,
785 identifier: &ModuleIdentifier,
786 ) -> &mut ModuleGraphModule {
787 self
788 .inner
789 .module_graph_modules
790 .get_mut(identifier)
791 .unwrap_or_else(|| panic!("ModuleGraphModule with identifier {identifier:?} not found"))
792 }
793
794 pub fn get_ordered_outgoing_connections(
795 &self,
796 module_identifier: &ModuleIdentifier,
797 ) -> impl Iterator<Item = &ModuleGraphConnection> {
798 self
799 .module_graph_module_by_identifier(module_identifier)
800 .map(|m| {
801 m.all_dependencies()
802 .iter()
803 .filter_map(|dep_id| self.connection_by_dependency_id(dep_id))
804 })
805 .into_iter()
806 .flatten()
807 }
808
809 pub fn get_outgoing_deps_in_order(
810 &self,
811 module_identifier: &ModuleIdentifier,
812 ) -> impl Iterator<Item = &DependencyId> {
813 self
814 .module_graph_module_by_identifier(module_identifier)
815 .map(|m| {
816 m.all_dependencies()
817 .iter()
818 .filter(|dep_id| self.connection_by_dependency_id(dep_id).is_some())
819 })
820 .into_iter()
821 .flatten()
822 }
823
824 pub fn connection_by_dependency_id(
825 &self,
826 dependency_id: &DependencyId,
827 ) -> Option<&ModuleGraphConnection> {
828 self.inner.connections.get(dependency_id)
829 }
830
831 pub fn get_resolved_module(&self, dependency_id: &DependencyId) -> Option<&ModuleIdentifier> {
832 match self.connection_by_dependency_id(dependency_id) {
833 Some(connection) => Some(&connection.resolved_module),
834 None => None,
835 }
836 }
837
838 pub fn connection_by_dependency_id_mut(
839 &mut self,
840 dependency_id: &DependencyId,
841 ) -> Option<&mut ModuleGraphConnection> {
842 self.inner.connections.get_mut(dependency_id)
843 }
844
845 pub fn get_pre_order_index(&self, module_id: &ModuleIdentifier) -> Option<u32> {
846 self
847 .module_graph_module_by_identifier(module_id)
848 .and_then(|mgm| mgm.pre_order_index)
849 }
850
851 pub fn get_post_order_index(&self, module_id: &ModuleIdentifier) -> Option<u32> {
852 self
853 .module_graph_module_by_identifier(module_id)
854 .and_then(|mgm| mgm.post_order_index)
855 }
856
857 pub fn get_issuer(&self, module_id: &ModuleIdentifier) -> Option<&BoxModule> {
858 self
859 .module_graph_module_by_identifier(module_id)
860 .and_then(|mgm| mgm.issuer().get_module(self))
861 }
862
863 pub fn is_optional(
864 &self,
865 module_id: &ModuleIdentifier,
866 module_graph_cache: &ModuleGraphCacheArtifact,
867 side_effects_state_artifact: &SideEffectsStateArtifact,
868 exports_info_artifact: &ExportsInfoArtifact,
869 ) -> bool {
870 let mut has_connections = false;
871 for connection in self.get_incoming_connections(module_id) {
872 let dependency = self.dependency_by_id(&connection.dependency_id);
873 let Some(module_dependency) = dependency.as_module_dependency() else {
874 return false;
875 };
876 if !module_dependency.get_optional()
877 || !connection.is_target_active(
878 self,
879 None,
880 module_graph_cache,
881 side_effects_state_artifact,
882 exports_info_artifact,
883 )
884 {
885 return false;
886 }
887 has_connections = true;
888 }
889 has_connections
890 }
891
892 pub fn is_async(
893 async_modules_artifact: &AsyncModulesArtifact,
894 module_id: &ModuleIdentifier,
895 ) -> bool {
896 async_modules_artifact.contains(module_id)
897 }
898
899 pub fn is_deferred(
900 &self,
901 imported_by_defer_modules_artifact: &ImportedByDeferModulesArtifact,
902 module_id: &ModuleIdentifier,
903 ) -> bool {
904 let imported_by_defer = imported_by_defer_modules_artifact.contains(module_id);
905 if !imported_by_defer {
906 return false;
907 }
908 let module = self
909 .module_by_identifier(module_id)
910 .expect("should have module");
911 !module.build_meta().has_top_level_await
912 }
913
914 pub fn set_async(
915 async_modules_artifact: &mut AsyncModulesArtifact,
916 module_id: ModuleIdentifier,
917 is_async: bool,
918 ) -> bool {
919 let original = Self::is_async(async_modules_artifact, &module_id);
920 if original == is_async {
921 return false;
922 }
923 if original {
924 async_modules_artifact.remove(&module_id)
925 } else {
926 async_modules_artifact.insert(module_id)
927 }
928 }
929
930 pub fn get_outgoing_connections(
931 &self,
932 module_id: &ModuleIdentifier,
933 ) -> impl Iterator<Item = &ModuleGraphConnection> + Clone {
934 self
935 .module_graph_module_by_identifier(module_id)
936 .map(|mgm| {
937 mgm
938 .outgoing_connections()
939 .iter()
940 .filter_map(|id| self.connection_by_dependency_id(id))
941 })
942 .into_iter()
943 .flatten()
944 }
945
946 pub fn get_incoming_connections(
947 &self,
948 module_id: &ModuleIdentifier,
949 ) -> impl Iterator<Item = &ModuleGraphConnection> + Clone {
950 self
951 .module_graph_module_by_identifier(module_id)
952 .map(|mgm| {
953 mgm
954 .incoming_connections()
955 .iter()
956 .filter_map(|id| self.connection_by_dependency_id(id))
957 })
958 .into_iter()
959 .flatten()
960 }
961
962 pub fn get_module_hash(&self, module_id: &ModuleIdentifier) -> Option<&RspackHashDigest> {
963 self
964 .module_by_identifier(module_id)
965 .and_then(|m| m.build_info().hash.as_ref())
966 }
967
968 pub fn get_dep_meta_if_existing(&self, id: &DependencyId) -> Option<&DependencyExtraMeta> {
971 self.inner.dep_meta_map.get(id)
972 }
973
974 pub fn set_dependency_extra_meta(&mut self, dep_id: DependencyId, extra: DependencyExtraMeta) {
975 self.inner.dep_meta_map.insert(dep_id, extra);
976 }
977
978 pub fn can_update_module(&self, dep_id: &DependencyId, module_id: &ModuleIdentifier) -> bool {
979 let connection = self
980 .connection_by_dependency_id(dep_id)
981 .expect("should have connection");
982 connection.module_identifier() != module_id
983 }
984
985 pub fn do_update_module(&mut self, dep_id: &DependencyId, module_id: &ModuleIdentifier) {
986 let connection = self
987 .connection_by_dependency_id_mut(dep_id)
988 .unwrap_or_else(|| panic!("{dep_id:?}"));
989 let old_module_identifier = *connection.module_identifier();
990 connection.set_module_identifier(*module_id);
991
992 let old_mgm = self.module_graph_module_by_identifier_mut(&old_module_identifier);
994 old_mgm.remove_incoming_connection(dep_id);
995
996 let new_mgm = self.module_graph_module_by_identifier_mut(module_id);
998 new_mgm.add_incoming_connection(*dep_id);
999 }
1000
1001 pub fn get_optimization_bailout_mut(
1002 &mut self,
1003 id: &ModuleIdentifier,
1004 ) -> &mut Vec<OptimizationBailoutItem> {
1005 let mgm = self.module_graph_module_by_identifier_mut(id);
1006 mgm.optimization_bailout_mut()
1007 }
1008
1009 pub fn get_optimization_bailout(&self, id: &ModuleIdentifier) -> &Vec<OptimizationBailoutItem> {
1010 let mgm = self
1011 .module_graph_module_by_identifier(id)
1012 .expect("should have module graph module");
1013 &mgm.optimization_bailout
1014 }
1015
1016 pub fn get_condition_state(
1017 &self,
1018 connection: &ModuleGraphConnection,
1019 runtime: Option<&RuntimeSpec>,
1020 module_graph_cache: &ModuleGraphCacheArtifact,
1021 side_effects_state_artifact: &SideEffectsStateArtifact,
1022 exports_info_artifact: &ExportsInfoArtifact,
1023 ) -> ConnectionState {
1024 let condition = self
1025 .inner
1026 .connection_to_condition
1027 .get(&connection.dependency_id)
1028 .expect("should have condition");
1029 condition.get_connection_state(
1030 connection,
1031 runtime,
1032 self,
1033 module_graph_cache,
1034 side_effects_state_artifact,
1035 exports_info_artifact,
1036 )
1037 }
1038
1039 pub fn is_connection_active(
1040 &self,
1041 connection: &ModuleGraphConnection,
1042 runtime: Option<&RuntimeSpec>,
1043 module_graph_cache: &ModuleGraphCacheArtifact,
1044 side_effects_state_artifact: &SideEffectsStateArtifact,
1045 exports_info_artifact: &ExportsInfoArtifact,
1046 ) -> bool {
1047 let condition = self
1048 .inner
1049 .connection_to_condition
1050 .get(&connection.dependency_id)
1051 .expect("should have condition");
1052 condition.is_connection_active(
1053 connection,
1054 runtime,
1055 self,
1056 module_graph_cache,
1057 side_effects_state_artifact,
1058 exports_info_artifact,
1059 )
1060 }
1061
1062 pub fn cache_recovery_connection(&mut self, connection: ModuleGraphConnection) {
1064 let condition = self
1065 .dependency_by_id(&connection.dependency_id)
1066 .as_module_dependency()
1067 .and_then(|dep| dep.get_condition());
1068
1069 if let Some(condition) = condition {
1071 self
1072 .inner
1073 .connection_to_condition
1074 .insert(connection.dependency_id, condition);
1075 }
1076
1077 self
1078 .inner
1079 .connections
1080 .insert(connection.dependency_id, connection);
1081 }
1082
1083 pub fn batch_set_connections_original_module(
1084 &mut self,
1085 tasks: Vec<(DependencyId, ModuleIdentifier)>,
1086 ) {
1087 let changed = tasks
1088 .into_par_iter()
1089 .map(|(dep_id, original_module_identifier)| {
1090 let mut con = self
1091 .connection_by_dependency_id(&dep_id)
1092 .expect("should have connection")
1093 .clone();
1094 con.original_module_identifier = Some(original_module_identifier);
1095 (dep_id, con)
1096 })
1097 .collect::<Vec<_>>();
1098
1099 for (dep_id, con) in changed {
1100 self.inner.connections.insert(dep_id, con);
1101 }
1102 }
1103
1104 pub fn batch_set_connections_module(&mut self, tasks: Vec<(DependencyId, ModuleIdentifier)>) {
1105 let changed = tasks
1106 .into_par_iter()
1107 .map(|(dep_id, module_identifier)| {
1108 let mut con = self
1109 .connection_by_dependency_id(&dep_id)
1110 .expect("should have connection")
1111 .clone();
1112 con.set_module_identifier(module_identifier);
1113 (dep_id, con)
1114 })
1115 .collect::<Vec<_>>();
1116
1117 for (dep_id, con) in changed {
1118 self.inner.connections.insert(dep_id, con);
1119 }
1120 }
1121
1122 pub fn batch_add_connections(
1123 &mut self,
1124 tasks: Vec<(ModuleIdentifier, Vec<DependencyId>, Vec<DependencyId>)>,
1125 ) {
1126 let changed = tasks
1127 .into_par_iter()
1128 .map(|(mid, outgoings, incomings)| {
1129 let mut mgm = self
1130 .module_graph_module_by_identifier(&mid)
1131 .expect("should have mgm")
1132 .clone();
1133 for outgoing in outgoings {
1134 mgm.add_outgoing_connection(outgoing);
1135 }
1136 for incoming in incomings {
1137 mgm.add_incoming_connection(incoming);
1138 }
1139 (mid, mgm)
1140 })
1141 .collect::<Vec<_>>();
1142
1143 for (mid, mgm) in changed {
1144 self.inner.module_graph_modules.insert(mid, mgm);
1145 }
1146 }
1147
1148 pub fn batch_remove_connections(
1149 &mut self,
1150 tasks: Vec<(ModuleIdentifier, Vec<DependencyId>, Vec<DependencyId>)>,
1151 ) {
1152 let changed = tasks
1153 .into_par_iter()
1154 .map(|(mid, outgoings, incomings)| {
1155 let mut mgm = self
1156 .module_graph_module_by_identifier(&mid)
1157 .expect("should have mgm")
1158 .clone();
1159 for outgoing in outgoings.iter() {
1160 mgm.remove_outgoing_connection(outgoing);
1161 }
1162 for incoming in incomings.iter() {
1163 mgm.remove_incoming_connection(incoming);
1164 }
1165 (mid, mgm)
1166 })
1167 .collect::<Vec<_>>();
1168
1169 for (mid, mgm) in changed {
1170 self.inner.module_graph_modules.insert(mid, mgm);
1171 }
1172 }
1173
1174 pub fn batch_set_export_info_used_name(
1175 &mut self,
1176 exports_info_artifact: &mut ExportsInfoArtifact,
1177 tasks: Vec<(ExportInfo, UsedNameItem)>,
1178 ) {
1179 for (export_info, used_name) in tasks {
1180 export_info
1181 .as_data_mut(exports_info_artifact)
1182 .set_used_name(used_name);
1183 }
1184 }
1185}