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