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 async_module_info,
152 }
153 .cell())
154 }
155}
156
157#[turbo_tasks::value_impl]
158impl EcmascriptChunkPlaceable for EcmascriptModuleLocalsModule {
159 #[turbo_tasks::function]
160 async fn get_exports(&self) -> Result<Vc<EcmascriptExports>> {
161 let EcmascriptExports::EsmExports(exports) = *self.module.get_exports().await? else {
162 bail!("EcmascriptModuleLocalsModule must only be used on modules with EsmExports");
163 };
164 let esm_exports = exports.await?;
165 let mut exports = Vec::new();
166
167 for (name, export) in &esm_exports.exports {
168 match export {
169 EsmExport::ImportedBinding(..) | EsmExport::ImportedNamespace(..) => {
170 }
172 EsmExport::LocalBinding(local_name, liveness) => {
173 exports.push((
174 name.clone(),
175 EsmExport::LocalBinding(local_name.clone(), *liveness),
176 ));
177 }
178 EsmExport::Error => {
179 exports.push((name.clone(), EsmExport::Error));
180 }
181 }
182 }
183
184 let exports = EsmExports {
185 exports: FrozenMap::from_unique_sorted_box(exports.into_boxed_slice()),
186 star_exports: vec![],
187 mangle_export_names: esm_exports.mangle_export_names,
188 }
189 .resolved_cell();
190 Ok(EcmascriptExports::EsmExports(exports).cell())
191 }
192
193 #[turbo_tasks::function]
194 fn get_async_module(&self) -> Vc<OptionAsyncModule> {
195 self.module.get_async_module()
196 }
197
198 #[turbo_tasks::function]
199 async fn chunk_item_content(
200 self: Vc<Self>,
201 chunking_context: Vc<Box<dyn ChunkingContext>>,
202 _module_graph: Vc<ModuleGraph>,
203 async_module_info: Option<Vc<AsyncModuleInfo>>,
204 _estimated: bool,
205 ) -> Result<Vc<EcmascriptChunkItemContent>> {
206 let analyze = self.await?.module.analyze().await?;
207 let async_module_options = analyze.async_module.module_options(async_module_info);
208
209 let content = self.module_content(chunking_context, async_module_info);
210
211 Ok(EcmascriptChunkItemContent::new(
212 content,
213 chunking_context,
214 async_module_options,
215 ))
216 }
217}
218
219#[turbo_tasks::value_impl]
220impl ChunkableModule for EcmascriptModuleLocalsModule {
221 #[turbo_tasks::function]
222 fn as_chunk_item(
223 self: ResolvedVc<Self>,
224 module_graph: ResolvedVc<ModuleGraph>,
225 chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
226 ) -> Vc<Box<dyn turbopack_core::chunk::ChunkItem>> {
227 ecmascript_chunk_item(ResolvedVc::upcast(self), module_graph, chunking_context)
228 }
229}
230
231#[turbo_tasks::value_impl]
232impl MergeableModule for EcmascriptModuleLocalsModule {
233 #[turbo_tasks::function]
234 async fn merge(
235 &self,
236 modules: Vc<MergeableModulesExposed>,
237 entry_points: Vc<MergeableModules>,
238 ) -> Result<Vc<Box<dyn ChunkableModule>>> {
239 Ok(Vc::upcast(
240 *MergedEcmascriptModule::new(modules, entry_points, self.module.await?.options).await?,
241 ))
242 }
243}