turbopack_ecmascript/module_fragments/side_effects/
module.rs1use anyhow::Result;
2use turbo_rcstr::{RcStr, rcstr};
3use turbo_tasks::{ResolvedVc, TryJoinIterExt, Vc};
4use turbo_tasks_fs::rope::RopeBuilder;
5use turbopack_core::{
6 chunk::{
7 AsyncModuleInfo, ChunkableModule, ChunkingContext, EvaluatableAsset, ModuleChunkItemIdExt,
8 },
9 ident::AssetIdent,
10 module::{Module, ModuleSideEffects},
11 module_graph::ModuleGraph,
12 reference::{ModuleReferences, SingleChunkableModuleReference},
13 resolve::{ExportUsage, ModulePart},
14};
15
16use crate::{
17 EcmascriptModuleAsset,
18 chunk::{
19 EcmascriptChunkItemContent, EcmascriptChunkItemOptions, EcmascriptChunkPlaceable,
20 EcmascriptExports, ecmascript_chunk_item, item::RewriteSourcePath,
21 },
22 references::async_module::AsyncModuleOptions,
23 runtime_functions::{TURBOPACK_EXPORT_NAMESPACE, TURBOPACK_IMPORT},
24 utils::StringifyModuleId,
25};
26
27#[turbo_tasks::value]
28pub struct SideEffectsModule {
29 pub module: ResolvedVc<EcmascriptModuleAsset>,
31 pub part: ModulePart,
33 pub resolved_as: ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>,
35 pub side_effects: Vec<ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>>,
37}
38
39#[turbo_tasks::value_impl]
40impl SideEffectsModule {
41 #[turbo_tasks::function]
42 pub fn new(
43 module: ResolvedVc<EcmascriptModuleAsset>,
44 part: ModulePart,
45 resolved_as: ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>,
46 side_effects: Vec<ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>>,
47 ) -> Vc<Self> {
48 SideEffectsModule {
49 module,
50 part,
51 resolved_as,
52 side_effects,
53 }
54 .cell()
55 }
56}
57
58fn side_effect_reference(
59 side_effect: ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>,
60) -> Vc<SingleChunkableModuleReference> {
61 SingleChunkableModuleReference::new(
62 *ResolvedVc::upcast(side_effect),
63 rcstr!("side effect"),
64 ExportUsage::evaluation(),
65 )
66}
67
68#[turbo_tasks::value_impl]
69impl Module for SideEffectsModule {
70 #[turbo_tasks::function]
71 async fn ident(&self) -> Result<Vc<AssetIdent>> {
72 let mut ident = self
73 .module
74 .ident()
75 .owned()
76 .await?
77 .with_part(self.part.clone())
78 .with_asset(
79 rcstr!("resolved"),
80 self.resolved_as.ident().to_resolved().await?,
81 )
82 .with_modifier(rcstr!("side effects"));
83
84 for (i, side_effect) in self.side_effects.iter().enumerate() {
85 ident = ident.with_asset(
86 RcStr::from(format!("side effect {i}")),
87 side_effect.ident().to_resolved().await?,
88 );
89 }
90
91 Ok(ident.into_vc())
92 }
93
94 #[turbo_tasks::function]
95 fn source(&self) -> Vc<turbopack_core::source::OptionSource> {
96 Vc::cell(None)
97 }
98
99 #[turbo_tasks::function]
100 async fn references(&self) -> Result<Vc<ModuleReferences>> {
101 let mut references = vec![];
102
103 references.extend(
104 self.side_effects
105 .iter()
106 .map(async |side_effect| {
107 Ok(ResolvedVc::upcast(
108 side_effect_reference(*side_effect).to_resolved().await?,
109 ))
110 })
111 .try_join()
112 .await?,
113 );
114
115 references.push(ResolvedVc::upcast(
116 SingleChunkableModuleReference::new(
117 *ResolvedVc::upcast(self.resolved_as),
118 rcstr!("resolved as"),
119 ExportUsage::all(),
120 )
121 .to_resolved()
122 .await?,
123 ));
124
125 Ok(Vc::cell(references))
126 }
127
128 #[turbo_tasks::function]
129 fn side_effects(self: Vc<Self>) -> Vc<ModuleSideEffects> {
130 ModuleSideEffects::ModuleEvaluationIsSideEffectFree.cell()
134 }
135}
136
137#[turbo_tasks::value_impl]
138impl EcmascriptChunkPlaceable for SideEffectsModule {
139 #[turbo_tasks::function]
140 fn get_exports(&self) -> Vc<EcmascriptExports> {
141 self.resolved_as.get_exports().borrowed()
143 }
144
145 #[turbo_tasks::function]
146 async fn chunk_item_content(
147 self: Vc<Self>,
148 chunking_context: Vc<Box<dyn ChunkingContext>>,
149 _module_graph: Vc<ModuleGraph>,
150 _async_module_info: Option<Vc<AsyncModuleInfo>>,
151 _estimated: bool,
152 ) -> Result<Vc<EcmascriptChunkItemContent>> {
153 let module = self.await?;
154 let mut code = RopeBuilder::default();
155 let mut has_top_level_await = false;
156
157 let unused_references = chunking_context.unused_references();
158
159 for &side_effect in module.side_effects.iter() {
160 let reference = side_effect_reference(side_effect).to_resolved().await?;
161 if unused_references
162 .contains_key(&ResolvedVc::upcast(reference))
163 .await?
164 {
165 continue;
166 }
167
168 let need_await = 'need_await: {
169 let async_module = *side_effect.get_async_module().await?;
170 if let Some(async_module) = async_module
171 && async_module.await?.has_top_level_await
172 {
173 break 'need_await true;
174 }
175 false
176 };
177
178 if !has_top_level_await && need_await {
179 has_top_level_await = true;
180 }
181
182 code.push_bytes(
183 format!(
184 "{}{TURBOPACK_IMPORT}({});\n",
185 if need_await { "await " } else { "" },
186 StringifyModuleId(&side_effect.chunk_item_id(chunking_context).await?)
187 )
188 .as_bytes(),
189 );
190 }
191
192 code.push_bytes(
193 format!(
194 "{TURBOPACK_EXPORT_NAMESPACE}({TURBOPACK_IMPORT}({}));\n",
195 StringifyModuleId(&module.resolved_as.chunk_item_id(chunking_context).await?)
196 )
197 .as_bytes(),
198 );
199
200 let code = code.build();
201
202 Ok(EcmascriptChunkItemContent {
203 inner_code: code,
204 source_map: None,
205 rewrite_source_path: RewriteSourcePath::None,
206 options: EcmascriptChunkItemOptions {
207 strict: true,
208 async_module: if has_top_level_await {
209 Some(AsyncModuleOptions {
210 has_top_level_await: true,
211 })
212 } else {
213 None
214 },
215 supports_arrow_functions: *chunking_context
216 .environment()
217 .runtime_versions()
218 .supports_arrow_functions()
219 .await?,
220 ..Default::default()
221 },
222 additional_ids: Default::default(),
223 placeholder_for_future_extensions: (),
224 }
225 .cell())
226 }
227}
228
229#[turbo_tasks::value_impl]
230impl ChunkableModule for SideEffectsModule {
231 #[turbo_tasks::function]
232 fn as_chunk_item(
233 self: ResolvedVc<Self>,
234 module_graph: ResolvedVc<ModuleGraph>,
235 chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
236 ) -> Vc<Box<dyn turbopack_core::chunk::ChunkItem>> {
237 ecmascript_chunk_item(ResolvedVc::upcast(self), module_graph, chunking_context)
238 }
239}
240
241#[turbo_tasks::value_impl]
242impl EvaluatableAsset for SideEffectsModule {}