diff --git a/crates/cli-support/src/js/mod.rs b/crates/cli-support/src/js/mod.rs index 8450349482d..aef113833c3 100644 --- a/crates/cli-support/src/js/mod.rs +++ b/crates/cli-support/src/js/mod.rs @@ -142,7 +142,7 @@ impl<'a> Context<'a> { self.globals.push_str(c); } let global = match self.config.mode { - OutputMode::Node { module: false } => { + OutputMode::InlineNodeJs | OutputMode::Node { module: false } => { if contents.starts_with("class") { format!("{}\nmodule.exports.{1} = {1};\n", contents, export_name) } else { @@ -291,6 +291,31 @@ impl<'a> Context<'a> { reset_indentation(&shim) } + fn generate_isomorphic_wasm_loading(&mut self) -> String { + let mut shim = String::new(); + + let buf = self.module.emit_wasm(); + + let mut serialized = "const bytes = Buffer.from([".to_string(); + let (last, bytes) = buf.split_last().unwrap(); + for byte in bytes { + serialized.push_str(&format!("{},", byte)); + } + serialized.push_str(&format!("{}", last)); + serialized.push_str("]);"); + shim.push_str(&serialized); + shim.push_str( + " + const wasmModule = new WebAssembly.Module(bytes); + const wasmInstance = new WebAssembly.Instance(wasmModule, imports); + wasm = wasmInstance.exports; + module.exports.__wasm = wasm; + ", + ); + + reset_indentation(&shim) + } + // generates something like // ```js // import * as import0 from './snippets/.../inline1.js'; @@ -500,6 +525,32 @@ impl<'a> Context<'a> { footer.push_str("export { initSync };\n"); footer.push_str("export default __wbg_init;"); } + + OutputMode::InlineNodeJs => { + js.push_str(&self.generate_node_imports()); + + js.push_str("let wasm;\n"); + + for (id, js) in crate::sorted_iter(&self.wasm_import_definitions) { + let import = self.module.imports.get_mut(*id); + footer.push_str("\nmodule.exports."); + footer.push_str(&import.name); + footer.push_str(" = "); + footer.push_str(js.trim()); + footer.push_str(";\n"); + } + + footer.push_str( + &self.generate_node_wasm_loading(Path::new(&format!( + "./{}_bg.wasm", + module_name + ))), + ); + + if needs_manual_start { + footer.push_str("\nwasm.__wbindgen_start();\n"); + } + } } // Before putting the static init code declaration info, put all existing typescript into a `wasm_bindgen` namespace declaration. @@ -568,7 +619,7 @@ impl<'a> Context<'a> { } } - OutputMode::Node { module: false } => { + OutputMode::InlineNodeJs | OutputMode::Node { module: false } => { for (module, items) in crate::sorted_iter(&self.js_imports) { imports.push_str("const { "); for (i, (item, rename)) in items.iter().enumerate() { @@ -1043,7 +1094,7 @@ impl<'a> Context<'a> { */\n toString(): string;\n", ); - if self.config.mode.nodejs() { + if self.config.mode.nodejs() || self.config.mode.inline_nodejs() { // `util.inspect` must be imported in Node.js to define [inspect.custom] let module_name = self.import_name(&JsImport { name: JsImportName::Module { @@ -1522,7 +1573,8 @@ impl<'a> Context<'a> { init: Option<&str>, ) -> Result<(), Error> { match &self.config.mode { - OutputMode::Node { .. } => { + + OutputMode::InlineNodeJs | OutputMode::Node { .. } => { let name = self.import_name(&JsImport { name: JsImportName::Module { module: "util".to_string(), @@ -1555,6 +1607,7 @@ impl<'a> Context<'a> { if let Some(init) = init { match &self.config.mode { OutputMode::Node { .. } + | OutputMode::InlineNodeJs | OutputMode::Bundler { browser_only: false, } => self.global(init), @@ -3244,7 +3297,7 @@ impl<'a> Context<'a> { | OutputMode::Bundler { .. } | OutputMode::Deno | OutputMode::Node { module: true } => "import.meta.url", - OutputMode::Node { module: false } => { + OutputMode::InlineNodeJs | OutputMode::Node { module: false } => { "require('url').pathToFileURL(__filename)" } OutputMode::NoModules { .. } => { diff --git a/crates/cli-support/src/lib.rs b/crates/cli-support/src/lib.rs index 7a3d70cc704..5c08b137faa 100755 --- a/crates/cli-support/src/lib.rs +++ b/crates/cli-support/src/lib.rs @@ -68,6 +68,7 @@ enum OutputMode { NoModules { global: String }, Node { module: bool }, Deno, + InlineNodeJs, } enum Input { @@ -169,6 +170,16 @@ impl Bindgen { Ok(self) } + pub fn inline_nodejs(&mut self, inline_nodejs: bool) -> Result<&mut Bindgen, Error> { + if inline_nodejs { + self.switch_mode( + OutputMode::InlineNodeJs, + "--target experimental-inline-nodejs", + )?; + } + Ok(self) + } + pub fn bundler(&mut self, bundler: bool) -> Result<&mut Bindgen, Error> { if bundler { self.switch_mode( @@ -544,6 +555,10 @@ impl OutputMode { matches!(self, OutputMode::Node { .. }) } + fn inline_nodejs(&self) -> bool { + matches!(self, OutputMode::InlineNodeJs) + } + fn no_modules(&self) -> bool { matches!(self, OutputMode::NoModules { .. }) } diff --git a/crates/cli/src/bin/wasm-bindgen.rs b/crates/cli/src/bin/wasm-bindgen.rs index ee33c8de036..682a32a0248 100644 --- a/crates/cli/src/bin/wasm-bindgen.rs +++ b/crates/cli/src/bin/wasm-bindgen.rs @@ -110,6 +110,7 @@ fn rmain(args: &Args) -> Result<(), Error> { "nodejs" => b.nodejs(true)?, "deno" => b.deno(true)?, "experimental-nodejs-module" => b.nodejs_module(true)?, + "experimental-inline-nodejs" => b.inline_nodejs(true)?, s => bail!("invalid encode-into mode: `{}`", s), }; }