diff --git a/crates/cli-support/src/intrinsic.rs b/crates/cli-support/src/intrinsic.rs index efdc131ca21..b01e6434c2e 100644 --- a/crates/cli-support/src/intrinsic.rs +++ b/crates/cli-support/src/intrinsic.rs @@ -229,6 +229,9 @@ intrinsics! { #[symbol = "__wbindgen_module"] #[signature = fn() -> Externref] Module, + #[symbol = "__wbindgen_script_url"] + #[signature = fn() -> String] + ScriptUrl, #[symbol = "__wbindgen_function_table"] #[signature = fn() -> Externref] FunctionTable, diff --git a/crates/cli-support/src/js/mod.rs b/crates/cli-support/src/js/mod.rs index 0e8934ed809..61f21f884ff 100644 --- a/crates/cli-support/src/js/mod.rs +++ b/crates/cli-support/src/js/mod.rs @@ -378,6 +378,15 @@ impl<'a> Context<'a> { // function. OutputMode::NoModules { global } => { js.push_str("const __exports = {};\n"); + js.push_str("let script_src;\n"); + js.push_str( + "\ + if (typeof document === 'undefined') { + script_src = location.href; + } else { + script_src = document.currentScript.src; + }\n", + ); js.push_str("let wasm;\n"); init = self.gen_init(needs_manual_start, None)?; footer.push_str(&format!("{} = Object.assign(init, __exports);\n", global)); @@ -701,13 +710,7 @@ impl<'a> Context<'a> { ), OutputMode::NoModules { .. } => "\ if (typeof input === 'undefined') { - let src; - if (typeof document === 'undefined') { - src = location.href; - } else { - src = document.currentScript.src; - } - input = src.replace(/\\.js$/, '_bg.wasm'); + input = script_src.replace(/\\.js$/, '_bg.wasm'); }" .to_string(), _ => "".to_string(), @@ -3426,6 +3429,22 @@ impl<'a> Context<'a> { format!("wasm.{}", self.export_name_of(memory)) } + Intrinsic::ScriptUrl => { + assert_eq!(args.len(), 0); + match self.config.mode { + OutputMode::Web + | OutputMode::Deno + | OutputMode::Node { + experimental_modules: true, + } => format!("import.meta.url"), + OutputMode::Node { + experimental_modules: false, + } => format!("__filename"), + OutputMode::NoModules { .. } => format!("script_src"), + OutputMode::Bundler { .. } => format!("__webpack_public_path__"), + } + } + Intrinsic::FunctionTable => { assert_eq!(args.len(), 0); let name = self.export_function_table()?; diff --git a/crates/cli/tests/wasm-bindgen/main.rs b/crates/cli/tests/wasm-bindgen/main.rs index b52f14e64c3..1fb94f7c97b 100644 --- a/crates/cli/tests/wasm-bindgen/main.rs +++ b/crates/cli/tests/wasm-bindgen/main.rs @@ -258,17 +258,19 @@ fn default_module_path_target_no_modules() { cmd.assert().success(); let contents = fs::read_to_string(out_dir.join("default_module_path_target_no_modules.js")).unwrap(); + assert!(contents.contains( + "\ + if (typeof document === 'undefined') { + script_src = location.href; + } else { + script_src = document.currentScript.src; + }", + )); assert!(contents.contains( "\ async function init(input) { if (typeof input === 'undefined') { - let src; - if (typeof document === 'undefined') { - src = location.href; - } else { - src = document.currentScript.src; - } - input = src.replace(/\\.js$/, '_bg.wasm'); + input = script_src.replace(/\\.js$/, '_bg.wasm'); }", )); } diff --git a/examples/wasm-audio-worklet/src/dependent_module.rs b/examples/wasm-audio-worklet/src/dependent_module.rs index d4180e3985e..d9846e69519 100644 --- a/examples/wasm-audio-worklet/src/dependent_module.rs +++ b/examples/wasm-audio-worklet/src/dependent_module.rs @@ -2,25 +2,11 @@ use js_sys::{Array, JsString}; use wasm_bindgen::prelude::*; use web_sys::{Blob, BlobPropertyBag, Url}; -// This is a not-so-clean approach to get the current bindgen ES module URL -// in Rust. This will fail at run time on bindgen targets not using ES modules. -#[wasm_bindgen] -extern "C" { - #[wasm_bindgen] - type ImportMeta; - - #[wasm_bindgen(method, getter)] - fn url(this: &ImportMeta) -> JsString; - - #[wasm_bindgen(js_namespace = import, js_name = meta)] - static IMPORT_META: ImportMeta; -} - pub fn on_the_fly(code: &str) -> Result { // Generate the import of the bindgen ES module, assuming `--target web`: let header = format!( "import init, * as bindgen from '{}';\n\n", - IMPORT_META.url(), + &wasm_bindgen::script_url(), ); Url::create_object_url_with_blob(&Blob::new_with_str_sequence_and_options( diff --git a/src/lib.rs b/src/lib.rs index 7f3e82f7337..ec3fa3ba586 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -972,6 +972,7 @@ externs! { fn __wbindgen_memory() -> u32; fn __wbindgen_module() -> u32; + fn __wbindgen_script_url(ret: *mut [usize; 2]) -> (); fn __wbindgen_function_table() -> u32; } } @@ -1251,6 +1252,20 @@ pub fn memory() -> JsValue { unsafe { JsValue::_new(__wbindgen_memory()) } } +/// Returns the URL to the script that instantiated the wasm module. +/// +/// On some wasm-bindgen targets, this script is a module or a bundle. +/// Also, the returned URL is relative on some wasm-bindgen targets. +#[cfg(feature = "std")] +pub fn script_url() -> String { + unsafe { + let mut ret = [0; 2]; + __wbindgen_script_url(&mut ret); + let data = Vec::from_raw_parts(ret[0] as *mut u8, ret[1], ret[1]); + String::from_utf8_unchecked(data) + } +} + /// Returns a handle to this wasm instance's `WebAssembly.Table` which is the /// indirect function table used by Rust pub fn function_table() -> JsValue {