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