Skip to content

Commit 9668380

Browse files
committed
Scope hoist tree shaking module types as well
1 parent 9ce1d87 commit 9668380

File tree

5 files changed

+141
-29
lines changed

5 files changed

+141
-29
lines changed

turbopack/crates/turbopack-ecmascript/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -971,7 +971,7 @@ impl EcmascriptModuleContentOptions {
971971

972972
let part_code_gens = part_references
973973
.iter()
974-
.map(|r| r.code_generation(**chunking_context))
974+
.map(|r| r.code_generation(**chunking_context, scope_hoisting_context))
975975
.try_join()
976976
.await?;
977977

turbopack/crates/turbopack-ecmascript/src/references/esm/base.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -544,8 +544,9 @@ impl EsmAssetReference {
544544
.as_ref()
545545
.is_none_or(|e| matches!(e, ModulePart::Exports))
546546
{
547-
// No need to import, the module is already available in the same scope
548-
// hoisting group (unless it's a namespace import)
547+
// No need to import, the module was already executed and is available in
548+
// the same scope hoisting group (unless it's a
549+
// namespace import)
549550
} else if let Some(ident) = referenced_asset
550551
.get_ident(chunking_context, None, scope_hoisting_context)
551552
.await?

turbopack/crates/turbopack-ecmascript/src/side_effect_optimization/facade/module.rs

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
use std::collections::BTreeMap;
22

3-
use anyhow::{Result, bail};
3+
use anyhow::{Context, Result, bail};
44
use turbo_rcstr::rcstr;
55
use turbo_tasks::{ResolvedVc, Vc};
66
use turbo_tasks_fs::{File, FileContent, glob::Glob};
77
use turbopack_core::{
88
asset::{Asset, AssetContent},
9-
chunk::{AsyncModuleInfo, ChunkableModule, ChunkingContext, EvaluatableAsset},
9+
chunk::{
10+
AsyncModuleInfo, ChunkableModule, ChunkingContext, EvaluatableAsset, MergeableModule,
11+
MergeableModules, MergeableModulesExposed,
12+
},
1013
ident::AssetIdent,
1114
module::Module,
1215
module_graph::ModuleGraph,
@@ -17,7 +20,7 @@ use turbopack_core::{
1720
use super::chunk_item::EcmascriptModuleFacadeChunkItem;
1821
use crate::{
1922
AnalyzeEcmascriptModuleResult, EcmascriptAnalyzable, EcmascriptModuleContent,
20-
EcmascriptModuleContentOptions, SpecifiedModuleType,
23+
EcmascriptModuleContentOptions, EcmascriptOptions, MergedEcmascriptModule, SpecifiedModuleType,
2124
chunk::{EcmascriptChunkPlaceable, EcmascriptExports},
2225
code_gen::CodeGens,
2326
parse::ParseResult,
@@ -450,3 +453,36 @@ impl ChunkableModule for EcmascriptModuleFacadeModule {
450453

451454
#[turbo_tasks::value_impl]
452455
impl EvaluatableAsset for EcmascriptModuleFacadeModule {}
456+
457+
#[turbo_tasks::value_impl]
458+
impl MergeableModule for EcmascriptModuleFacadeModule {
459+
#[turbo_tasks::function]
460+
async fn merge(
461+
self: Vc<Self>,
462+
modules: Vc<MergeableModulesExposed>,
463+
entry_points: Vc<MergeableModules>,
464+
) -> Result<Vc<Box<dyn ChunkableModule>>> {
465+
Ok(Vc::upcast(*MergedEcmascriptModule::new(
466+
modules
467+
.await?
468+
.iter()
469+
.map(|(m, exposed)| {
470+
Ok((
471+
ResolvedVc::try_sidecast::<Box<dyn EcmascriptAnalyzable>>(*m)
472+
.context("expected EcmascriptAnalyzable")?,
473+
*exposed,
474+
))
475+
})
476+
.collect::<Result<Vec<_>>>()?,
477+
entry_points
478+
.await?
479+
.iter()
480+
.map(|m| {
481+
ResolvedVc::try_sidecast::<Box<dyn EcmascriptAnalyzable>>(*m)
482+
.context("expected EcmascriptAnalyzable")
483+
})
484+
.collect::<Result<Vec<_>>>()?,
485+
EcmascriptOptions::default().resolved_cell(),
486+
)))
487+
}
488+
}

turbopack/crates/turbopack-ecmascript/src/side_effect_optimization/locals/module.rs

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
use std::collections::BTreeMap;
22

3-
use anyhow::{Result, bail};
3+
use anyhow::{Context, Result, bail};
44
use turbo_tasks::{ResolvedVc, Vc};
55
use turbo_tasks_fs::glob::Glob;
66
use turbopack_core::{
77
asset::{Asset, AssetContent},
8-
chunk::{AsyncModuleInfo, ChunkableModule, ChunkingContext},
8+
chunk::{
9+
AsyncModuleInfo, ChunkableModule, ChunkingContext, MergeableModule, MergeableModules,
10+
MergeableModulesExposed,
11+
},
912
ident::AssetIdent,
1013
module::Module,
1114
module_graph::ModuleGraph,
@@ -16,7 +19,7 @@ use turbopack_core::{
1619
use super::chunk_item::EcmascriptModuleLocalsChunkItem;
1720
use crate::{
1821
AnalyzeEcmascriptModuleResult, EcmascriptAnalyzable, EcmascriptModuleAsset,
19-
EcmascriptModuleContent, EcmascriptModuleContentOptions,
22+
EcmascriptModuleContent, EcmascriptModuleContentOptions, MergedEcmascriptModule,
2023
chunk::{EcmascriptChunkPlaceable, EcmascriptExports},
2124
references::{
2225
async_module::OptionAsyncModule,
@@ -205,3 +208,36 @@ impl ChunkableModule for EcmascriptModuleLocalsModule {
205208
)
206209
}
207210
}
211+
212+
#[turbo_tasks::value_impl]
213+
impl MergeableModule for EcmascriptModuleLocalsModule {
214+
#[turbo_tasks::function]
215+
async fn merge(
216+
&self,
217+
modules: Vc<MergeableModulesExposed>,
218+
entry_points: Vc<MergeableModules>,
219+
) -> Result<Vc<Box<dyn ChunkableModule>>> {
220+
Ok(Vc::upcast(*MergedEcmascriptModule::new(
221+
modules
222+
.await?
223+
.iter()
224+
.map(|(m, exposed)| {
225+
Ok((
226+
ResolvedVc::try_sidecast::<Box<dyn EcmascriptAnalyzable>>(*m)
227+
.context("expected EcmascriptAnalyzable")?,
228+
*exposed,
229+
))
230+
})
231+
.collect::<Result<Vec<_>>>()?,
232+
entry_points
233+
.await?
234+
.iter()
235+
.map(|m| {
236+
ResolvedVc::try_sidecast::<Box<dyn EcmascriptAnalyzable>>(*m)
237+
.context("expected EcmascriptAnalyzable")
238+
})
239+
.collect::<Result<Vec<_>>>()?,
240+
self.module.await?.options,
241+
)))
242+
}
243+
}

turbopack/crates/turbopack-ecmascript/src/side_effect_optimization/reference.rs

Lines changed: 59 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use anyhow::{Context, Result, bail};
22
use serde::{Deserialize, Serialize};
3-
use swc_core::{common::DUMMY_SP, quote};
3+
use swc_core::{common::DUMMY_SP, ecma::ast::Lit, quote};
44
use turbo_rcstr::RcStr;
55
use turbo_tasks::{NonLocalValue, ResolvedVc, ValueToString, Vc, trace::TraceRawVcs};
66
use turbopack_core::{
@@ -17,8 +17,11 @@ use super::{
1717
facade::module::EcmascriptModuleFacadeModule, locals::module::EcmascriptModuleLocalsModule,
1818
};
1919
use crate::{
20-
ScopeHoistingContext, chunk::EcmascriptChunkPlaceable, code_gen::CodeGeneration,
21-
references::esm::base::ReferencedAsset, runtime_functions::TURBOPACK_IMPORT,
20+
ScopeHoistingContext,
21+
chunk::EcmascriptChunkPlaceable,
22+
code_gen::{CodeGeneration, CodeGenerationHoistedStmt},
23+
references::esm::base::ReferencedAsset,
24+
runtime_functions::TURBOPACK_IMPORT,
2225
utils::module_id_to_lit,
2326
};
2427

@@ -152,29 +155,65 @@ impl EcmascriptModulePartReference {
152155
pub async fn code_generation(
153156
self: Vc<Self>,
154157
chunking_context: Vc<Box<dyn ChunkingContext>>,
158+
scope_hoisting_context: ScopeHoistingContext<'_>,
155159
) -> Result<CodeGeneration> {
156160
let referenced_asset = ReferencedAsset::from_resolve_result(self.resolve_reference());
157161
let referenced_asset = referenced_asset.await?;
158-
let ident = referenced_asset
159-
.get_ident(chunking_context, None, ScopeHoistingContext::None)
160-
.await?
161-
.context("part module reference should have an ident")?
162-
.as_expr_individual(DUMMY_SP)
163-
.unwrap_left();
162+
let part = &self.await?.part;
164163

165164
let ReferencedAsset::Some(module) = *referenced_asset else {
166165
bail!("part module reference should have an module reference");
167166
};
168-
let id = module.chunk_item_id(Vc::upcast(chunking_context)).await?;
169-
170-
Ok(CodeGeneration::hoisted_stmt(
171-
ident.sym.as_str().into(),
172-
quote!(
173-
"var $name = $turbopack_import($id);" as Stmt,
174-
name = ident,
175-
turbopack_import: Expr = TURBOPACK_IMPORT.into(),
176-
id: Expr = module_id_to_lit(&id),
177-
),
178-
))
167+
168+
let mut result = vec![];
169+
170+
let merged_index = scope_hoisting_context.get_module_index(module);
171+
if let Some(merged_index) = merged_index {
172+
// Insert a placeholder to inline the merged module at the right place
173+
// relative to the other references (so to keep reference order).
174+
result.push(CodeGenerationHoistedStmt::new(
175+
format!("hoisted {merged_index}").into(),
176+
quote!(
177+
"__turbopack_merged_esm__($id);" as Stmt,
178+
id: Expr = Lit::Num(merged_index.into()).into(),
179+
),
180+
));
181+
}
182+
183+
let needs_namespace = match part {
184+
ModulePart::Export(_) | ModulePart::RenamedExport { .. } | ModulePart::Evaluation => {
185+
false
186+
}
187+
ModulePart::RenamedNamespace { .. }
188+
| ModulePart::Internal(_)
189+
| ModulePart::Locals
190+
| ModulePart::Exports
191+
| ModulePart::Facade => true,
192+
};
193+
194+
if merged_index.is_some() && !needs_namespace {
195+
// No need to import, the module was already executed and is available in the same scope
196+
// hoisting group (unless it's a namespace import)
197+
} else {
198+
let ident = referenced_asset
199+
.get_ident(chunking_context, None, scope_hoisting_context)
200+
.await?
201+
.context("part module reference should have an ident")?
202+
.as_expr_individual(DUMMY_SP)
203+
.unwrap_left();
204+
let id = module.chunk_item_id(Vc::upcast(chunking_context)).await?;
205+
206+
result.push(CodeGenerationHoistedStmt::new(
207+
ident.sym.as_str().into(),
208+
quote!(
209+
"var $name = $turbopack_import($id);" as Stmt,
210+
name = ident,
211+
turbopack_import: Expr = TURBOPACK_IMPORT.into(),
212+
id: Expr = module_id_to_lit(&id),
213+
),
214+
));
215+
}
216+
217+
Ok(CodeGeneration::hoisted_stmts(result))
179218
}
180219
}

0 commit comments

Comments
 (0)