turbopack_static/
ecma.rs

1use anyhow::Result;
2use turbo_rcstr::{RcStr, rcstr};
3use turbo_tasks::{ResolvedVc, Vc};
4use turbopack_core::{
5    asset::{Asset, AssetContent},
6    chunk::{ChunkItem, ChunkType, ChunkableModule, ChunkingContext},
7    ident::AssetIdent,
8    module::{Module, ModuleSideEffects},
9    module_graph::ModuleGraph,
10    output::{OutputAsset, OutputAssetsReference, OutputAssetsWithReferenced},
11    source::Source,
12};
13use turbopack_ecmascript::{
14    chunk::{
15        EcmascriptChunkItem, EcmascriptChunkItemContent, EcmascriptChunkPlaceable,
16        EcmascriptChunkType, EcmascriptExports,
17    },
18    runtime_functions::TURBOPACK_EXPORT_VALUE,
19    utils::StringifyJs,
20};
21
22use crate::output_asset::StaticOutputAsset;
23
24#[turbo_tasks::value]
25#[derive(Clone)]
26pub struct StaticUrlJsModule {
27    pub source: ResolvedVc<Box<dyn Source>>,
28    pub tag: Option<RcStr>,
29}
30
31#[turbo_tasks::value_impl]
32impl StaticUrlJsModule {
33    #[turbo_tasks::function]
34    pub fn new(source: ResolvedVc<Box<dyn Source>>, tag: Option<RcStr>) -> Vc<Self> {
35        Self::cell(StaticUrlJsModule { source, tag })
36    }
37
38    #[turbo_tasks::function]
39    fn static_output_asset(
40        &self,
41        chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
42    ) -> Vc<StaticOutputAsset> {
43        StaticOutputAsset::new(*chunking_context, *self.source, self.tag.clone())
44    }
45}
46
47#[turbo_tasks::value_impl]
48impl Module for StaticUrlJsModule {
49    #[turbo_tasks::function]
50    fn ident(&self) -> Vc<AssetIdent> {
51        let mut ident = self
52            .source
53            .ident()
54            .with_modifier(rcstr!("static in ecmascript"));
55        if let Some(tag) = &self.tag {
56            ident = ident.with_modifier(format!("tag {}", tag).into());
57        }
58        ident
59    }
60
61    #[turbo_tasks::function]
62    fn source(&self) -> Vc<turbopack_core::source::OptionSource> {
63        Vc::cell(Some(self.source))
64    }
65
66    #[turbo_tasks::function]
67    fn side_effects(self: Vc<Self>) -> Vc<ModuleSideEffects> {
68        ModuleSideEffects::SideEffectFree.cell()
69    }
70}
71
72#[turbo_tasks::value_impl]
73impl Asset for StaticUrlJsModule {
74    #[turbo_tasks::function]
75    fn content(&self) -> Vc<AssetContent> {
76        self.source.content()
77    }
78}
79
80#[turbo_tasks::value_impl]
81impl ChunkableModule for StaticUrlJsModule {
82    #[turbo_tasks::function]
83    async fn as_chunk_item(
84        self: ResolvedVc<Self>,
85        _module_graph: Vc<ModuleGraph>,
86        chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
87    ) -> Result<Vc<Box<dyn turbopack_core::chunk::ChunkItem>>> {
88        Ok(Vc::upcast(StaticUrlJsChunkItem::cell(
89            StaticUrlJsChunkItem {
90                module: self,
91                chunking_context,
92                static_asset: self
93                    .static_output_asset(*chunking_context)
94                    .to_resolved()
95                    .await?,
96                tag: self.await?.tag.clone(),
97            },
98        )))
99    }
100}
101
102#[turbo_tasks::value_impl]
103impl EcmascriptChunkPlaceable for StaticUrlJsModule {
104    #[turbo_tasks::function]
105    fn get_exports(&self) -> Vc<EcmascriptExports> {
106        EcmascriptExports::Value.cell()
107    }
108}
109
110#[turbo_tasks::value]
111struct StaticUrlJsChunkItem {
112    module: ResolvedVc<StaticUrlJsModule>,
113    chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
114    static_asset: ResolvedVc<StaticOutputAsset>,
115    tag: Option<RcStr>,
116}
117
118#[turbo_tasks::value_impl]
119impl OutputAssetsReference for StaticUrlJsChunkItem {
120    #[turbo_tasks::function]
121    fn references(&self) -> Vc<OutputAssetsWithReferenced> {
122        OutputAssetsWithReferenced::from_assets(Vc::cell(vec![ResolvedVc::upcast(
123            self.static_asset,
124        )]))
125    }
126}
127
128#[turbo_tasks::value_impl]
129impl ChunkItem for StaticUrlJsChunkItem {
130    #[turbo_tasks::function]
131    fn asset_ident(&self) -> Vc<AssetIdent> {
132        self.module.ident()
133    }
134
135    #[turbo_tasks::function]
136    fn chunking_context(&self) -> Vc<Box<dyn ChunkingContext>> {
137        *self.chunking_context
138    }
139
140    #[turbo_tasks::function]
141    async fn ty(&self) -> Result<Vc<Box<dyn ChunkType>>> {
142        Ok(Vc::upcast(
143            Vc::<EcmascriptChunkType>::default().resolve().await?,
144        ))
145    }
146
147    #[turbo_tasks::function]
148    fn module(&self) -> Vc<Box<dyn Module>> {
149        *ResolvedVc::upcast(self.module)
150    }
151}
152
153#[turbo_tasks::value_impl]
154impl EcmascriptChunkItem for StaticUrlJsChunkItem {
155    #[turbo_tasks::function]
156    async fn content(&self) -> Result<Vc<EcmascriptChunkItemContent>> {
157        Ok(EcmascriptChunkItemContent {
158            inner_code: format!(
159                "{TURBOPACK_EXPORT_VALUE}({path});",
160                path = StringifyJs(
161                    &self
162                        .chunking_context
163                        .asset_url(self.static_asset.path().owned().await?, self.tag.clone())
164                        .await?
165                )
166            )
167            .into(),
168            ..Default::default()
169        }
170        .cell())
171    }
172}