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