Skip to main content

turbopack_wasm/
raw.rs

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/// 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            .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        // this just exports a path
70        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}