Skip to main content

rspack_core/
normal_module.rs

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