turbopack_wasm/
module_asset.rs1use anyhow::{Result, bail};
2use turbo_rcstr::rcstr;
3use turbo_tasks::{ResolvedVc, Vc, fxindexmap};
4use turbo_tasks_fs::FileSystemPath;
5use turbopack_core::{
6 chunk::{AsyncModuleInfo, ChunkableModule, ChunkingContext},
7 context::AssetContext,
8 ident::AssetIdent,
9 module::{Module, ModuleSideEffects},
10 module_graph::ModuleGraph,
11 output::OutputAssetsWithReferenced,
12 reference::{ModuleReferences, SingleChunkableModuleReference},
13 reference_type::ReferenceType,
14 resolve::{ExportUsage, origin::ResolveOrigin},
15 source::{OptionSource, Source},
16};
17use turbopack_ecmascript::{
18 chunk::{
19 EcmascriptChunkItemContent, EcmascriptChunkPlaceable, EcmascriptExports,
20 ecmascript_chunk_item,
21 },
22 references::async_module::OptionAsyncModule,
23};
24
25use crate::{
26 loader::{compiling_loader_source, instantiating_loader_source},
27 output_asset::WebAssemblyAsset,
28 raw::RawWebAssemblyModuleAsset,
29 source::WebAssemblySource,
30};
31
32#[turbo_tasks::value]
35#[derive(Clone)]
36pub struct WebAssemblyModuleAsset {
37 source: ResolvedVc<WebAssemblySource>,
38 asset_context: ResolvedVc<Box<dyn AssetContext>>,
39}
40
41#[turbo_tasks::value_impl]
42impl WebAssemblyModuleAsset {
43 #[turbo_tasks::function]
44 pub fn new(
45 source: ResolvedVc<WebAssemblySource>,
46 asset_context: ResolvedVc<Box<dyn AssetContext>>,
47 ) -> Vc<Self> {
48 Self::cell(WebAssemblyModuleAsset {
49 source,
50 asset_context,
51 })
52 }
53
54 #[turbo_tasks::function]
55 fn wasm_asset(&self, chunking_context: Vc<Box<dyn ChunkingContext>>) -> Vc<WebAssemblyAsset> {
56 WebAssemblyAsset::new(*self.source, chunking_context)
57 }
58
59 #[turbo_tasks::function]
60 async fn loader_as_module(&self) -> Result<Vc<Box<dyn Module>>> {
61 let query = &self.source.ident().await?.query;
62
63 let loader_source = if query == "?module" {
64 compiling_loader_source(*self.source)
65 } else {
66 instantiating_loader_source(*self.source)
67 };
68
69 let module = self.asset_context.process(
70 loader_source,
71 ReferenceType::Internal(ResolvedVc::cell(fxindexmap! {
72 rcstr!("WASM_PATH") => ResolvedVc::upcast(RawWebAssemblyModuleAsset::new(*self.source, *self.asset_context).to_resolved().await?),
73 })),
74 ).module();
75
76 Ok(module)
77 }
78 #[turbo_tasks::function]
79 async fn loader_as_resolve_origin(self: Vc<Self>) -> Result<Vc<Box<dyn ResolveOrigin>>> {
80 let module = self.loader_as_module();
81
82 let Some(esm_asset) =
83 ResolvedVc::try_sidecast::<Box<dyn ResolveOrigin>>(module.to_resolved().await?)
84 else {
85 bail!("WASM loader was not processed into an EcmascriptModuleAsset");
86 };
87
88 Ok(*esm_asset)
89 }
90
91 #[turbo_tasks::function]
92 async fn loader(self: Vc<Self>) -> Result<Vc<Box<dyn EcmascriptChunkPlaceable>>> {
93 let module = self.loader_as_module();
94
95 let Some(esm_asset) = ResolvedVc::try_sidecast::<Box<dyn EcmascriptChunkPlaceable>>(
96 module.to_resolved().await?,
97 ) else {
98 bail!("WASM loader was not processed into an EcmascriptModuleAsset");
99 };
100
101 Ok(*esm_asset)
102 }
103
104 #[turbo_tasks::function]
105 async fn references(self: Vc<Self>) -> Result<Vc<ModuleReferences>> {
106 Ok(Vc::cell(vec![ResolvedVc::upcast(
107 SingleChunkableModuleReference::new(
108 Vc::upcast(self.loader()),
109 rcstr!("wasm loader"),
110 ExportUsage::all(),
111 )
112 .to_resolved()
113 .await?,
114 )]))
115 }
116}
117
118#[turbo_tasks::value_impl]
119impl Module for WebAssemblyModuleAsset {
120 #[turbo_tasks::function]
121 async fn ident(&self) -> Result<Vc<AssetIdent>> {
122 Ok(self
123 .source
124 .ident()
125 .with_modifier(rcstr!("wasm module"))
126 .with_layer(self.asset_context.into_trait_ref().await?.layer()))
127 }
128
129 #[turbo_tasks::function]
130 fn source(&self) -> Vc<OptionSource> {
131 Vc::cell(Some(ResolvedVc::upcast(self.source)))
132 }
133
134 #[turbo_tasks::function]
135 fn references(self: Vc<Self>) -> Vc<ModuleReferences> {
136 self.loader().references()
137 }
138
139 #[turbo_tasks::function]
140 fn is_self_async(self: Vc<Self>) -> Vc<bool> {
141 Vc::cell(true)
142 }
143
144 #[turbo_tasks::function]
145 fn side_effects(self: Vc<Self>) -> Vc<ModuleSideEffects> {
146 ModuleSideEffects::SideEffectful.cell()
150 }
151}
152
153#[turbo_tasks::value_impl]
154impl ChunkableModule for WebAssemblyModuleAsset {
155 #[turbo_tasks::function]
156 fn as_chunk_item(
157 self: ResolvedVc<Self>,
158 module_graph: ResolvedVc<ModuleGraph>,
159 chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
160 ) -> Vc<Box<dyn turbopack_core::chunk::ChunkItem>> {
161 ecmascript_chunk_item(ResolvedVc::upcast(self), module_graph, chunking_context)
162 }
163}
164
165#[turbo_tasks::value_impl]
166impl EcmascriptChunkPlaceable for WebAssemblyModuleAsset {
167 #[turbo_tasks::function]
168 fn get_exports(self: Vc<Self>) -> Vc<EcmascriptExports> {
169 self.loader().get_exports()
170 }
171
172 #[turbo_tasks::function]
173 fn get_async_module(self: Vc<Self>) -> Vc<OptionAsyncModule> {
174 self.loader().get_async_module()
175 }
176
177 #[turbo_tasks::function]
178 async fn chunk_item_content(
179 self: Vc<Self>,
180 chunking_context: Vc<Box<dyn ChunkingContext>>,
181 module_graph: Vc<ModuleGraph>,
182 async_module_info: Option<Vc<AsyncModuleInfo>>,
183 estimated: bool,
184 ) -> Result<Vc<EcmascriptChunkItemContent>> {
185 Ok(self.loader().chunk_item_content(
187 chunking_context,
188 module_graph,
189 async_module_info,
190 estimated,
191 ))
192 }
193
194 #[turbo_tasks::function]
195 async fn chunk_item_output_assets(
196 self: Vc<Self>,
197 chunking_context: Vc<Box<dyn ChunkingContext>>,
198 _module_graph: Vc<ModuleGraph>,
199 ) -> Result<Vc<OutputAssetsWithReferenced>> {
200 let wasm_asset = self.wasm_asset(chunking_context).to_resolved().await?;
201 Ok(OutputAssetsWithReferenced::from_assets(Vc::cell(vec![
202 ResolvedVc::upcast(wasm_asset),
203 ])))
204 }
205}
206
207#[turbo_tasks::value_impl]
208impl ResolveOrigin for WebAssemblyModuleAsset {
209 #[turbo_tasks::function]
210 fn origin_path(&self) -> Vc<FileSystemPath> {
211 self.source.ident().path()
212 }
213
214 #[turbo_tasks::function]
215 fn asset_context(&self) -> Vc<Box<dyn AssetContext>> {
216 *self.asset_context
217 }
218}