Skip to content

Commit

Permalink
Implement skipping of side effect free fragments
Browse files Browse the repository at this point in the history
  • Loading branch information
kdy1 committed Oct 16, 2024
1 parent 1e0f250 commit b081b30
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 58 deletions.
18 changes: 16 additions & 2 deletions turbopack/crates/turbopack-ecmascript/src/references/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ use turbopack_core::{
compile_time_info::{
CompileTimeInfo, DefineableNameSegment, FreeVarReference, FreeVarReferences,
},
context::AssetContext,
environment::Rendering,
error::PrettyPrintError,
issue::{analyze::AnalyzeIssue, IssueExt, IssueSeverity, IssueSource, StyledString},
Expand Down Expand Up @@ -123,7 +124,7 @@ use crate::{
top_level_await::has_top_level_await,
ConstantNumber, ConstantString, JsValueUrlKind, RequireContextValue,
},
chunk::EcmascriptExports,
chunk::{EcmascriptChunkPlaceable, EcmascriptExports},
code_gen::{CodeGen, CodeGenerateable, CodeGenerateableWithAsyncModuleInfo, CodeGenerateables},
magic_identifier,
parse::parse,
Expand Down Expand Up @@ -584,7 +585,18 @@ pub(crate) async fn analyse_ecmascript_module_internal(

let mut evaluation_references = Vec::new();

let side_effect_free_packages = module.asset_context().side_effect_free_packages();
let is_side_effect_free = *module
.is_marked_as_side_effect_free(side_effect_free_packages)
.await?;

for (i, r) in eval_context.imports.references().enumerate() {
// If side effect free, ImportedSymbol::PartEvaluation doesn't need to be evaluated
let is_fragment_import = matches!(
r.imported_symbol,
ImportedSymbol::PartEvaluation(_) | ImportedSymbol::Part(_)
);

let r = EsmAssetReference::new(
origin,
Request::parse(Value::new(RcStr::from(&*r.module_path).into())),
Expand All @@ -599,7 +611,9 @@ pub(crate) async fn analyse_ecmascript_module_internal(
}
ImportedSymbol::Symbol(name) => Some(ModulePart::export((&**name).into())),
ImportedSymbol::PartEvaluation(part_id) => {
evaluation_references.push(i);
if !is_side_effect_free || !is_fragment_import {
evaluation_references.push(i);
}
Some(ModulePart::internal(*part_id))
}
ImportedSymbol::Part(part_id) => Some(ModulePart::internal(*part_id)),
Expand Down
60 changes: 4 additions & 56 deletions turbopack/crates/turbopack-ecmascript/src/tree_shake/asset.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
use anyhow::{Context, Result};
use anyhow::Result;
use turbo_tasks::Vc;
use turbopack_core::{
asset::{Asset, AssetContent},
chunk::{AsyncModuleInfo, ChunkableModule, ChunkingContext, EvaluatableAsset},
ident::AssetIdent,
module::Module,
reference::{ModuleReference, ModuleReferences, SingleModuleReference},
reference::ModuleReferences,
resolve::ModulePart,
};

use super::{
chunk_item::EcmascriptModulePartChunkItem, get_part_id, part_of_module, split, split_module,
PartId, SplitResult,
chunk_item::EcmascriptModulePartChunkItem, part_of_module, split, split_module, SplitResult,
};
use crate::{
chunk::{EcmascriptChunkPlaceable, EcmascriptExports},
Expand Down Expand Up @@ -123,60 +122,9 @@ impl Module for EcmascriptModulePartAsset {

#[turbo_tasks::function]
async fn references(&self) -> Result<Vc<ModuleReferences>> {
let split_data = split_module(self.full_module).await?;

let analyze = analyze(self.full_module, self.part).await?;

let deps = match &*split_data {
SplitResult::Ok { deps, .. } => deps,
SplitResult::Failed { .. } => return Ok(analyze.references),
};

let part_dep = |part: Vc<ModulePart>| -> Vc<Box<dyn ModuleReference>> {
Vc::upcast(SingleModuleReference::new(
Vc::upcast(EcmascriptModulePartAsset::new(self.full_module, part)),
Vc::cell("ecmascript module part".into()),
))
};

let mut references = analyze.references.await?.to_vec();

// Facade depends on evaluation and re-exports
if matches!(&*self.part.await?, ModulePart::Facade) {
references.push(part_dep(ModulePart::evaluation()));
references.push(part_dep(ModulePart::exports()));
return Ok(Vc::cell(references));
}

let deps = {
let part_id = get_part_id(&split_data, self.part)
.await
.with_context(|| format!("part {:?} is not found in the module", self.part))?;

match deps.get(&part_id) {
Some(v) => &**v,
None => &[],
}
};

references.extend(
deps.iter()
.filter_map(|part_id| {
Some(part_dep(match part_id {
// This is an internal part that is not for evaluation, so we don't need to
// force-add it.
PartId::Internal(.., false) => return None,
PartId::Internal(part_id, true) => ModulePart::internal(*part_id),
PartId::Export(name) => ModulePart::export(name.clone()),
_ => unreachable!(
"PartId other than Internal and Export should not be used here"
),
}))
})
.collect::<Vec<_>>(),
);

Ok(Vc::cell(references))
Ok(analyze.references)
}
}

Expand Down

0 comments on commit b081b30

Please # to comment.