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