Skip to main content

turbopack_wasm/
raw.rs

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/// Exports the relative path to the WebAssembly file without loading it.
25#[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        // this just exports a path
73        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}