1use std::{
2 borrow::Cow,
3 hash::Hash,
4 sync::{
5 Arc,
6 atomic::{AtomicUsize, Ordering},
7 },
8};
9
10use derive_more::Debug;
11use rspack_cacheable::{
12 cacheable, cacheable_dyn,
13 with::{As, AsOption, AsPreset},
14};
15use rspack_collections::{Identifiable, IdentifierMap, IdentifierSet};
16use rspack_error::{Diagnosable, Diagnostic, Result, error};
17use rspack_fs::ReadableFileSystem;
18use rspack_hash::{RspackHash, RspackHashDigest};
19use rspack_hook::define_hook;
20use rspack_loader_runner::{AdditionalData, Content, LoaderContext, ResourceData, run_loaders};
21use rspack_sources::{
22 BoxSource, CachedSource, OriginalSource, RawBufferSource, RawStringSource, SourceExt, SourceMap,
23 SourceMapSource, WithoutOriginalOptions,
24};
25use rspack_util::{
26 ext::DynHash,
27 source_map::{ModuleSourceMapConfig, SourceMapKind},
28};
29use serde_json::json;
30use tracing::{Instrument, info_span};
31
32use crate::{
33 AsyncDependenciesBlockIdentifier, BoxDependencyTemplate, BoxLoader, BoxModule,
34 BoxModuleDependency, BuildContext, BuildInfo, BuildMeta, BuildResult, ChunkGraph,
35 CodeGenerationResult, Compilation, ConnectionState, Context, DependenciesBlock, DependencyId,
36 FactoryMeta, GenerateContext, GeneratorOptions, LibIdentOptions, Module,
37 ModuleCodeGenerationContext, ModuleGraph, ModuleGraphCacheArtifact, ModuleIdentifier,
38 ModuleLayer, ModuleType, OptimizationBailoutItem, OutputOptions, ParseContext, ParseResult,
39 ParserAndGenerator, ParserOptions, Resolve, RspackLoaderRunnerPlugin, RunnerContext,
40 RuntimeGlobals, RuntimeSpec, SideEffectsStateArtifact, SourceType, contextify,
41 diagnostics::ModuleBuildError,
42 get_context, module_analyzed_side_effect_free, module_declared_side_effect_free,
43 module_update_hash,
44 utils::{SourceSizeCache, SourceSizeCacheSerde},
45};
46
47#[cacheable]
48#[derive(Debug, Clone)]
49pub enum ModuleIssuer {
50 Unset,
51 None,
52 Some(ModuleIdentifier),
53}
54
55impl ModuleIssuer {
56 pub fn from_identifier(identifier: Option<ModuleIdentifier>) -> Self {
57 match identifier {
58 Some(id) => Self::Some(id),
59 None => Self::None,
60 }
61 }
62
63 pub fn identifier(&self) -> Option<&ModuleIdentifier> {
64 match self {
65 ModuleIssuer::Some(id) => Some(id),
66 _ => None,
67 }
68 }
69
70 pub fn get_module<'a>(&self, module_graph: &'a ModuleGraph) -> Option<&'a BoxModule> {
71 if let Some(id) = self.identifier()
72 && let Some(module) = module_graph.module_by_identifier(id)
73 {
74 Some(module)
75 } else {
76 None
77 }
78 }
79}
80
81define_hook!(NormalModuleReadResource: SeriesBail(resource_data: &ResourceData, fs: &Arc<dyn ReadableFileSystem>) -> Content,tracing=false);
82define_hook!(NormalModuleLoader: Series(loader_context: &mut LoaderContext<RunnerContext>),tracing=false);
83define_hook!(NormalModuleLoaderShouldYield: SeriesBail(loader_context: &LoaderContext<RunnerContext>) -> bool,tracing=false);
84define_hook!(NormalModuleLoaderStartYielding: Series(loader_context: &mut LoaderContext<RunnerContext>),tracing=false);
85define_hook!(NormalModuleBeforeLoaders: Series(module: &mut NormalModule),tracing=false);
86define_hook!(NormalModuleAdditionalData: Series(additional_data: &mut Option<&mut AdditionalData>),tracing=false);
87
88#[derive(Debug, Default)]
89pub struct NormalModuleHooks {
90 pub read_resource: NormalModuleReadResourceHook,
91 pub loader: NormalModuleLoaderHook,
92 pub loader_should_yield: NormalModuleLoaderShouldYieldHook,
93 pub loader_yield: NormalModuleLoaderStartYieldingHook,
94 pub before_loaders: NormalModuleBeforeLoadersHook,
95 pub additional_data: NormalModuleAdditionalDataHook,
96}
97
98#[cacheable]
99#[derive(Debug)]
100pub struct NormalModule {
101 blocks: Vec<AsyncDependenciesBlockIdentifier>,
102 dependencies: Vec<DependencyId>,
103
104 id: ModuleIdentifier,
105 context: Box<Context>,
107 request: String,
109 user_request: String,
111 raw_request: String,
113 module_type: ModuleType,
115 layer: Option<ModuleLayer>,
117 parser_and_generator: Box<dyn ParserAndGenerator>,
119 match_resource: Option<ResourceData>,
121 resource_data: Arc<ResourceData>,
123 #[debug(skip)]
125 loaders: Vec<BoxLoader>,
126
127 #[cacheable(with=AsOption<AsPreset>)]
129 source: Option<BoxSource>,
130
131 resolve_options: Option<Arc<Resolve>>,
133 parser_options: Option<Arc<ParserOptions>>,
135 generator_options: Option<GeneratorOptions>,
137 extract_source_map: Option<bool>,
139
140 #[allow(unused)]
141 debug_id: usize,
142 #[cacheable(with=As<SourceSizeCacheSerde>)]
143 cached_source_sizes: SourceSizeCache,
144 diagnostics: Vec<Diagnostic>,
145
146 code_generation_dependencies: Option<Vec<BoxModuleDependency>>,
147 presentational_dependencies: Option<Vec<BoxDependencyTemplate>>,
148
149 factory_meta: Option<FactoryMeta>,
150 build_info: BuildInfo,
151 build_meta: BuildMeta,
152 parsed: bool,
153
154 source_map_kind: SourceMapKind,
155}
156
157static DEBUG_ID: AtomicUsize = AtomicUsize::new(1);
158
159impl NormalModule {
160 fn create_id<'request>(
161 module_type: &ModuleType,
162 layer: Option<&ModuleLayer>,
163 request: &'request str,
164 ) -> Cow<'request, str> {
165 if let Some(layer) = layer {
166 format!("{module_type}|{request}|{layer}").into()
167 } else if *module_type == ModuleType::JsAuto {
168 request.into()
169 } else {
170 format!("{module_type}|{request}").into()
171 }
172 }
173
174 #[allow(clippy::too_many_arguments)]
175 pub fn new(
176 request: String,
177 user_request: String,
178 raw_request: String,
179 module_type: impl Into<ModuleType>,
180 layer: Option<ModuleLayer>,
181 parser_and_generator: Box<dyn ParserAndGenerator>,
182 parser_options: Option<Arc<ParserOptions>>,
183 generator_options: Option<GeneratorOptions>,
184 match_resource: Option<ResourceData>,
185 resource_data: Arc<ResourceData>,
186 resolve_options: Option<Arc<Resolve>>,
187 loaders: Vec<BoxLoader>,
188 context: Option<Context>,
189 extract_source_map: Option<bool>,
190 ) -> Self {
191 let module_type = module_type.into();
192 let id = Self::create_id(&module_type, layer.as_ref(), &request);
193 Self {
194 blocks: Vec::new(),
195 dependencies: Vec::new(),
196 id: ModuleIdentifier::from(id.as_ref()),
197 context: Box::new(context.unwrap_or_else(|| get_context(&resource_data))),
198 request,
199 user_request,
200 raw_request,
201 module_type,
202 layer,
203 parser_and_generator,
204 parser_options,
205 generator_options,
206 match_resource,
207 resource_data,
208 resolve_options,
209 loaders,
210 source: None,
211 debug_id: DEBUG_ID.fetch_add(1, Ordering::Relaxed),
212 extract_source_map,
213
214 cached_source_sizes: SourceSizeCache::default(),
215 diagnostics: Default::default(),
216 code_generation_dependencies: None,
217 presentational_dependencies: None,
218 factory_meta: None,
219 build_info: Default::default(),
220 build_meta: Default::default(),
221 parsed: false,
222 source_map_kind: SourceMapKind::empty(),
223 }
224 }
225
226 pub fn id(&self) -> ModuleIdentifier {
227 self.id
228 }
229
230 pub fn match_resource(&self) -> Option<&ResourceData> {
231 self.match_resource.as_ref()
232 }
233
234 pub fn match_resource_mut(&mut self) -> &mut Option<ResourceData> {
235 &mut self.match_resource
236 }
237
238 pub fn resource_resolved_data(&self) -> &Arc<ResourceData> {
239 &self.resource_data
240 }
241
242 pub fn request(&self) -> &str {
243 &self.request
244 }
245
246 pub fn user_request(&self) -> &str {
247 &self.user_request
248 }
249
250 pub fn user_request_mut(&mut self) -> &mut String {
251 &mut self.user_request
252 }
253
254 pub fn raw_request(&self) -> &str {
255 &self.raw_request
256 }
257
258 pub fn loaders(&self) -> &[BoxLoader] {
259 &self.loaders
260 }
261
262 pub fn parser_and_generator(&self) -> &dyn ParserAndGenerator {
263 &*self.parser_and_generator
264 }
265
266 pub fn parser_and_generator_mut(&mut self) -> &mut dyn ParserAndGenerator {
267 &mut *self.parser_and_generator
268 }
269
270 pub fn code_generation_dependencies(&self) -> &Option<Vec<BoxModuleDependency>> {
271 &self.code_generation_dependencies
272 }
273
274 pub fn presentational_dependencies(&self) -> &Option<Vec<BoxDependencyTemplate>> {
275 &self.presentational_dependencies
276 }
277
278 #[tracing::instrument(
279 "NormalModule:build_hash", skip_all,fields(
280 resource = self.resource_data.resource()
281 )
282 )]
283 fn init_build_hash(
284 &self,
285 output_options: &OutputOptions,
286 build_meta: &BuildMeta,
287 ) -> RspackHashDigest {
288 let mut hasher = RspackHash::from(output_options);
289 "source".hash(&mut hasher);
290 if let Some(error) = self.first_error() {
291 error.message.hash(&mut hasher);
292 } else if let Some(s) = &self.source {
293 s.hash(&mut hasher);
294 }
295 "meta".hash(&mut hasher);
296 build_meta.hash(&mut hasher);
297 hasher.digest(&output_options.hash_digest)
298 }
299
300 pub fn get_parser_options(&self) -> Option<&ParserOptions> {
301 self.parser_options.as_deref()
302 }
303
304 pub fn get_generator_options(&self) -> Option<&GeneratorOptions> {
305 self.generator_options.as_ref()
306 }
307
308 pub fn get_generator_options_mut(&mut self) -> Option<&mut GeneratorOptions> {
309 self.generator_options.as_mut()
310 }
311
312 pub fn set_generator_options(&mut self, generator_options: Option<GeneratorOptions>) {
313 self.generator_options = generator_options;
314 }
315}
316
317impl Identifiable for NormalModule {
318 #[inline]
319 fn identifier(&self) -> ModuleIdentifier {
320 self.id
321 }
322}
323
324impl DependenciesBlock for NormalModule {
325 fn add_block_id(&mut self, block: AsyncDependenciesBlockIdentifier) {
326 self.blocks.push(block)
327 }
328
329 fn get_blocks(&self) -> &[AsyncDependenciesBlockIdentifier] {
330 &self.blocks
331 }
332
333 fn add_dependency_id(&mut self, dependency: DependencyId) {
334 self.dependencies.push(dependency)
335 }
336
337 fn remove_dependency_id(&mut self, dependency: DependencyId) {
338 self.dependencies.retain(|d| d != &dependency)
339 }
340
341 fn get_dependencies(&self) -> &[DependencyId] {
342 &self.dependencies
343 }
344}
345
346#[cacheable_dyn]
347#[async_trait::async_trait]
348impl Module for NormalModule {
349 fn module_type(&self) -> &ModuleType {
350 &self.module_type
351 }
352
353 fn source_types(&self, module_graph: &ModuleGraph) -> &[SourceType] {
354 self.parser_and_generator.source_types(self, module_graph)
355 }
356
357 fn source(&self) -> Option<&BoxSource> {
358 self.source.as_ref()
359 }
360
361 fn readable_identifier(&self, context: &Context) -> Cow<'_, str> {
362 Cow::Owned(context.shorten(&self.user_request))
363 }
364
365 fn size(&self, source_type: Option<&SourceType>, _compilation: Option<&Compilation>) -> f64 {
366 if let Some(source_type) = source_type {
367 if let Some(size) = self.cached_source_sizes.get(source_type) {
369 return size;
370 }
371
372 let size = f64::max(1.0, self.parser_and_generator.size(self, Some(source_type)));
373 self.cached_source_sizes.get_or_insert(source_type, size)
374 } else {
375 f64::max(1.0, self.parser_and_generator.size(self, source_type))
376 }
377 }
378
379 #[tracing::instrument("NormalModule:build", skip_all, fields(
380 perfetto.track_name = format!("Module Build"),
381 perfetto.process_name = format!("Rspack Build Detail"),
382 module.resource = self.resource_resolved_data().resource(),
383 module.identifier = self.identifier().as_str(),
384 module.loaders = ?self.loaders.iter().map(|l| l.identifier().as_str()).collect::<Vec<_>>())
385 )]
386 async fn build(
387 mut self: Box<Self>,
388 build_context: BuildContext,
389 _compilation: Option<&Compilation>,
390 ) -> Result<BuildResult> {
391 self.parsed = true;
393
394 let no_parse = if let Some(no_parse) = build_context.compiler_options.module.no_parse.as_ref() {
395 no_parse.try_match(self.request.as_str()).await?
396 } else {
397 false
398 };
399
400 build_context
401 .plugin_driver
402 .normal_module_hooks
403 .before_loaders
404 .call(self.as_mut())
405 .await?;
406
407 let plugin = Arc::new(RspackLoaderRunnerPlugin {
408 plugin_driver: build_context.plugin_driver.clone(),
409 extract_source_map: self.extract_source_map,
410 });
411
412 let compiler_id = build_context.compiler_id;
413 let compilation_id = build_context.compilation_id;
414 let compiler_options = build_context.compiler_options.clone();
415 let resolver_factory = build_context.resolver_factory.clone();
416 let fs = build_context.fs.clone();
417 let (mut loader_result, err) = run_loaders(
418 self.loaders.clone(),
419 self.resource_data.clone(),
420 Some(plugin.clone()),
421 RunnerContext {
422 compiler_id,
423 compilation_id,
424 options: compiler_options,
425 resolver_factory,
426 source_map_kind: self.source_map_kind,
427 module: self,
428 },
429 fs,
430 )
431 .instrument(info_span!("NormalModule:run_loaders",))
432 .await;
433 self = loader_result.context.module;
434
435 if let Some(err) = err {
436 self.build_info.cacheable = loader_result.cacheable;
437 self.build_info.file_dependencies = loader_result
438 .file_dependencies
439 .into_iter()
440 .map(Into::into)
441 .collect();
442 self.build_info.context_dependencies = loader_result
443 .context_dependencies
444 .into_iter()
445 .map(Into::into)
446 .collect();
447 self.build_info.missing_dependencies = loader_result
448 .missing_dependencies
449 .into_iter()
450 .map(Into::into)
451 .collect();
452 self.build_info.build_dependencies = loader_result
453 .build_dependencies
454 .into_iter()
455 .map(Into::into)
456 .collect();
457
458 self.source = None;
459
460 let current_loader = loader_result.current_loader.map(|current_loader| {
461 contextify(
462 build_context.compiler_options.context.as_path(),
463 current_loader.as_str(),
464 )
465 });
466 let diagnostic = Diagnostic::from(rspack_error::Error::from(ModuleBuildError::new(
467 err,
468 current_loader,
469 )));
470 self.diagnostics.push(diagnostic);
471
472 self.build_info.hash =
473 Some(self.init_build_hash(&build_context.compiler_options.output, &self.build_meta));
474 return Ok(BuildResult {
475 module: BoxModule::new(self),
476 dependencies: Vec::new(),
477 blocks: Vec::new(),
478 optimization_bailouts: vec![],
479 });
480 };
481
482 build_context
483 .plugin_driver
484 .normal_module_hooks
485 .additional_data
486 .call(&mut loader_result.additional_data.as_mut())
487 .await?;
488 self.add_diagnostics(loader_result.diagnostics);
489
490 let is_binary = self
491 .generator_options
492 .as_ref()
493 .and_then(|g| match g {
494 GeneratorOptions::Asset(g) => g.binary,
495 GeneratorOptions::AssetInline(g) => g.binary,
496 GeneratorOptions::AssetResource(g) => g.binary,
497 _ => None,
498 })
499 .unwrap_or_else(|| self.module_type.is_binary());
500
501 let content = if is_binary {
502 Content::Buffer(loader_result.content.into_bytes())
503 } else {
504 Content::String(loader_result.content.into_string_lossy())
505 };
506 let source = self.create_source(content, loader_result.source_map)?;
507
508 self.build_info.cacheable = loader_result.cacheable;
509 self.build_info.file_dependencies = loader_result
510 .file_dependencies
511 .into_iter()
512 .map(Into::into)
513 .collect();
514 self.build_info.context_dependencies = loader_result
515 .context_dependencies
516 .into_iter()
517 .map(Into::into)
518 .collect();
519 self.build_info.missing_dependencies = loader_result
520 .missing_dependencies
521 .into_iter()
522 .map(Into::into)
523 .collect();
524 self.build_info.build_dependencies = loader_result
525 .build_dependencies
526 .into_iter()
527 .map(Into::into)
528 .collect();
529
530 if no_parse {
531 self.parsed = false;
532 self.source = Some(source);
533 self.code_generation_dependencies = Some(Vec::new());
534 self.presentational_dependencies = Some(Vec::new());
535
536 self.build_info.hash =
537 Some(self.init_build_hash(&build_context.compiler_options.output, &self.build_meta));
538
539 return Ok(BuildResult {
540 module: BoxModule::new(self),
541 dependencies: vec![],
542 blocks: vec![],
543 optimization_bailouts: vec![],
544 });
545 }
546
547 let (
548 ParseResult {
549 source,
550 dependencies,
551 blocks,
552 presentational_dependencies,
553 code_generation_dependencies,
554 side_effects_bailout,
555 },
556 diagnostics,
557 ) = self
558 .parser_and_generator
559 .parse(ParseContext {
560 source: source.clone(),
561 module_context: &self.context,
562 module_identifier: self.id,
563 module_parser_options: self.parser_options.as_deref(),
564 module_type: &self.module_type,
565 module_layer: self.layer.as_ref(),
566 module_user_request: &self.user_request,
567 module_match_resource: self.match_resource.as_ref(),
568 module_source_map_kind: self.source_map_kind,
569 loaders: &self.loaders,
570 resource_data: &self.resource_data,
571 compiler_options: &build_context.compiler_options,
572 additional_data: loader_result.additional_data,
573 factory_meta: self.factory_meta.as_ref(),
574 build_info: &mut self.build_info,
575 build_meta: &mut self.build_meta,
576 parse_meta: loader_result.parse_meta,
577 runtime_template: &build_context.runtime_template,
578 })
579 .await?
580 .split_into_parts();
581 if diagnostics.iter().any(|d| d.is_error()) {
582 self.build_meta = Default::default();
583 }
584 if !diagnostics.is_empty() {
585 self.add_diagnostics(diagnostics);
586 }
587 let optimization_bailouts = if let Some(side_effects_bailout) = side_effects_bailout {
588 let short_id = self.readable_identifier(&build_context.compiler_options.context);
589 vec![OptimizationBailoutItem::SideEffects {
590 node_type: side_effects_bailout.ty,
591 loc: side_effects_bailout.msg,
592 short_id: short_id.to_string(),
593 }]
594 } else {
595 vec![]
596 };
597 self.source = Some(source);
600 self.code_generation_dependencies = Some(code_generation_dependencies);
601 self.presentational_dependencies = Some(presentational_dependencies);
602
603 self.build_info.hash =
604 Some(self.init_build_hash(&build_context.compiler_options.output, &self.build_meta));
605
606 Ok(BuildResult {
607 module: BoxModule::new(self),
608 dependencies,
609 blocks,
610 optimization_bailouts,
611 })
612 }
613
614 async fn code_generation(
616 &self,
617 code_generation_context: &mut ModuleCodeGenerationContext,
618 ) -> Result<CodeGenerationResult> {
619 let ModuleCodeGenerationContext {
620 compilation,
621 runtime,
622 concatenation_scope,
623 runtime_template,
624 } = code_generation_context;
625
626 if let Some(error) = self.first_error() {
627 let mut code_generation_result = CodeGenerationResult::default();
628 let module_graph = compilation.get_module_graph();
629
630 if self
633 .source_types(module_graph)
634 .contains(&SourceType::JavaScript)
635 {
636 let error = error.render_report(compilation.options.stats.colors)?;
637 code_generation_result.add(
638 SourceType::JavaScript,
639 RawStringSource::from(format!("throw new Error({});\n", json!(error))).boxed(),
640 );
641 code_generation_result.concatenation_scope = std::mem::take(concatenation_scope);
642 }
643 return Ok(code_generation_result);
644 }
645 let Some(source) = &self.source else {
646 return Err(error!(
647 "Failed to generate code because ast or source is not set for module {}",
648 self.request
649 ));
650 };
651
652 let mut code_generation_result = CodeGenerationResult::default();
653 if !self.parsed {
654 runtime_template
655 .runtime_requirements_mut()
656 .insert(RuntimeGlobals::MODULE | RuntimeGlobals::EXPORTS | RuntimeGlobals::THIS_AS_EXPORTS);
657 }
658
659 let module_graph = compilation.get_module_graph();
660 for source_type in self.source_types(module_graph) {
661 let generation_result = self
662 .parser_and_generator
663 .generate(
664 source,
665 self,
666 &mut GenerateContext {
667 compilation,
668 runtime_template,
669 data: &mut code_generation_result.data,
670 requested_source_type: *source_type,
671 runtime: *runtime,
672 concatenation_scope: concatenation_scope.as_mut(),
673 },
674 )
675 .await?;
676 code_generation_result.add(*source_type, CachedSource::new(generation_result).boxed());
677 }
678 code_generation_result.concatenation_scope = std::mem::take(concatenation_scope);
679 Ok(code_generation_result)
680 }
681
682 async fn get_runtime_hash(
683 &self,
684 compilation: &Compilation,
685 runtime: Option<&RuntimeSpec>,
686 ) -> Result<RspackHashDigest> {
687 let mut hasher = RspackHash::from(&compilation.options.output);
688 self.build_info.hash.dyn_hash(&mut hasher);
689 if self.source.is_some() {
691 self
692 .parser_and_generator
693 .get_runtime_hash(self, compilation, runtime)
694 .await?
695 .dyn_hash(&mut hasher);
696 }
697 module_update_hash(self, &mut hasher, compilation, runtime);
698 Ok(hasher.digest(&compilation.options.output.hash_digest))
699 }
700
701 fn name_for_condition(&self) -> Option<Box<str>> {
702 let resource = self
704 .match_resource()
705 .unwrap_or_else(|| &self.resource_data)
706 .resource();
707 let idx = resource.find('?');
708 if let Some(idx) = idx {
709 Some(resource[..idx].into())
710 } else {
711 Some(resource.into())
712 }
713 }
714
715 fn lib_ident(&self, options: LibIdentOptions) -> Option<Cow<'_, str>> {
716 let mut ident = String::new();
717 if let Some(layer) = &self.layer {
718 ident += "(";
719 ident += layer;
720 ident += ")/";
721 }
722 ident += &contextify(options.context, self.user_request());
723 Some(Cow::Owned(ident))
724 }
725
726 fn get_resolve_options(&self) -> Option<Arc<Resolve>> {
727 self.resolve_options.clone()
728 }
729
730 fn get_code_generation_dependencies(&self) -> Option<&[BoxModuleDependency]> {
731 if let Some(deps) = self.code_generation_dependencies.as_deref()
732 && !deps.is_empty()
733 {
734 Some(deps)
735 } else {
736 None
737 }
738 }
739
740 fn get_presentational_dependencies(&self) -> Option<&[BoxDependencyTemplate]> {
741 if let Some(deps) = self.presentational_dependencies.as_deref()
742 && !deps.is_empty()
743 {
744 Some(deps)
745 } else {
746 None
747 }
748 }
749
750 fn get_context(&self) -> Option<Box<Context>> {
751 Some(self.context.clone())
752 }
753
754 fn get_layer(&self) -> Option<&ModuleLayer> {
755 self.layer.as_ref()
756 }
757
758 fn get_side_effects_connection_state(
760 &self,
761 module_graph: &ModuleGraph,
762 module_graph_cache: &ModuleGraphCacheArtifact,
763 side_effects_state_artifact: &SideEffectsStateArtifact,
764 module_chain: &mut IdentifierSet,
765 connection_state_cache: &mut IdentifierMap<ConnectionState>,
766 ) -> ConnectionState {
767 module_graph_cache.cached_get_side_effects_connection_state(self.id(), || {
768 if let Some(state) = connection_state_cache.get(&self.id) {
769 return *state;
770 }
771
772 if let Some(side_effect_free) = module_declared_side_effect_free(self) {
773 return ConnectionState::Active(!side_effect_free);
774 }
775
776 if module_analyzed_side_effect_free(self, side_effects_state_artifact) == Some(true) {
777 if module_chain.contains(&self.identifier()) {
779 return ConnectionState::CircularConnection;
780 }
781 module_chain.insert(self.identifier());
782 let mut current = ConnectionState::Active(false);
783 for dependency_id in self.get_dependencies().iter() {
784 let dependency = module_graph.dependency_by_id(dependency_id);
785 let state = dependency.get_module_evaluation_side_effects_state(
786 module_graph,
787 module_graph_cache,
788 side_effects_state_artifact,
789 module_chain,
790 connection_state_cache,
791 );
792 if matches!(state, ConnectionState::Active(true)) {
793 module_chain.remove(&self.identifier());
795 connection_state_cache.insert(self.id, ConnectionState::Active(true));
796 return ConnectionState::Active(true);
797 } else if !matches!(state, ConnectionState::CircularConnection) {
798 current = current + state;
799 }
800 }
801 module_chain.remove(&self.identifier());
802 connection_state_cache.insert(self.id, current);
803 return current;
804 }
805 ConnectionState::Active(true)
806 })
807 }
808
809 fn get_concatenation_bailout_reason(
810 &self,
811 mg: &ModuleGraph,
812 cg: &ChunkGraph,
813 ) -> Option<Cow<'static, str>> {
814 self
815 .parser_and_generator
816 .get_concatenation_bailout_reason(self, mg, cg)
817 }
818
819 fn factory_meta(&self) -> Option<&FactoryMeta> {
820 self.factory_meta.as_ref()
821 }
822
823 fn set_factory_meta(&mut self, factory_meta: FactoryMeta) {
824 self.factory_meta = Some(factory_meta);
825 }
826
827 fn build_info(&self) -> &BuildInfo {
828 &self.build_info
829 }
830
831 fn build_info_mut(&mut self) -> &mut BuildInfo {
832 &mut self.build_info
833 }
834
835 fn build_meta(&self) -> &BuildMeta {
836 &self.build_meta
837 }
838
839 fn build_meta_mut(&mut self) -> &mut BuildMeta {
840 &mut self.build_meta
841 }
842}
843
844impl ModuleSourceMapConfig for NormalModule {
845 fn get_source_map_kind(&self) -> &SourceMapKind {
846 &self.source_map_kind
847 }
848
849 fn set_source_map_kind(&mut self, source_map_kind: SourceMapKind) {
850 self.source_map_kind = source_map_kind;
851 }
852}
853
854impl Diagnosable for NormalModule {
855 fn add_diagnostic(&mut self, diagnostic: Diagnostic) {
856 self.diagnostics.push(diagnostic);
857 }
858
859 fn add_diagnostics(&mut self, mut diagnostics: Vec<Diagnostic>) {
860 self.diagnostics.append(&mut diagnostics);
861 }
862
863 fn diagnostics(&self) -> Cow<'_, [Diagnostic]> {
864 Cow::Borrowed(&self.diagnostics)
865 }
866}
867
868impl NormalModule {
869 fn create_source(&self, content: Content, source_map: Option<SourceMap>) -> Result<BoxSource> {
870 if content.is_buffer() {
871 return Ok(RawBufferSource::from(content.into_bytes()).boxed());
872 }
873 let source_map_kind = self.get_source_map_kind();
874 if source_map_kind.enabled()
875 && let Some(source_map) = source_map
876 {
877 let content = content.into_string_lossy();
878 return Ok(
879 SourceMapSource::new(WithoutOriginalOptions {
880 value: content,
881 name: self.request(),
882 source_map,
883 })
884 .boxed(),
885 );
886 }
887 if source_map_kind.enabled()
888 && let Content::String(content) = content
889 {
890 return Ok(OriginalSource::new(content, self.request()).boxed());
891 }
892 Ok(RawStringSource::from(content.into_string_lossy()).boxed())
893 }
894}