turbopack_ecmascript/side_effect_optimization/locals/
module.rs1use anyhow::{Result, bail};
2use turbo_frozenmap::FrozenMap;
3use turbo_tasks::{ResolvedVc, Vc};
4use turbopack_core::{
5 chunk::{
6 AsyncModuleInfo, ChunkableModule, ChunkingContext, MergeableModule, MergeableModules,
7 MergeableModulesExposed,
8 },
9 ident::AssetIdent,
10 module::{Module, ModuleSideEffects},
11 module_graph::ModuleGraph,
12 reference::ModuleReferences,
13 resolve::ModulePart,
14 source::OptionSource,
15};
16
17use crate::{
18 AnalyzeEcmascriptModuleResult, EcmascriptAnalyzable, EcmascriptAnalyzableExt,
19 EcmascriptModuleAsset, EcmascriptModuleContent, EcmascriptModuleContentOptions,
20 EcmascriptParsable, EnvVarInfo, MergedEcmascriptModule,
21 chunk::{
22 EcmascriptChunkItemContent, EcmascriptChunkPlaceable, EcmascriptExports,
23 ecmascript_chunk_item,
24 },
25 parse::ParseResult,
26 references::{
27 async_module::OptionAsyncModule,
28 esm::{EsmExport, EsmExports},
29 },
30};
31
32#[turbo_tasks::value]
38pub struct EcmascriptModuleLocalsModule {
39 pub module: ResolvedVc<EcmascriptModuleAsset>,
40}
41
42#[turbo_tasks::value_impl]
43impl EcmascriptModuleLocalsModule {
44 #[turbo_tasks::function]
45 pub fn new(module: ResolvedVc<EcmascriptModuleAsset>) -> Vc<Self> {
46 EcmascriptModuleLocalsModule { module }.cell()
47 }
48}
49
50#[turbo_tasks::value_impl]
51impl Module for EcmascriptModuleLocalsModule {
52 #[turbo_tasks::function]
53 async fn ident(&self) -> Result<Vc<AssetIdent>> {
54 Ok(self
55 .module
56 .ident()
57 .owned()
58 .await?
59 .with_part(ModulePart::locals())
60 .into_vc())
61 }
62
63 #[turbo_tasks::function]
64 fn source(&self) -> Vc<OptionSource> {
65 ResolvedVc::upcast::<Box<dyn Module>>(self.module).source()
66 }
67
68 #[turbo_tasks::function]
69 fn references(&self) -> Result<Vc<ModuleReferences>> {
70 let result = self.module.analyze();
71 Ok(result.local_references())
72 }
73
74 #[turbo_tasks::function]
75 async fn is_self_async(self: Vc<Self>) -> Result<Vc<bool>> {
76 let analyze = self.await?.module.analyze().await?;
77 if let Some(async_module) = *analyze.async_module.await? {
78 let is_self_async = async_module.is_self_async(self.references());
79 Ok(is_self_async)
80 } else {
81 Ok(Vc::cell(false))
82 }
83 }
84
85 #[turbo_tasks::function]
86 fn side_effects(&self) -> Vc<ModuleSideEffects> {
87 self.module.side_effects()
88 }
89}
90
91#[turbo_tasks::value_impl]
92impl EcmascriptParsable for EcmascriptModuleLocalsModule {
93 #[turbo_tasks::function]
94 fn failsafe_parse(&self) -> Vc<ParseResult> {
95 self.module.failsafe_parse()
96 }
97}
98
99#[turbo_tasks::value_impl]
100impl EcmascriptAnalyzable for EcmascriptModuleLocalsModule {
101 #[turbo_tasks::function]
102 fn analyze(&self) -> Vc<AnalyzeEcmascriptModuleResult> {
103 self.module.analyze()
104 }
105
106 #[turbo_tasks::function]
107 fn env_var_info(&self) -> Vc<EnvVarInfo> {
108 self.module.env_var_info()
109 }
110
111 #[turbo_tasks::function]
112 fn module_content_without_analysis(
113 &self,
114 generate_source_map: bool,
115 ) -> Vc<EcmascriptModuleContent> {
116 self.module
117 .module_content_without_analysis(generate_source_map)
118 }
119
120 #[turbo_tasks::function]
121 async fn module_content_options(
122 self: ResolvedVc<Self>,
123 chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
124 async_module_info: Option<ResolvedVc<AsyncModuleInfo>>,
125 ) -> Result<Vc<EcmascriptModuleContentOptions>> {
126 let exports = self.get_exports().to_resolved().await?;
127 let original_module = self.await?.module;
128 let parsed = original_module.await?.parse().await?.to_resolved().await?;
129
130 let analyze = original_module.analyze();
131 let analyze_result = analyze.await?;
132
133 let module_type_result = original_module.determine_module_type().await?;
134 let generate_source_map = *chunking_context
135 .reference_module_source_maps(Vc::upcast(*self))
136 .await?;
137
138 Ok(EcmascriptModuleContentOptions {
139 parsed: Some(parsed),
140 module: ResolvedVc::upcast(self),
141 specified_module_type: module_type_result.module_type,
142 chunking_context,
143 references: analyze.local_references().to_resolved().await?,
144 esm_references: analyze_result.esm_local_references,
145 part_references: vec![],
146 code_generation: analyze_result.code_generation,
147 async_module: analyze_result.async_module,
148 generate_source_map,
149 original_source_map: analyze_result.source_map,
150 exports,
151 export_registration_mode: None,
152 async_module_info,
153 }
154 .cell())
155 }
156}
157
158#[turbo_tasks::value_impl]
159impl EcmascriptChunkPlaceable for EcmascriptModuleLocalsModule {
160 #[turbo_tasks::function]
161 async fn get_exports(&self) -> Result<Vc<EcmascriptExports>> {
162 let EcmascriptExports::EsmExports(exports) = *self.module.get_exports().await? else {
163 bail!("EcmascriptModuleLocalsModule must only be used on modules with EsmExports");
164 };
165 let esm_exports = exports.await?;
166 let mut exports = Vec::new();
167
168 for (name, export) in &esm_exports.exports {
169 match export {
170 EsmExport::ImportedBinding(..) | EsmExport::ImportedNamespace(..) => {
171 }
173 EsmExport::LocalBinding(local_name, liveness) => {
174 exports.push((
175 name.clone(),
176 EsmExport::LocalBinding(local_name.clone(), *liveness),
177 ));
178 }
179 EsmExport::Error => {
180 exports.push((name.clone(), EsmExport::Error));
181 }
182 }
183 }
184
185 let exports = EsmExports {
186 exports: FrozenMap::from_unique_sorted_box(exports.into_boxed_slice()),
187 star_exports: vec![],
188 mangle_export_names: esm_exports.mangle_export_names,
189 }
190 .resolved_cell();
191 Ok(EcmascriptExports::EsmExports(exports).cell())
192 }
193
194 #[turbo_tasks::function]
195 fn get_async_module(&self) -> Vc<OptionAsyncModule> {
196 self.module.get_async_module()
197 }
198
199 #[turbo_tasks::function]
200 async fn chunk_item_content(
201 self: Vc<Self>,
202 chunking_context: Vc<Box<dyn ChunkingContext>>,
203 _module_graph: Vc<ModuleGraph>,
204 async_module_info: Option<Vc<AsyncModuleInfo>>,
205 _estimated: bool,
206 ) -> Result<Vc<EcmascriptChunkItemContent>> {
207 let analyze = self.await?.module.analyze().await?;
208 let async_module_options = analyze.async_module.module_options(async_module_info);
209
210 let content = self.module_content(chunking_context, async_module_info);
211
212 Ok(EcmascriptChunkItemContent::new(
213 content,
214 chunking_context,
215 async_module_options,
216 ))
217 }
218}
219
220#[turbo_tasks::value_impl]
221impl ChunkableModule for EcmascriptModuleLocalsModule {
222 #[turbo_tasks::function]
223 fn as_chunk_item(
224 self: ResolvedVc<Self>,
225 module_graph: ResolvedVc<ModuleGraph>,
226 chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
227 ) -> Vc<Box<dyn turbopack_core::chunk::ChunkItem>> {
228 ecmascript_chunk_item(ResolvedVc::upcast(self), module_graph, chunking_context)
229 }
230}
231
232#[turbo_tasks::value_impl]
233impl MergeableModule for EcmascriptModuleLocalsModule {
234 #[turbo_tasks::function]
237 fn is_mergeable(&self) -> Vc<bool> {
238 self.module.is_mergeable()
239 }
240
241 #[turbo_tasks::function]
242 async fn merge(
243 &self,
244 modules: Vc<MergeableModulesExposed>,
245 entry_points: Vc<MergeableModules>,
246 ) -> Result<Vc<Box<dyn ChunkableModule>>> {
247 Ok(Vc::upcast(
248 *MergedEcmascriptModule::new(modules, entry_points, self.module.await?.options).await?,
249 ))
250 }
251}