1use anyhow::{Result, bail};
2use turbo_rcstr::rcstr;
3use turbo_tasks::{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 .owned()
59 .await?
60 .with_modifier(rcstr!("wasm raw"))
61 .with_layer(self.asset_context.into_trait_ref().await?.layer())
62 .into_vc())
63 }
64
65 #[turbo_tasks::function]
66 fn source(&self) -> Vc<OptionSource> {
67 Vc::cell(Some(ResolvedVc::upcast(self.source)))
68 }
69
70 #[turbo_tasks::function]
71 fn side_effects(self: Vc<Self>) -> Vc<ModuleSideEffects> {
72 ModuleSideEffects::SideEffectFree.cell()
74 }
75}
76
77#[turbo_tasks::value_impl]
78impl ChunkableModule for RawWebAssemblyModuleAsset {
79 #[turbo_tasks::function]
80 fn as_chunk_item(
81 self: ResolvedVc<Self>,
82 module_graph: ResolvedVc<ModuleGraph>,
83 chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
84 ) -> Vc<Box<dyn turbopack_core::chunk::ChunkItem>> {
85 ecmascript_chunk_item(ResolvedVc::upcast(self), module_graph, chunking_context)
86 }
87}
88
89#[turbo_tasks::value_impl]
90impl EcmascriptChunkPlaceable for RawWebAssemblyModuleAsset {
91 #[turbo_tasks::function]
92 fn get_exports(self: Vc<Self>) -> Vc<EcmascriptExports> {
93 EcmascriptExports::Value.cell()
94 }
95
96 #[turbo_tasks::function]
97 async fn chunk_item_content(
98 self: Vc<Self>,
99 chunking_context: Vc<Box<dyn ChunkingContext>>,
100 _module_graph: Vc<ModuleGraph>,
101 _async_module_info: Option<Vc<AsyncModuleInfo>>,
102 _estimated: bool,
103 ) -> Result<Vc<EcmascriptChunkItemContent>> {
104 let wasm_asset = self.wasm_asset(chunking_context);
105 let path = wasm_asset.path().await?;
106 let output_root = chunking_context.output_root().await?;
107
108 let Some(path) = output_root.get_path_to(&path) else {
109 bail!("WASM asset ident is not relative to output root");
110 };
111
112 Ok(EcmascriptChunkItemContent {
113 inner_code: format!("{TURBOPACK_EXPORT_URL}({path});", path = StringifyJs(path)).into(),
114 ..Default::default()
115 }
116 .cell())
117 }
118
119 #[turbo_tasks::function]
120 async fn chunk_item_output_assets(
121 self: Vc<Self>,
122 chunking_context: Vc<Box<dyn ChunkingContext>>,
123 _module_graph: Vc<ModuleGraph>,
124 ) -> Result<Vc<OutputAssetsWithReferenced>> {
125 let wasm_asset = self.wasm_asset(chunking_context).to_resolved().await?;
126 Ok(OutputAssetsWithReferenced::from_assets(Vc::cell(vec![
127 ResolvedVc::upcast(wasm_asset),
128 ])))
129 }
130}