turbopack_ecmascript/tree_shake/
side_effect_module.rs

1use anyhow::Result;
2use turbo_rcstr::RcStr;
3use turbo_tasks::{ResolvedVc, TryJoinIterExt, Value, 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::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            ResolvedVc::cell(RcStr::from("resolved")),
61            self.resolved_as.ident().to_resolved().await?,
62        );
63
64        ident.add_modifier(ResolvedVc::cell(RcStr::from("side effects")));
65
66        for (i, side_effect) in self.side_effects.iter().enumerate() {
67            ident.add_asset(
68                ResolvedVc::cell(RcStr::from(format!("side effect {i}"))),
69                side_effect.ident().to_resolved().await?,
70            );
71        }
72
73        Ok(AssetIdent::new(Value::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                            Vc::cell(RcStr::from("side effect")),
88                        )
89                        .to_resolved()
90                        .await?,
91                    ))
92                })
93                .try_join()
94                .await?,
95        );
96
97        references.push(ResolvedVc::upcast(
98            SingleChunkableModuleReference::new(
99                *ResolvedVc::upcast(self.resolved_as),
100                Vc::cell(RcStr::from("resolved as")),
101            )
102            .to_resolved()
103            .await?,
104        ));
105
106        Ok(Vc::cell(references))
107    }
108}
109
110#[turbo_tasks::value_impl]
111impl Asset for SideEffectsModule {
112    #[turbo_tasks::function]
113    fn content(&self) -> Vc<AssetContent> {
114        unreachable!("SideEffectsModule has no content")
115    }
116}
117
118#[turbo_tasks::value_impl]
119impl EcmascriptChunkPlaceable for SideEffectsModule {
120    #[turbo_tasks::function]
121    async fn get_exports(&self) -> Vc<EcmascriptExports> {
122        self.resolved_as.get_exports()
123    }
124
125    #[turbo_tasks::function]
126    async fn is_marked_as_side_effect_free(self: Vc<Self>, _: Vc<Glob>) -> Vc<bool> {
127        Vc::cell(true)
128    }
129}
130
131#[turbo_tasks::value_impl]
132impl ChunkableModule for SideEffectsModule {
133    #[turbo_tasks::function]
134    async fn as_chunk_item(
135        self: Vc<Self>,
136        module_graph: ResolvedVc<ModuleGraph>,
137        chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
138    ) -> Result<Vc<Box<dyn turbopack_core::chunk::ChunkItem>>> {
139        Ok(Vc::upcast(
140            SideEffectsModuleChunkItem {
141                module: self.to_resolved().await?,
142                module_graph,
143                chunking_context,
144            }
145            .cell(),
146        ))
147    }
148}
149
150#[turbo_tasks::value_impl]
151impl EvaluatableAsset for SideEffectsModule {}