1use anyhow::{Result, bail};
2use turbo_rcstr::rcstr;
3use turbo_tasks::{IntoTraitRef, ResolvedVc, Vc};
4use turbopack_core::{
5 asset::{Asset, AssetContent},
6 chunk::{ChunkItem, ChunkType, ChunkableModule, ChunkingContext},
7 context::AssetContext,
8 ident::AssetIdent,
9 module::{Module, ModuleSideEffects},
10 module_graph::ModuleGraph,
11 output::{OutputAsset, OutputAssetsReference, OutputAssetsWithReferenced},
12 source::{OptionSource, Source},
13};
14use turbopack_ecmascript::{
15 chunk::{
16 EcmascriptChunkItem, EcmascriptChunkItemContent, EcmascriptChunkPlaceable,
17 EcmascriptChunkType, EcmascriptExports,
18 },
19 runtime_functions::TURBOPACK_EXPORT_VALUE,
20 utils::StringifyJs,
21};
22
23use crate::{output_asset::WebAssemblyAsset, source::WebAssemblySource};
24
25#[turbo_tasks::value]
27#[derive(Clone)]
28pub struct RawWebAssemblyModuleAsset {
29 source: ResolvedVc<WebAssemblySource>,
30 asset_context: ResolvedVc<Box<dyn AssetContext>>,
31}
32
33#[turbo_tasks::value_impl]
34impl RawWebAssemblyModuleAsset {
35 #[turbo_tasks::function]
36 pub fn new(
37 source: ResolvedVc<WebAssemblySource>,
38 asset_context: ResolvedVc<Box<dyn AssetContext>>,
39 ) -> Vc<Self> {
40 Self::cell(RawWebAssemblyModuleAsset {
41 source,
42 asset_context,
43 })
44 }
45
46 #[turbo_tasks::function]
47 fn wasm_asset(&self, chunking_context: Vc<Box<dyn ChunkingContext>>) -> Vc<WebAssemblyAsset> {
48 WebAssemblyAsset::new(*self.source, chunking_context)
49 }
50}
51
52#[turbo_tasks::value_impl]
53impl Module for RawWebAssemblyModuleAsset {
54 #[turbo_tasks::function]
55 async fn ident(&self) -> Result<Vc<AssetIdent>> {
56 Ok(self
57 .source
58 .ident()
59 .with_modifier(rcstr!("wasm raw"))
60 .with_layer(self.asset_context.into_trait_ref().await?.layer()))
61 }
62
63 #[turbo_tasks::function]
64 fn source(&self) -> Vc<OptionSource> {
65 Vc::cell(Some(ResolvedVc::upcast(self.source)))
66 }
67
68 #[turbo_tasks::function]
69 fn side_effects(self: Vc<Self>) -> Vc<ModuleSideEffects> {
70 ModuleSideEffects::SideEffectFree.cell()
72 }
73}
74
75#[turbo_tasks::value_impl]
76impl Asset for RawWebAssemblyModuleAsset {
77 #[turbo_tasks::function]
78 fn content(&self) -> Vc<AssetContent> {
79 self.source.content()
80 }
81}
82
83#[turbo_tasks::value_impl]
84impl ChunkableModule for RawWebAssemblyModuleAsset {
85 #[turbo_tasks::function]
86 async fn as_chunk_item(
87 self: ResolvedVc<Self>,
88 _module_graph: Vc<ModuleGraph>,
89 chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
90 ) -> Result<Vc<Box<dyn turbopack_core::chunk::ChunkItem>>> {
91 Ok(Vc::upcast(
92 RawModuleChunkItem {
93 module: self,
94 chunking_context,
95 wasm_asset: self.wasm_asset(*chunking_context).to_resolved().await?,
96 }
97 .cell(),
98 ))
99 }
100}
101
102#[turbo_tasks::value_impl]
103impl EcmascriptChunkPlaceable for RawWebAssemblyModuleAsset {
104 #[turbo_tasks::function]
105 fn get_exports(self: Vc<Self>) -> Vc<EcmascriptExports> {
106 EcmascriptExports::Value.cell()
107 }
108}
109
110#[turbo_tasks::value]
111struct RawModuleChunkItem {
112 module: ResolvedVc<RawWebAssemblyModuleAsset>,
113 chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
114 wasm_asset: ResolvedVc<WebAssemblyAsset>,
115}
116
117#[turbo_tasks::value_impl]
118impl OutputAssetsReference for RawModuleChunkItem {
119 #[turbo_tasks::function]
120 fn references(&self) -> Vc<OutputAssetsWithReferenced> {
121 OutputAssetsWithReferenced::from_assets(Vc::cell(vec![ResolvedVc::upcast(self.wasm_asset)]))
122 }
123}
124
125#[turbo_tasks::value_impl]
126impl ChunkItem for RawModuleChunkItem {
127 #[turbo_tasks::function]
128 fn asset_ident(&self) -> Vc<AssetIdent> {
129 self.module.ident()
130 }
131
132 #[turbo_tasks::function]
133 fn chunking_context(&self) -> Vc<Box<dyn ChunkingContext>> {
134 *self.chunking_context
135 }
136
137 #[turbo_tasks::function]
138 async fn ty(&self) -> Result<Vc<Box<dyn ChunkType>>> {
139 Ok(Vc::upcast(
140 Vc::<EcmascriptChunkType>::default().resolve().await?,
141 ))
142 }
143
144 #[turbo_tasks::function]
145 fn module(&self) -> Vc<Box<dyn Module>> {
146 Vc::upcast(*self.module)
147 }
148}
149
150#[turbo_tasks::value_impl]
151impl EcmascriptChunkItem for RawModuleChunkItem {
152 #[turbo_tasks::function]
153 async fn content(&self) -> Result<Vc<EcmascriptChunkItemContent>> {
154 let path = self.wasm_asset.path().await?;
155 let output_root = self.chunking_context.output_root().await?;
156
157 let Some(path) = output_root.get_path_to(&path) else {
158 bail!("WASM asset ident is not relative to output root");
159 };
160
161 Ok(EcmascriptChunkItemContent {
162 inner_code: format!(
163 "{TURBOPACK_EXPORT_VALUE}({path});",
164 path = StringifyJs(path)
165 )
166 .into(),
167 ..Default::default()
168 }
169 .cell())
170 }
171}