turbopack_ecmascript/side_effect_optimization/locals/
module.rs1use std::collections::BTreeMap;
2
3use anyhow::{Result, bail};
4use turbo_tasks::{ResolvedVc, Vc};
5use turbo_tasks_fs::glob::Glob;
6use turbopack_core::{
7 asset::{Asset, AssetContent},
8 chunk::{AsyncModuleInfo, ChunkableModule, ChunkingContext},
9 ident::AssetIdent,
10 module::Module,
11 module_graph::ModuleGraph,
12 reference::ModuleReferences,
13 resolve::ModulePart,
14};
15
16use super::chunk_item::EcmascriptModuleLocalsChunkItem;
17use crate::{
18 AnalyzeEcmascriptModuleResult, EcmascriptAnalyzable, EcmascriptModuleAsset,
19 EcmascriptModuleContent, EcmascriptModuleContentOptions,
20 chunk::{EcmascriptChunkPlaceable, EcmascriptExports},
21 references::{
22 async_module::OptionAsyncModule,
23 esm::{EsmExport, EsmExports},
24 },
25};
26
27#[turbo_tasks::value]
31pub struct EcmascriptModuleLocalsModule {
32 pub module: ResolvedVc<EcmascriptModuleAsset>,
33}
34
35#[turbo_tasks::value_impl]
36impl EcmascriptModuleLocalsModule {
37 #[turbo_tasks::function]
38 pub fn new(module: ResolvedVc<EcmascriptModuleAsset>) -> Vc<Self> {
39 EcmascriptModuleLocalsModule { module }.cell()
40 }
41}
42
43#[turbo_tasks::value_impl]
44impl Module for EcmascriptModuleLocalsModule {
45 #[turbo_tasks::function]
46 fn ident(&self) -> Vc<AssetIdent> {
47 let inner = self.module.ident();
48
49 inner.with_part(ModulePart::locals())
50 }
51
52 #[turbo_tasks::function]
53 async fn references(&self) -> Result<Vc<ModuleReferences>> {
54 let result = self.module.analyze();
55 Ok(result.local_references())
56 }
57
58 #[turbo_tasks::function]
59 async fn is_self_async(self: Vc<Self>) -> Result<Vc<bool>> {
60 let analyze = self.await?.module.analyze().await?;
61 if let Some(async_module) = *analyze.async_module.await? {
62 let is_self_async = async_module.is_self_async(self.references());
63 Ok(is_self_async)
64 } else {
65 Ok(Vc::cell(false))
66 }
67 }
68}
69
70#[turbo_tasks::value_impl]
71impl Asset for EcmascriptModuleLocalsModule {
72 #[turbo_tasks::function]
73 fn content(&self) -> Vc<AssetContent> {
74 self.module.content()
75 }
76}
77
78#[turbo_tasks::value_impl]
79impl EcmascriptAnalyzable for EcmascriptModuleLocalsModule {
80 #[turbo_tasks::function]
81 fn analyze(&self) -> Vc<AnalyzeEcmascriptModuleResult> {
82 self.module.analyze()
83 }
84
85 #[turbo_tasks::function]
86 fn module_content_without_analysis(
87 &self,
88 generate_source_map: bool,
89 ) -> Vc<EcmascriptModuleContent> {
90 self.module
91 .module_content_without_analysis(generate_source_map)
92 }
93
94 #[turbo_tasks::function]
95 async fn module_content_options(
96 self: Vc<Self>,
97 module_graph: ResolvedVc<ModuleGraph>,
98 chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
99 async_module_info: Option<ResolvedVc<AsyncModuleInfo>>,
100 ) -> Result<Vc<EcmascriptModuleContentOptions>> {
101 let exports = self.get_exports().to_resolved().await?;
102 let original_module = self.await?.module;
103 let parsed = original_module.parse().to_resolved().await?;
104
105 let analyze = original_module.analyze();
106 let analyze_result = analyze.await?;
107
108 let module_type_result = *original_module.determine_module_type().await?;
109 let generate_source_map = *chunking_context
110 .reference_module_source_maps(Vc::upcast(self))
111 .await?;
112
113 Ok(EcmascriptModuleContentOptions {
114 parsed,
115 ident: self.ident().to_resolved().await?,
116 specified_module_type: module_type_result.module_type,
117 module_graph,
118 chunking_context,
119 references: analyze.local_references().to_resolved().await?,
120 esm_references: analyze_result.esm_local_references,
121 part_references: vec![],
122 code_generation: analyze_result.code_generation,
123 async_module: analyze_result.async_module,
124 generate_source_map,
125 original_source_map: analyze_result.source_map,
126 exports,
127 async_module_info,
128 }
129 .cell())
130 }
131}
132
133#[turbo_tasks::value_impl]
134impl EcmascriptChunkPlaceable for EcmascriptModuleLocalsModule {
135 #[turbo_tasks::function]
136 async fn get_exports(&self) -> Result<Vc<EcmascriptExports>> {
137 let EcmascriptExports::EsmExports(exports) = *self.module.get_exports().await? else {
138 bail!("EcmascriptModuleLocalsModule must only be used on modules with EsmExports");
139 };
140 let esm_exports = exports.await?;
141 let mut exports = BTreeMap::new();
142
143 for (name, export) in &esm_exports.exports {
144 match export {
145 EsmExport::ImportedBinding(..) | EsmExport::ImportedNamespace(..) => {
146 }
148 EsmExport::LocalBinding(local_name, mutable) => {
149 exports.insert(
150 name.clone(),
151 EsmExport::LocalBinding(local_name.clone(), *mutable),
152 );
153 }
154 EsmExport::Error => {
155 exports.insert(name.clone(), EsmExport::Error);
156 }
157 }
158 }
159
160 let exports = EsmExports {
161 exports,
162 star_exports: vec![],
163 }
164 .resolved_cell();
165 Ok(EcmascriptExports::EsmExports(exports).cell())
166 }
167
168 #[turbo_tasks::function]
169 fn is_marked_as_side_effect_free(&self, side_effect_free_packages: Vc<Glob>) -> Vc<bool> {
170 self.module
171 .is_marked_as_side_effect_free(side_effect_free_packages)
172 }
173
174 #[turbo_tasks::function]
175 fn get_async_module(&self) -> Vc<OptionAsyncModule> {
176 self.module.get_async_module()
177 }
178}
179
180#[turbo_tasks::value_impl]
181impl ChunkableModule for EcmascriptModuleLocalsModule {
182 #[turbo_tasks::function]
183 fn as_chunk_item(
184 self: ResolvedVc<Self>,
185 module_graph: ResolvedVc<ModuleGraph>,
186 chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
187 ) -> Vc<Box<dyn turbopack_core::chunk::ChunkItem>> {
188 Vc::upcast(
189 EcmascriptModuleLocalsChunkItem {
190 module: self,
191 module_graph,
192 chunking_context,
193 }
194 .cell(),
195 )
196 }
197}