1use anyhow::{Result, bail};
2use turbo_rcstr::rcstr;
3use turbo_tasks::{IntoTraitRef, ResolvedVc, Vc};
4use turbopack_core::{
5 chunk::{AsyncModuleInfo, ChunkableModule, ChunkingContext},
6 context::AssetContext,
7 ident::AssetIdent,
8 module::{Module, ModuleSideEffects},
9 module_graph::ModuleGraph,
10 output::{OutputAsset, OutputAssetsWithReferenced},
11 source::{OptionSource, Source},
12};
13use turbopack_ecmascript::{
14 chunk::{
15 EcmascriptChunkItemContent, EcmascriptChunkPlaceable, EcmascriptExports,
16 ecmascript_chunk_item,
17 },
18 runtime_functions::TURBOPACK_EXPORT_URL,
19 utils::StringifyJs,
20};
21
22use crate::{output_asset::WebAssemblyAsset, source::WebAssemblySource};
23
24#[turbo_tasks::value]
26#[derive(Clone)]
27pub struct RawWebAssemblyModuleAsset {
28 source: ResolvedVc<WebAssemblySource>,
29 asset_context: ResolvedVc<Box<dyn AssetContext>>,
30}
31
32#[turbo_tasks::value_impl]
33impl RawWebAssemblyModuleAsset {
34 #[turbo_tasks::function]
35 pub fn new(
36 source: ResolvedVc<WebAssemblySource>,
37 asset_context: ResolvedVc<Box<dyn AssetContext>>,
38 ) -> Vc<Self> {
39 Self::cell(RawWebAssemblyModuleAsset {
40 source,
41 asset_context,
42 })
43 }
44
45 #[turbo_tasks::function]
46 fn wasm_asset(&self, chunking_context: Vc<Box<dyn ChunkingContext>>) -> Vc<WebAssemblyAsset> {
47 WebAssemblyAsset::new(*self.source, chunking_context)
48 }
49}
50
51#[turbo_tasks::value_impl]
52impl Module for RawWebAssemblyModuleAsset {
53 #[turbo_tasks::function]
54 async fn ident(&self) -> Result<Vc<AssetIdent>> {
55 Ok(self
56 .source
57 .ident()
58 .with_modifier(rcstr!("wasm raw"))
59 .with_layer(self.asset_context.into_trait_ref().await?.layer()))
60 }
61
62 #[turbo_tasks::function]
63 fn source(&self) -> Vc<OptionSource> {
64 Vc::cell(Some(ResolvedVc::upcast(self.source)))
65 }
66
67 #[turbo_tasks::function]
68 fn side_effects(self: Vc<Self>) -> Vc<ModuleSideEffects> {
69 ModuleSideEffects::SideEffectFree.cell()
71 }
72}
73
74#[turbo_tasks::value_impl]
75impl ChunkableModule for RawWebAssemblyModuleAsset {
76 #[turbo_tasks::function]
77 fn as_chunk_item(
78 self: ResolvedVc<Self>,
79 module_graph: ResolvedVc<ModuleGraph>,
80 chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
81 ) -> Vc<Box<dyn turbopack_core::chunk::ChunkItem>> {
82 ecmascript_chunk_item(ResolvedVc::upcast(self), module_graph, chunking_context)
83 }
84}
85
86#[turbo_tasks::value_impl]
87impl EcmascriptChunkPlaceable for RawWebAssemblyModuleAsset {
88 #[turbo_tasks::function]
89 fn get_exports(self: Vc<Self>) -> Vc<EcmascriptExports> {
90 EcmascriptExports::Value.cell()
91 }
92
93 #[turbo_tasks::function]
94 async fn chunk_item_content(
95 self: Vc<Self>,
96 chunking_context: Vc<Box<dyn ChunkingContext>>,
97 _module_graph: Vc<ModuleGraph>,
98 _async_module_info: Option<Vc<AsyncModuleInfo>>,
99 _estimated: bool,
100 ) -> Result<Vc<EcmascriptChunkItemContent>> {
101 let wasm_asset = self.wasm_asset(chunking_context);
102 let path = wasm_asset.path().await?;
103 let output_root = chunking_context.output_root().await?;
104
105 let Some(path) = output_root.get_path_to(&path) else {
106 bail!("WASM asset ident is not relative to output root");
107 };
108
109 Ok(EcmascriptChunkItemContent {
110 inner_code: format!("{TURBOPACK_EXPORT_URL}({path});", path = StringifyJs(path)).into(),
111 ..Default::default()
112 }
113 .cell())
114 }
115
116 #[turbo_tasks::function]
117 async fn chunk_item_output_assets(
118 self: Vc<Self>,
119 chunking_context: Vc<Box<dyn ChunkingContext>>,
120 _module_graph: Vc<ModuleGraph>,
121 ) -> Result<Vc<OutputAssetsWithReferenced>> {
122 let wasm_asset = self.wasm_asset(chunking_context).to_resolved().await?;
123 Ok(OutputAssetsWithReferenced::from_assets(Vc::cell(vec![
124 ResolvedVc::upcast(wasm_asset),
125 ])))
126 }
127}