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}