Skip to content

Commit 428616e

Browse files
authored
Turbopack: refactor side effects optimization (#82466)
### What? Refactors the side effects optimization. * Gets rid of the `<module evaluation>` and the `<exports>` module. * Only two modules: `<local>` and the facade. * The local module has all the evaluation side effects and local exports. * The facade reexports the local module and all reexports of the module. * `require()` and `import *` will resolve to the facade module * `import "..."` will resolve to the locals * `import { x } from "..."` will follow reexports and finally imports from a locals module
1 parent 8f8c78e commit 428616e

File tree

15 files changed

+93
-197
lines changed

15 files changed

+93
-197
lines changed

test/e2e/app-dir/cache-components-errors/cache-components-errors.test.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2430,7 +2430,7 @@ describe('Cache Components Errors', () => {
24302430
| ^",
24312431
"stack": [
24322432
"{module evaluation} app/use-cache-private-in-unstable-cache/page.tsx (21:38)",
2433-
"<FIXME-file-protocol>",
2433+
"{module evaluation} .next-internal/server/app/use-cache-private-in-unstable-cache/page/actions.js (server actions loader) (1:1)",
24342434
"<FIXME-file-protocol>",
24352435
"<FIXME-next-dist-dir>",
24362436
],
@@ -2487,8 +2487,8 @@ describe('Cache Components Errors', () => {
24872487
expect(output).toMatchInlineSnapshot(`
24882488
"Error: "use cache: private" must not be used within \`unstable_cache()\`.
24892489
at __TURBOPACK__module__evaluation__ (bundler:///app/use-cache-private-in-unstable-cache/page.tsx:21:38)
2490+
at __TURBOPACK__module__evaluation__ (bundler:///.next-internal/server/app/use-cache-private-in-unstable-cache/page/actions.js (server actions loader):1:1)
24902491
at a (<next-dist-dir>)
2491-
at b (<next-dist-dir>)
24922492
19 | }
24932493
20 |
24942494
> 21 | const getCachedData = unstable_cache(async () => {
@@ -2506,6 +2506,7 @@ describe('Cache Components Errors', () => {
25062506
expect(output).toMatchInlineSnapshot(`
25072507
"Error: "use cache: private" must not be used within \`unstable_cache()\`.
25082508
at __TURBOPACK__module__evaluation__ (bundler:///app/use-cache-private-in-unstable-cache/page.tsx:21:38)
2509+
at __TURBOPACK__module__evaluation__ (bundler:///.next-internal/server/app/use-cache-private-in-unstable-cache/page/actions.js%20(server%20actions%20loader):1:1)
25092510
at a (<next-dist-dir>)
25102511
19 | }
25112512
20 |
@@ -2574,7 +2575,7 @@ describe('Cache Components Errors', () => {
25742575
| ^",
25752576
"stack": [
25762577
"{module evaluation} app/use-cache-private-in-use-cache/page.tsx (15:1)",
2577-
"<FIXME-file-protocol>",
2578+
"{module evaluation} .next-internal/server/app/use-cache-private-in-use-cache/page/actions.js (server actions loader) (1:1)",
25782579
"<FIXME-file-protocol>",
25792580
"<FIXME-next-dist-dir>",
25802581
],
@@ -2632,8 +2633,8 @@ describe('Cache Components Errors', () => {
26322633
expect(output).toMatchInlineSnapshot(`
26332634
"Error: "use cache: private" must not be used within "use cache". It can only be nested inside of another "use cache: private".
26342635
at __TURBOPACK__module__evaluation__ (bundler:///app/use-cache-private-in-use-cache/page.tsx:15:1)
2636+
at __TURBOPACK__module__evaluation__ (bundler:///.next-internal/server/app/use-cache-private-in-use-cache/page/actions.js (server actions loader):1:1)
26352637
at a (<next-dist-dir>)
2636-
at b (<next-dist-dir>)
26372638
13 | }
26382639
14 |
26392640
> 15 | async function Private() {
@@ -2643,8 +2644,8 @@ describe('Cache Components Errors', () => {
26432644
18 | return <p>Private</p>
26442645
Error: "use cache: private" must not be used within "use cache". It can only be nested inside of another "use cache: private".
26452646
at __TURBOPACK__module__evaluation__ (bundler:///app/use-cache-private-in-use-cache/page.tsx:15:1)
2646-
at c (<next-dist-dir>)
2647-
at d (<next-dist-dir>)
2647+
at __TURBOPACK__module__evaluation__ (bundler:///.next-internal/server/app/use-cache-private-in-use-cache/page/actions.js (server actions loader):1:1)
2648+
at b (<next-dist-dir>)
26482649
13 | }
26492650
14 |
26502651
> 15 | async function Private() {
@@ -2662,7 +2663,7 @@ describe('Cache Components Errors', () => {
26622663
expect(output).toMatchInlineSnapshot(`
26632664
"Error: "use cache: private" must not be used within "use cache". It can only be nested inside of another "use cache: private".
26642665
at __TURBOPACK__module__evaluation__ (bundler:///app/use-cache-private-in-use-cache/page.tsx:15:1)
2665-
at __TURBOPACK__module__evaluation__ (bundler:///app/use-cache-private-in-use-cache/page.tsx:15:16)
2666+
at __TURBOPACK__module__evaluation__ (bundler:///.next-internal/server/app/use-cache-private-in-use-cache/page/actions.js%20(server%20actions%20loader):1:1)
26662667
at a (<next-dist-dir>)
26672668
13 | }
26682669
14 |
@@ -2673,7 +2674,7 @@ describe('Cache Components Errors', () => {
26732674
18 | return <p>Private</p>
26742675
Error: "use cache: private" must not be used within "use cache". It can only be nested inside of another "use cache: private".
26752676
at __TURBOPACK__module__evaluation__ (bundler:///app/use-cache-private-in-use-cache/page.tsx:15:1)
2676-
at __TURBOPACK__module__evaluation__ (bundler:///app/use-cache-private-in-use-cache/page.tsx:15:16)
2677+
at __TURBOPACK__module__evaluation__ (bundler:///.next-internal/server/app/use-cache-private-in-use-cache/page/actions.js%20(server%20actions%20loader):1:1)
26772678
at b (<next-dist-dir>)
26782679
13 | }
26792680
14 |

turbopack/crates/turbopack-ecmascript/src/chunk/placeable.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ pub enum EcmascriptExports {
230230
#[turbo_tasks::value_impl]
231231
impl EcmascriptExports {
232232
#[turbo_tasks::function]
233-
pub async fn needs_facade(&self) -> Result<Vc<bool>> {
233+
pub async fn split_locals_and_reexports(&self) -> Result<Vc<bool>> {
234234
Ok(match self {
235235
EcmascriptExports::EsmExports(exports) => {
236236
let exports = exports.await?;

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

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -850,8 +850,8 @@ pub struct EcmascriptModuleContentOptions {
850850
specified_module_type: SpecifiedModuleType,
851851
chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
852852
references: ResolvedVc<ModuleReferences>,
853-
esm_references: ResolvedVc<EsmAssetReferences>,
854853
part_references: Vec<ResolvedVc<EcmascriptModulePartReference>>,
854+
esm_references: ResolvedVc<EsmAssetReferences>,
855855
code_generation: ResolvedVc<CodeGens>,
856856
async_module: ResolvedVc<OptionAsyncModule>,
857857
generate_source_map: bool,
@@ -872,8 +872,8 @@ impl EcmascriptModuleContentOptions {
872872
module,
873873
chunking_context,
874874
references,
875-
esm_references,
876875
part_references,
876+
esm_references,
877877
code_generation,
878878
async_module,
879879
exports,
@@ -912,14 +912,14 @@ impl EcmascriptModuleContentOptions {
912912
},
913913
];
914914

915-
let esm_code_gens = esm_references
916-
.await?
915+
let part_code_gens = part_references
917916
.iter()
918917
.map(|r| r.code_generation(**chunking_context, scope_hoisting_context))
919918
.try_join()
920919
.await?;
921920

922-
let part_code_gens = part_references
921+
let esm_code_gens = esm_references
922+
.await?
923923
.iter()
924924
.map(|r| r.code_generation(**chunking_context, scope_hoisting_context))
925925
.try_join()
@@ -933,9 +933,9 @@ impl EcmascriptModuleContentOptions {
933933
.await?;
934934

935935
anyhow::Ok(
936-
esm_code_gens
936+
part_code_gens
937937
.into_iter()
938-
.chain(part_code_gens.into_iter())
938+
.chain(esm_code_gens.into_iter())
939939
.chain(additional_code_gens.into_iter().flatten())
940940
.chain(code_gens.into_iter())
941941
.collect(),

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

Lines changed: 20 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -141,17 +141,8 @@ pub async fn follow_reexports(
141141
side_effect_free_packages: Vc<Glob>,
142142
ignore_side_effect_of_entry: bool,
143143
) -> Result<Vc<FollowExportsResult>> {
144-
if !ignore_side_effect_of_entry
145-
&& !*module
146-
.is_marked_as_side_effect_free(side_effect_free_packages)
147-
.await?
148-
{
149-
return Ok(FollowExportsResult::cell(FollowExportsResult {
150-
module,
151-
export_name: Some(export_name),
152-
ty: FoundExportType::SideEffects,
153-
}));
154-
}
144+
let mut ignore_side_effects = ignore_side_effect_of_entry;
145+
155146
let mut module = module;
156147
let mut export_name = export_name;
157148
loop {
@@ -164,12 +155,26 @@ pub async fn follow_reexports(
164155
}));
165156
};
166157

158+
if !ignore_side_effects
159+
&& !*module
160+
.is_marked_as_side_effect_free(side_effect_free_packages)
161+
.await?
162+
{
163+
// TODO It's unfortunate that we have to use the whole module here.
164+
// This is often the Facade module, which includes all reexports.
165+
// Often we could use Locals + the followed reexports instead.
166+
return Ok(FollowExportsResult::cell(FollowExportsResult {
167+
module,
168+
export_name: Some(export_name),
169+
ty: FoundExportType::SideEffects,
170+
}));
171+
}
172+
ignore_side_effects = false;
173+
167174
// Try to find the export in the local exports
168175
let exports_ref = exports.await?;
169176
if let Some(export) = exports_ref.exports.get(&export_name) {
170-
match handle_declared_export(module, export_name, export, side_effect_free_packages)
171-
.await?
172-
{
177+
match handle_declared_export(module, export_name, export).await? {
173178
ControlFlow::Continue((m, n)) => {
174179
module = m.to_resolved().await?;
175180
export_name = n;
@@ -222,23 +227,12 @@ async fn handle_declared_export(
222227
module: ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>,
223228
export_name: RcStr,
224229
export: &EsmExport,
225-
side_effect_free_packages: Vc<Glob>,
226230
) -> Result<ControlFlow<FollowExportsResult, (Vc<Box<dyn EcmascriptChunkPlaceable>>, RcStr)>> {
227231
match export {
228232
EsmExport::ImportedBinding(reference, name, _) => {
229233
if let ReferencedAsset::Some(module) =
230234
*ReferencedAsset::from_resolve_result(reference.resolve_reference()).await?
231235
{
232-
if !*module
233-
.is_marked_as_side_effect_free(side_effect_free_packages)
234-
.await?
235-
{
236-
return Ok(ControlFlow::Break(FollowExportsResult {
237-
module,
238-
export_name: Some(name.clone()),
239-
ty: FoundExportType::SideEffects,
240-
}));
241-
}
242236
return Ok(ControlFlow::Continue((*module, name.clone())));
243237
}
244238
}
@@ -286,6 +280,7 @@ async fn find_export_from_reexports(
286280
module: ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>,
287281
export_name: RcStr,
288282
) -> Result<Vc<FindExportFromReexportsResult>> {
283+
// TODO why do we need a special case for this?
289284
if let Some(module) =
290285
Vc::try_resolve_downcast_type::<EcmascriptModulePartAsset>(*module).await?
291286
&& matches!(module.await?.part, ModulePart::Exports)

turbopack/crates/turbopack-ecmascript/src/references/mod.rs

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,6 @@ pub struct AnalyzeEcmascriptModuleResult {
171171
pub esm_references: ResolvedVc<EsmAssetReferences>,
172172
pub esm_local_references: ResolvedVc<EsmAssetReferences>,
173173
pub esm_reexport_references: ResolvedVc<EsmAssetReferences>,
174-
pub esm_evaluation_references: ResolvedVc<EsmAssetReferences>,
175174

176175
pub code_generation: ResolvedVc<CodeGens>,
177176
pub exports: ResolvedVc<EcmascriptExports>,
@@ -217,7 +216,6 @@ pub struct AnalyzeEcmascriptModuleResultBuilder {
217216
esm_references: FxHashSet<usize>,
218217
esm_local_references: FxHashSet<usize>,
219218
esm_reexport_references: FxHashSet<usize>,
220-
esm_evaluation_references: FxHashSet<usize>,
221219

222220
esm_references_free_var: FxIndexMap<RcStr, ResolvedVc<EsmAssetReference>>,
223221
// Ad-hoc created import references that are resolved `import * as x from ...; x.foo` accesses
@@ -239,7 +237,6 @@ impl AnalyzeEcmascriptModuleResultBuilder {
239237
esm_references: Default::default(),
240238
esm_local_references: Default::default(),
241239
esm_reexport_references: Default::default(),
242-
esm_evaluation_references: Default::default(),
243240
esm_references_rewritten: Default::default(),
244241
esm_references_free_var: Default::default(),
245242
code_gens: Default::default(),
@@ -282,7 +279,6 @@ impl AnalyzeEcmascriptModuleResultBuilder {
282279
pub fn add_esm_evaluation_reference(&mut self, idx: usize) {
283280
self.esm_references.insert(idx);
284281
self.esm_local_references.insert(idx);
285-
self.esm_evaluation_references.insert(idx);
286282
}
287283

288284
/// Adds a codegen to the analysis result.
@@ -369,8 +365,6 @@ impl AnalyzeEcmascriptModuleResultBuilder {
369365
});
370366
let mut esm_reexport_references = track_reexport_references
371367
.then(|| Vec::with_capacity(self.esm_reexport_references.len()));
372-
let mut esm_evaluation_references = track_reexport_references
373-
.then(|| Vec::with_capacity(self.esm_evaluation_references.len()));
374368
for (i, reference) in import_references.iter().enumerate() {
375369
if self.esm_references.contains(&i) {
376370
esm_references.push(*reference);
@@ -392,11 +386,6 @@ impl AnalyzeEcmascriptModuleResultBuilder {
392386
.flat_map(|m| m.values().copied()),
393387
);
394388
}
395-
if let Some(esm_evaluation_references) = &mut esm_evaluation_references
396-
&& self.esm_evaluation_references.contains(&i)
397-
{
398-
esm_evaluation_references.push(*reference);
399-
}
400389
if let Some(esm_reexport_references) = &mut esm_reexport_references
401390
&& self.esm_reexport_references.contains(&i)
402391
{
@@ -415,9 +404,6 @@ impl AnalyzeEcmascriptModuleResultBuilder {
415404
esm_reexport_references: ResolvedVc::cell(
416405
esm_reexport_references.unwrap_or_default(),
417406
),
418-
esm_evaluation_references: ResolvedVc::cell(
419-
esm_evaluation_references.unwrap_or_default(),
420-
),
421407
code_generation: ResolvedVc::cell(self.code_gens),
422408
exports: self.exports.resolved_cell(),
423409
async_module: self.async_module,

0 commit comments

Comments
 (0)