turbopack_wasm/
raw.rs

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,
10    module_graph::ModuleGraph,
11    output::{OutputAsset, OutputAssets},
12    source::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/// Exports the relative path to the WebAssembly file without loading it.
26#[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
64#[turbo_tasks::value_impl]
65impl Asset for RawWebAssemblyModuleAsset {
66    #[turbo_tasks::function]
67    fn content(&self) -> Vc<AssetContent> {
68        self.source.content()
69    }
70}
71
72#[turbo_tasks::value_impl]
73impl ChunkableModule for RawWebAssemblyModuleAsset {
74    #[turbo_tasks::function]
75    async fn as_chunk_item(
76        self: ResolvedVc<Self>,
77        _module_graph: Vc<ModuleGraph>,
78        chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
79    ) -> Result<Vc<Box<dyn turbopack_core::chunk::ChunkItem>>> {
80        Ok(Vc::upcast(
81            RawModuleChunkItem {
82                module: self,
83                chunking_context,
84                wasm_asset: self.wasm_asset(*chunking_context).to_resolved().await?,
85            }
86            .cell(),
87        ))
88    }
89}
90
91#[turbo_tasks::value_impl]
92impl EcmascriptChunkPlaceable for RawWebAssemblyModuleAsset {
93    #[turbo_tasks::function]
94    fn get_exports(self: Vc<Self>) -> Vc<EcmascriptExports> {
95        EcmascriptExports::Value.cell()
96    }
97}
98
99#[turbo_tasks::value]
100struct RawModuleChunkItem {
101    module: ResolvedVc<RawWebAssemblyModuleAsset>,
102    chunking_context: ResolvedVc<Box<dyn ChunkingContext>>,
103    wasm_asset: ResolvedVc<WebAssemblyAsset>,
104}
105
106#[turbo_tasks::value_impl]
107impl ChunkItem for RawModuleChunkItem {
108    #[turbo_tasks::function]
109    fn asset_ident(&self) -> Vc<AssetIdent> {
110        self.module.ident()
111    }
112
113    #[turbo_tasks::function]
114    fn references(&self) -> Result<Vc<OutputAssets>> {
115        Ok(Vc::cell(vec![ResolvedVc::upcast(self.wasm_asset)]))
116    }
117
118    #[turbo_tasks::function]
119    fn chunking_context(&self) -> Vc<Box<dyn ChunkingContext>> {
120        Vc::upcast(*self.chunking_context)
121    }
122
123    #[turbo_tasks::function]
124    async fn ty(&self) -> Result<Vc<Box<dyn ChunkType>>> {
125        Ok(Vc::upcast(
126            Vc::<EcmascriptChunkType>::default().resolve().await?,
127        ))
128    }
129
130    #[turbo_tasks::function]
131    fn module(&self) -> Vc<Box<dyn Module>> {
132        Vc::upcast(*self.module)
133    }
134}
135
136#[turbo_tasks::value_impl]
137impl EcmascriptChunkItem for RawModuleChunkItem {
138    #[turbo_tasks::function]
139    async fn content(&self) -> Result<Vc<EcmascriptChunkItemContent>> {
140        let path = self.wasm_asset.path().await?;
141        let output_root = self.chunking_context.output_root().await?;
142
143        let Some(path) = output_root.get_path_to(&path) else {
144            bail!("WASM asset ident is not relative to output root");
145        };
146
147        Ok(EcmascriptChunkItemContent {
148            inner_code: format!(
149                "{TURBOPACK_EXPORT_VALUE}({path});",
150                path = StringifyJs(path)
151            )
152            .into(),
153            ..Default::default()
154        }
155        .into())
156    }
157}