turbopack_ecmascript/tree_shake/
side_effect_module.rs

1use 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    /// Original module
24    pub module: ResolvedVc<EcmascriptModuleAsset>,
25    /// The part of the original module that is the binding
26    pub part: ModulePart,
27    /// The module that is the binding
28    pub resolved_as: ResolvedVc<Box<dyn EcmascriptChunkPlaceable>>,
29    /// Side effects from the original module to the binding.
30    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 {}