turbopack_ecmascript/tree_shake/
side_effect_module.rs1use anyhow::Result;
2use turbo_rcstr::{RcStr, rcstr};
3use turbo_tasks::{ResolvedVc, TryJoinIterExt, Vc};
4use turbo_tasks_fs::glob::Glob;
5use turbopack_core::{
6 asset::{Asset, AssetContent},
7 chunk::{ChunkableModule, ChunkingContext, EvaluatableAsset},
8 ident::AssetIdent,
9 module::Module,
10 module_graph::ModuleGraph,
11 reference::{ModuleReferences, SingleChunkableModuleReference},
12 resolve::{ExportUsage, ModulePart},
13};
14
15use crate::{
16 EcmascriptModuleAsset,
17 chunk::{EcmascriptChunkPlaceable, EcmascriptExports},
18 tree_shake::chunk_item::SideEffectsModuleChunkItem,
19};
20
21#[turbo_tasks::value]
22pub(super) struct SideEffectsModule {
23 pub module: ResolvedVc<EcmascriptModuleAsset>,
25 pub part: ModulePart,
27 pub resolved_as: ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>,
29 pub side_effects: Vec<ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>>,
31}
32
33#[turbo_tasks::value_impl]
34impl SideEffectsModule {
35 #[turbo_tasks::function]
36 pub fn new(
37 module: ResolvedVc<EcmascriptModuleAsset>,
38 part: ModulePart,
39 resolved_as: ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>,
40 side_effects: Vec<ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>>,
41 ) -> Vc<Self> {
42 SideEffectsModule {
43 module,
44 part,
45 resolved_as,
46 side_effects,
47 }
48 .cell()
49 }
50}
51
52#[turbo_tasks::value_impl]
53impl Module for SideEffectsModule {
54 #[turbo_tasks::function]
55 async fn ident(&self) -> Result<Vc<AssetIdent>> {
56 let mut ident = self.module.ident().owned().await?;
57 ident.parts.push(self.part.clone());
58
59 ident.add_asset(
60 rcstr!("resolved"),
61 self.resolved_as.ident().to_resolved().await?,
62 );
63
64 ident.add_modifier(rcstr!("side effects"));
65
66 for (i, side_effect) in self.side_effects.iter().enumerate() {
67 ident.add_asset(
68 RcStr::from(format!("side effect {i}")),
69 side_effect.ident().to_resolved().await?,
70 );
71 }
72
73 Ok(AssetIdent::new(ident))
74 }
75
76 #[turbo_tasks::function]
77 async fn references(&self) -> Result<Vc<ModuleReferences>> {
78 let mut references = vec![];
79
80 references.extend(
81 self.side_effects
82 .iter()
83 .map(|side_effect| async move {
84 Ok(ResolvedVc::upcast(
85 SingleChunkableModuleReference::new(
86 *ResolvedVc::upcast(*side_effect),
87 rcstr!("side effect"),
88 ExportUsage::evaluation(),
89 )
90 .to_resolved()
91 .await?,
92 ))
93 })
94 .try_join()
95 .await?,
96 );
97
98 references.push(ResolvedVc::upcast(
99 SingleChunkableModuleReference::new(
100 *ResolvedVc::upcast(self.resolved_as),
101 rcstr!("resolved as"),
102 ExportUsage::all(),
103 )
104 .to_resolved()
105 .await?,
106 ));
107
108 Ok(Vc::cell(references))
109 }
110}
111
112#[turbo_tasks::value_impl]
113impl Asset for SideEffectsModule {
114 #[turbo_tasks::function]
115 fn content(&self) -> Vc<AssetContent> {
116 unreachable!("SideEffectsModule has no content")
117 }
118}
119
120#[turbo_tasks::value_impl]
121impl EcmascriptChunkPlaceable for SideEffectsModule {
122 #[turbo_tasks::function]
123 fn get_exports(&self) -> Vc<EcmascriptExports> {
124 self.resolved_as.get_exports()
125 }
126
127 #[turbo_tasks::function]
128 fn is_marked_as_side_effect_free(self: Vc<Self>, _: Vc<Glob>) -> Vc<bool> {
129 Vc::cell(true)
130 }
131}
132
133#[turbo_tasks::value_impl]
134impl ChunkableModule for SideEffectsModule {
135 #[turbo_tasks::function]
136 async fn as_chunk_item(
137 self: Vc<Self>,
138 module_graph: ResolvedVc<ModuleGraph>,
139 chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
140 ) -> Result<Vc<Box<dyn turbopack_core::chunk::ChunkItem>>> {
141 Ok(Vc::upcast(
142 SideEffectsModuleChunkItem {
143 module: self.to_resolved().await?,
144 module_graph,
145 chunking_context,
146 }
147 .cell(),
148 ))
149 }
150}
151
152#[turbo_tasks::value_impl]
153impl EvaluatableAsset for SideEffectsModule {}