diff --git a/crates/cli-support/src/js/mod.rs b/crates/cli-support/src/js/mod.rs index 4444d1ef..a26a489d 100644 --- a/crates/cli-support/src/js/mod.rs +++ b/crates/cli-support/src/js/mod.rs @@ -143,7 +143,8 @@ impl<'a> Context<'a> { | OutputMode::Node { experimental_modules: true, } - | OutputMode::Web => { + | OutputMode::Web + | OutputMode::Deno => { if contents.starts_with("function") { let body = &contents[8..]; if export_name == definition_name { @@ -269,6 +270,40 @@ impl<'a> Context<'a> { reset_indentation(&shim) } + // generates somthing like + // ```js + // const imports = { + // __wbindgen_placeholder__: { + // __wbindgen_throw: function(..) { .. }, + // .. + // } + // } + // ``` + fn generate_deno_imports(&self) -> String { + let mut imports = "const imports = {\n".to_string(); + imports.push_str(&format!(" {}: {{\n", crate::PLACEHOLDER_MODULE)); + + for (id, js) in crate::sorted_iter(&self.wasm_import_definitions) { + let import = self.module.imports.get(*id); + imports.push_str(&format!("{}: {},\n", &import.name, js.trim())); + } + + imports.push_str("\t}\n};\n\n"); + + imports + } + + fn generate_deno_wasm_loading(&self, module_name: &str) -> String { + format!( + "const file = new URL(import.meta.url).pathname; + const wasmFile = file.substring(0, file.lastIndexOf(Deno.build.os === 'windows' ? '\\\\' : '/') + 1) + '{}_bg.wasm'; + const wasmModule = new WebAssembly.Module(Deno.readFileSync(wasmFile)); + const wasmInstance = new WebAssembly.Instance(wasmModule, imports); + const wasm = wasmInstance.exports;", + module_name + ) + } + /// Performs the task of actually generating the final JS module, be it /// `--target no-modules`, `--target web`, or for bundlers. This is the very /// last step performed in `finalize`. @@ -331,6 +366,15 @@ impl<'a> Context<'a> { } } + OutputMode::Deno => { + footer.push_str(&self.generate_deno_imports()); + footer.push_str(&self.generate_deno_wasm_loading(module_name)); + + if needs_manual_start { + footer.push_str("wasm.__wbindgen_start();\n"); + } + } + // With Bundlers and modern ES6 support in Node we can simply import // the wasm file as if it were an ES module and let the // bundler/runtime take care of it. @@ -443,7 +487,8 @@ impl<'a> Context<'a> { | OutputMode::Node { experimental_modules: true, } - | OutputMode::Web => { + | OutputMode::Web + | OutputMode::Deno => { for (module, items) in crate::sorted_iter(&self.js_imports) { imports.push_str("import { "); for (i, (item, rename)) in items.iter().enumerate() { @@ -1247,7 +1292,7 @@ impl<'a> Context<'a> { fields: Vec::new(), })?; self.global(&format!("let cached{} = new {}{};", s, name, args)); - } else if !self.config.mode.always_run_in_browser() { + } else if !self.config.mode.always_run_in_browser() && !self.config.mode.deno() { self.global(&format!( " const l{0} = typeof {0} === 'undefined' ? \ diff --git a/crates/cli-support/src/lib.rs b/crates/cli-support/src/lib.rs index dd2979f1..ffbed9c1 100755 --- a/crates/cli-support/src/lib.rs +++ b/crates/cli-support/src/lib.rs @@ -74,6 +74,7 @@ enum OutputMode { Web, NoModules { global: String }, Node { experimental_modules: bool }, + Deno, } enum Input { @@ -210,6 +211,14 @@ impl Bindgen { Ok(self) } + pub fn deno(&mut self, deno: bool) -> Result<&mut Bindgen, Error> { + if deno { + self.switch_mode(OutputMode::Deno, "--target deno")?; + self.encode_into(EncodeInto::Always); + } + Ok(self) + } + pub fn no_modules_global(&mut self, name: &str) -> Result<&mut Bindgen, Error> { match &mut self.mode { OutputMode::NoModules { global } => *global = name.to_string(), @@ -526,7 +535,8 @@ impl OutputMode { | OutputMode::Web | OutputMode::Node { experimental_modules: true, - } => true, + } + | OutputMode::Deno => true, _ => false, } } @@ -570,6 +580,13 @@ impl OutputMode { } } + fn deno(&self) -> bool { + match self { + OutputMode::Deno { .. } => true, + _ => false, + } + } + fn esm_integration(&self) -> bool { match self { OutputMode::Bundler { .. } diff --git a/crates/cli/src/bin/wasm-bindgen.rs b/crates/cli/src/bin/wasm-bindgen.rs index 9e9969a6..6a633c0b 100644 --- a/crates/cli/src/bin/wasm-bindgen.rs +++ b/crates/cli/src/bin/wasm-bindgen.rs @@ -22,7 +22,7 @@ Options: --out-dir DIR Output directory --out-name VAR Set a custom output filename (Without extension. Defaults to crate name) --target TARGET What type of output to generate, valid - values are [web, bundler, nodejs, no-modules], + values are [web, bundler, nodejs, no-modules, deno], and the default is [bundler] --no-modules-global VAR Name of the global variable to initialize --browser Hint that JS should only be compatible with a browser @@ -98,6 +98,7 @@ fn rmain(args: &Args) -> Result<(), Error> { "web" => b.web(true)?, "no-modules" => b.no_modules(true)?, "nodejs" => b.nodejs(true)?, + "deno" => b.deno(true)?, s => bail!("invalid encode-into mode: `{}`", s), }; }