Skip to content

Commit

Permalink
refactor: align runtime condition of HarmonyImportDependency
Browse files Browse the repository at this point in the history
  • Loading branch information
LingyuCoder committed Feb 8, 2024
1 parent 625e982 commit 3f324c2
Show file tree
Hide file tree
Showing 4 changed files with 188 additions and 16 deletions.
167 changes: 163 additions & 4 deletions crates/rspack_core/src/init_fragment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 12,10 @@ use rspack_util::ext::{DynHash, IntoAny};
use rustc_hash::FxHasher;
use swc_core::ecma::atoms::Atom;

use crate::{property_name, ExportsArgument, GenerateContext, RuntimeGlobals};
use crate::{
merge_runtime, property_name, runtime_condition_expression, ExportsArgument, GenerateContext,
RuntimeCondition, RuntimeGlobals,
};

pub struct InitFragmentContents {
pub start: String,
Expand Down Expand Up @@ -47,8 50,37 @@ impl InitFragmentKey {
fragments: Vec<Box<dyn InitFragment<C>>>,
) -> Box<dyn InitFragment<C>> {
match self {
InitFragmentKey::HarmonyImport(_) => {
let mut iter = fragments.into_iter();
let first = iter
.next()
.expect("keyed_fragments should at least have one value");
let first = first
.into_any()
.downcast::<ConditionalInitFragment>()
.expect("fragment of InitFragmentKey::HarmonyImport should be a ConditionalInitFragment");

if matches!(first.runtime_condition, RuntimeCondition::Boolean(true)) {
return first;
}

let mut res = first;
for fragment in iter {
let fragment = fragment
.into_any()
.downcast::<ConditionalInitFragment>()
.expect(
"fragment of InitFragmentKey::HarmonyImport should be a ConditionalInitFragment",
);
res = ConditionalInitFragment::merge(res, fragment);
if matches!(res.runtime_condition, RuntimeCondition::Boolean(true)) {
return res;
}
}
res
}
InitFragmentKey::HarmonyExports => {
let mut export_map = vec![];
let mut export_map: Vec<(Atom, Atom)> = vec![];
let mut iter = fragments.into_iter();
let first = iter
.next()
Expand Down Expand Up @@ -76,8 108,7 @@ impl InitFragmentKey {
let promises = fragments.into_iter().map(|f| f.into_any().downcast::<AwaitDependenciesInitFragment>().expect("fragment of InitFragmentKey::AwaitDependencies should be a AwaitDependenciesInitFragment")).flat_map(|f| f.promises).collect();
AwaitDependenciesInitFragment::new(promises).boxed()
}
InitFragmentKey::HarmonyImport(_)
| InitFragmentKey::HarmonyFakeNamespaceObjectFragment(_)
InitFragmentKey::HarmonyFakeNamespaceObjectFragment(_)
| InitFragmentKey::HarmonyExportStar(_)
| InitFragmentKey::ExternalModule(_)
| InitFragmentKey::ModuleDecorator(_) => first(fragments),
Expand All @@ -98,6 129,7 @@ fn first<C>(fragments: Vec<Box<dyn InitFragment<C>>>) -> Box<dyn InitFragment<C>

pub trait InitFragmentRenderContext {
fn add_runtime_requirements(&mut self, requirement: RuntimeGlobals);
fn runtime_condition_expression(&mut self, runtime_condition: &RuntimeCondition) -> String;
}

pub trait InitFragment<C>: IntoAny DynHash DynClone Debug Sync Send {
Expand Down Expand Up @@ -201,6 233,15 @@ impl InitFragmentRenderContext for GenerateContext<'_> {
fn add_runtime_requirements(&mut self, requirement: RuntimeGlobals) {
self.runtime_requirements.insert(requirement);
}

fn runtime_condition_expression(&mut self, runtime_condition: &RuntimeCondition) -> String {
runtime_condition_expression(
&self.compilation.chunk_graph,
Some(runtime_condition),
self.runtime,
self.runtime_requirements,
)
}
}

pub struct ChunkRenderContext;
Expand All @@ -209,6 250,10 @@ impl InitFragmentRenderContext for ChunkRenderContext {
fn add_runtime_requirements(&mut self, _requirement: RuntimeGlobals) {
unreachable!("should not add runtime requirements in chunk render context")
}

fn runtime_condition_expression(&mut self, _runtime_condition: &RuntimeCondition) -> String {
unreachable!("should not call runtime condition expression in chunk render context")
}
}

#[derive(Debug, Clone, Hash)]
Expand Down Expand Up @@ -365,3 410,117 @@ impl<C: InitFragmentRenderContext> InitFragment<C> for AwaitDependenciesInitFrag
&InitFragmentKey::AwaitDependencies
}
}

#[derive(Debug, Clone, Hash)]
pub struct ConditionalInitFragment {
content: String,
stage: InitFragmentStage,
position: i32,
key: InitFragmentKey,
end_content: Option<String>,
runtime_condition: RuntimeCondition,
}

impl ConditionalInitFragment {
pub fn new(
content: String,
stage: InitFragmentStage,
position: i32,
key: InitFragmentKey,
end_content: Option<String>,
runtime_condition: RuntimeCondition,
) -> Self {
ConditionalInitFragment {
content,
stage,
position,
key,
end_content,
runtime_condition,
}
}

pub fn merge(
one: Box<ConditionalInitFragment>,
other: Box<ConditionalInitFragment>,
) -> Box<ConditionalInitFragment> {
if matches!(one.runtime_condition, RuntimeCondition::Boolean(true)) {
return one;
}
if matches!(other.runtime_condition, RuntimeCondition::Boolean(true)) {
return other;
}
if matches!(one.runtime_condition, RuntimeCondition::Boolean(false)) {
return other;
}
if matches!(other.runtime_condition, RuntimeCondition::Boolean(false)) {
return one;
}
Box::new(Self {
content: one.content,
stage: one.stage,
position: one.position,
key: one.key,
end_content: one.end_content,
runtime_condition: RuntimeCondition::Spec(merge_runtime(
one.runtime_condition.as_spec().expect("should be spec"),
other.runtime_condition.as_spec().expect("should be spec"),
)),
})
}
}

impl<C: InitFragmentRenderContext> InitFragment<C> for ConditionalInitFragment {
fn contents(self: Box<Self>, context: &mut C) -> Result<InitFragmentContents> {
Ok(
if matches!(self.runtime_condition, RuntimeCondition::Boolean(false))
|| self.content.is_empty()
{
InitFragmentContents {
start: "".to_owned(),
end: Some("".to_owned()),
}
} else if matches!(self.runtime_condition, RuntimeCondition::Boolean(true)) {
InitFragmentContents {
start: self.content,
end: self.end_content,
}
} else {
let condition = context.runtime_condition_expression(&self.runtime_condition);
if condition == "true" {
InitFragmentContents {
start: self.content,
end: self.end_content,
}
} else {
InitFragmentContents {
start: wrap_in_condition(&condition, &self.content),
end: self.end_content.map(|c| wrap_in_condition(&condition, &c)),
}
}
},
)
}

fn stage(&self) -> InitFragmentStage {
self.stage
}

fn position(&self) -> i32 {
self.position
}

fn key(&self) -> &InitFragmentKey {
&self.key
}
}

fn wrap_in_condition(condition: &str, source: &str) -> String {
format!(
r#"
if ({condition}) {{
{source}
}}
"#
)
}
13 changes: 13 additions & 0 deletions crates/rspack_core/src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 34,19 @@ pub enum RuntimeCondition {
Spec(RuntimeSpec),
}

impl std::hash::Hash for RuntimeCondition {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
match self {
Self::Boolean(v) => v.hash(state),
Self::Spec(s) => {
for i in s.iter() {
i.hash(state);
}
}
}
}
}

impl RuntimeCondition {
pub fn as_spec(&self) -> Option<&RuntimeSpec> {
if let Self::Spec(v) = self {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 5,11 @@ use rspack_core::tree_shaking::symbol::{self, IndirectTopLevelSymbol};
use rspack_core::tree_shaking::visitor::SymbolRef;
use rspack_core::{
filter_runtime, get_import_var, import_statement, merge_runtime, AsContextDependency,
AwaitDependenciesInitFragment, ConnectionState, Dependency, DependencyCategory,
DependencyCondition, DependencyId, DependencyTemplate, DependencyType, ErrorSpan,
ExtendedReferencedExport, InitFragmentExt, InitFragmentKey, InitFragmentStage, ModuleDependency,
ModuleIdentifier, NormalInitFragment, RuntimeCondition, RuntimeGlobals, TemplateContext,
TemplateReplaceSource,
AwaitDependenciesInitFragment, ConditionalInitFragment, ConnectionState, Dependency,
DependencyCategory, DependencyCondition, DependencyId, DependencyTemplate, DependencyType,
ErrorSpan, ExtendedReferencedExport, InitFragmentExt, InitFragmentKey, InitFragmentStage,
ModuleDependency, ModuleIdentifier, NormalInitFragment, RuntimeCondition, RuntimeGlobals,
TemplateContext, TemplateReplaceSource,
};
use rspack_core::{ModuleGraph, RuntimeSpec};
use rustc_hash::{FxHashMap, FxHashSet as HashSet};
Expand Down Expand Up @@ -244,7 244,7 @@ pub fn harmony_import_dependency_apply<T: ModuleDependency>(
None => RuntimeCondition::Boolean(false),
};

let mut merged_runtime_condition = runtime_condition;
let mut merged_runtime_condition = runtime_condition.clone();
if !matches!(old_runtime_condition, RuntimeCondition::Boolean(false))
&& !matches!(merged_runtime_condition, RuntimeCondition::Boolean(true))
{
Expand All @@ -266,28 266,31 @@ pub fn harmony_import_dependency_apply<T: ModuleDependency>(

let is_async_module = matches!(ref_module, Some(ref_module) if compilation.module_graph.is_async(ref_module) == Some(true));
if is_async_module {
init_fragments.push(Box::new(NormalInitFragment::new(
init_fragments.push(Box::new(ConditionalInitFragment::new(
content.0,
InitFragmentStage::StageHarmonyImports,
source_order,
InitFragmentKey::HarmonyImport(key.to_string()),
None,
runtime_condition.clone(),
)));
init_fragments.push(AwaitDependenciesInitFragment::new_single(import_var.to_string()).boxed());
init_fragments.push(Box::new(NormalInitFragment::new(
init_fragments.push(Box::new(ConditionalInitFragment::new(
content.1,
InitFragmentStage::StageAsyncHarmonyImports,
source_order,
InitFragmentKey::HarmonyImport(format!("{} compat", key)),
None,
runtime_condition,
)));
} else {
init_fragments.push(Box::new(NormalInitFragment::new(
init_fragments.push(Box::new(ConditionalInitFragment::new(
format!("{}{}", content.0, content.1),
InitFragmentStage::StageHarmonyImports,
source_order,
InitFragmentKey::HarmonyImport(key.to_string()),
None,
runtime_condition,
)));
}

Expand Down

This file was deleted.

0 comments on commit 3f324c2

Please sign in to comment.