rspack_plugin_javascript 0.100.0-rc.3

rspack javascript plugin
Documentation
use rspack_cacheable::{cacheable, cacheable_dyn};
use rspack_collections::{IdentifierMap, IdentifierSet};
use rspack_core::{
  AsContextDependency, AsModuleDependency, Compilation, ConnectionState, Dependency,
  DependencyCodeGeneration, DependencyId, DependencyRange, DependencyTemplate,
  DependencyTemplateType, ModuleGraph, ModuleGraphCacheArtifact, ModuleIdentifier,
  RuntimeCondition, RuntimeSpec, SideEffectsStateArtifact, TemplateContext, TemplateReplaceSource,
  UsedByExports,
};
use rspack_util::ext::DynHash;

use crate::runtime_condition_used_by_exports;

#[cacheable]
#[derive(Debug, Clone)]
pub struct PureExpressionDependency {
  pub range: DependencyRange,
  used_by_exports: Option<UsedByExports>,
  id: DependencyId,
  pub module_identifier: ModuleIdentifier,
}

impl PureExpressionDependency {
  pub fn new(range: DependencyRange, module_identifier: ModuleIdentifier) -> Self {
    Self {
      range,
      used_by_exports: None,
      id: DependencyId::default(),
      module_identifier,
    }
  }

  fn get_runtime_condition(
    &self,
    compilation: &Compilation,
    runtime: Option<&RuntimeSpec>,
  ) -> RuntimeCondition {
    runtime_condition_used_by_exports(
      compilation,
      &self.module_identifier,
      runtime,
      self.used_by_exports.as_ref(),
    )
  }

  pub fn set_used_by_exports(&mut self, used_by_exports: Option<UsedByExports>) {
    self.used_by_exports = used_by_exports;
  }
}

#[cacheable_dyn]
impl Dependency for PureExpressionDependency {
  fn id(&self) -> &rspack_core::DependencyId {
    &self.id
  }

  fn range(&self) -> Option<DependencyRange> {
    Some(self.range)
  }

  fn get_module_evaluation_side_effects_state(
    &self,
    _module_graph: &ModuleGraph,
    _module_graph_cache: &ModuleGraphCacheArtifact,
    _side_effects_state_artifact: &SideEffectsStateArtifact,
    _module_chain: &mut IdentifierSet,
    _connection_state_cache: &mut IdentifierMap<ConnectionState>,
  ) -> ConnectionState {
    ConnectionState::Active(false)
  }

  fn could_affect_referencing_module(&self) -> rspack_core::AffectType {
    rspack_core::AffectType::False
  }
}

impl AsModuleDependency for PureExpressionDependency {}

#[cacheable_dyn]
impl DependencyCodeGeneration for PureExpressionDependency {
  fn dependency_template(&self) -> Option<DependencyTemplateType> {
    Some(PureExpressionDependencyTemplate::template_type())
  }

  fn update_hash(
    &self,
    hasher: &mut dyn std::hash::Hasher,
    compilation: &Compilation,
    runtime: Option<&RuntimeSpec>,
  ) {
    let runtime_condition = self.get_runtime_condition(compilation, runtime);
    runtime_condition.dyn_hash(hasher);
  }
}

impl AsContextDependency for PureExpressionDependency {}

#[cacheable]
#[derive(Debug, Clone, Default)]
pub struct PureExpressionDependencyTemplate;

impl PureExpressionDependencyTemplate {
  pub fn template_type() -> DependencyTemplateType {
    DependencyTemplateType::Custom("PureExpressionDependency")
  }
}

impl DependencyTemplate for PureExpressionDependencyTemplate {
  fn render(
    &self,
    dep: &dyn DependencyCodeGeneration,
    source: &mut TemplateReplaceSource,
    code_generatable_context: &mut TemplateContext,
  ) {
    let dep = dep
      .as_any()
      .downcast_ref::<PureExpressionDependency>()
      .expect("PureExpressionDependencyTemplate should be used for PureExpressionDependency");

    let runtime_condition = dep.get_runtime_condition(
      code_generatable_context.compilation,
      code_generatable_context.runtime,
    );
    let condition = match &runtime_condition {
      rspack_core::RuntimeCondition::Boolean(true) => return,
      rspack_core::RuntimeCondition::Boolean(false) => None,
      rspack_core::RuntimeCondition::Spec(_spec) => Some(
        code_generatable_context
          .runtime_template
          .runtime_condition_expression(
            &code_generatable_context
              .compilation
              .build_chunk_graph_artifact
              .chunk_graph,
            Some(&runtime_condition),
            code_generatable_context.runtime,
          ),
      ),
    };

    if let Some(condition) = condition {
      source.insert(
        dep.range.start,
        format!("(/* runtime-dependent pure expression or super */ {condition} ? ("),
        None,
      );
      source.insert_static(dep.range.end, ") : null)", None);
    } else {
      source.insert_static(
        dep.range.start,
        "(/* unused pure expression or super */ null && (",
        None,
      );
      source.insert_static(dep.range.end, "))", None);
    }
  }
}