Add an option to detect node at runtime

Sometimes builds are done once and used in both the browser and in node, so add
an option to do runtime detection if necessary
This commit is contained in:
Alex Crichton 2018-03-07 08:50:56 -08:00
parent 48c0f290f9
commit 8254d9f516
5 changed files with 59 additions and 14 deletions

View File

@ -15,6 +15,7 @@ pub struct Project {
files: Vec<(String, String)>, files: Vec<(String, String)>,
debug: bool, debug: bool,
js: bool, js: bool,
detect_node: bool,
} }
pub fn project() -> Project { pub fn project() -> Project {
@ -28,6 +29,7 @@ pub fn project() -> Project {
Project { Project {
debug: true, debug: true,
js: false, js: false,
detect_node: false,
files: vec![ files: vec![
("Cargo.toml".to_string(), format!(r#" ("Cargo.toml".to_string(), format!(r#"
[package] [package]
@ -130,6 +132,11 @@ impl Project {
self self
} }
pub fn detect_node(&mut self, detect_node: bool) -> &mut Project {
self.detect_node = detect_node;
self
}
pub fn js(&mut self, js: bool) -> &mut Project { pub fn js(&mut self, js: bool) -> &mut Project {
self.js = js; self.js = js;
self self
@ -171,6 +178,7 @@ impl Project {
cli::Bindgen::new() cli::Bindgen::new()
.input_path(&as_a_module) .input_path(&as_a_module)
.nodejs(true) .nodejs(true)
.nodejs_runtime_detect(self.detect_node)
.typescript(true) .typescript(true)
.debug(self.debug) .debug(self.debug)
.generate(&root) .generate(&root)

View File

@ -517,9 +517,9 @@ impl<'a> Context<'a> {
return return
} }
self.required_internal_exports.insert("__wbindgen_malloc"); self.required_internal_exports.insert("__wbindgen_malloc");
if self.config.nodejs { if self.config.nodejs_runtime_detect || self.config.nodejs {
self.globals.push_str(&format!(" self.globals.push_str(&format!("
function passStringToWasm(arg) {{ function passStringToWasmNode(arg) {{
if (typeof(arg) !== 'string') if (typeof(arg) !== 'string')
throw new Error('expected a string argument'); throw new Error('expected a string argument');
const buf = Buffer.from(arg); const buf = Buffer.from(arg);
@ -529,11 +529,12 @@ impl<'a> Context<'a> {
return [ptr, len]; return [ptr, len];
}} }}
")); "));
} else { }
if self.config.nodejs_runtime_detect || !self.config.nodejs {
self.expose_text_encoder(); self.expose_text_encoder();
self.expose_uint8_memory(); self.expose_uint8_memory();
self.globals.push_str(&format!(" self.globals.push_str(&format!("
function passStringToWasm(arg) {{ function passStringToWasmBrowser(arg) {{
if (typeof(arg) !== 'string') if (typeof(arg) !== 'string')
throw new Error('expected a string argument'); throw new Error('expected a string argument');
const buf = textEncoder().encode(arg); const buf = textEncoder().encode(arg);
@ -544,6 +545,18 @@ impl<'a> Context<'a> {
}} }}
")); "));
} }
if self.config.nodejs_runtime_detect {
self.globals.push_str("
let passStringToWasm = passStringToWasmBrowser;
if (typeof window === 'undefined')
passStringToWasm = passStringToWasmNode;
");
} else if self.config.nodejs {
self.globals.push_str("const passStringToWasm = passStringToWasmNode;\n");
} else {
self.globals.push_str("const passStringToWasm = passStringToWasmBrowser;\n");
}
} }
fn expose_pass_array8_to_wasm(&mut self) { fn expose_pass_array8_to_wasm(&mut self) {
@ -653,19 +666,20 @@ impl<'a> Context<'a> {
if !self.exposed_globals.insert("get_string_from_wasm") { if !self.exposed_globals.insert("get_string_from_wasm") {
return return
} }
if self.config.nodejs { if self.config.nodejs_runtime_detect || self.config.nodejs {
self.globals.push_str(&format!(" self.globals.push_str(&format!("
function getStringFromWasm(ptr, len) {{ function getStringFromWasmNode(ptr, len) {{
const buf = Buffer.from(wasm.memory.buffer).slice(ptr, ptr + len); const buf = Buffer.from(wasm.memory.buffer).slice(ptr, ptr + len);
const ret = buf.toString(); const ret = buf.toString();
return ret; return ret;
}} }}
")); "));
} else { }
if self.config.nodejs_runtime_detect || !self.config.nodejs {
self.expose_text_decoder(); self.expose_text_decoder();
self.expose_uint8_memory(); self.expose_uint8_memory();
self.globals.push_str(&format!(" self.globals.push_str(&format!("
function getStringFromWasm(ptr, len) {{ function getStringFromWasmBrowser(ptr, len) {{
const mem = getUint8Memory(); const mem = getUint8Memory();
const slice = mem.slice(ptr, ptr + len); const slice = mem.slice(ptr, ptr + len);
const ret = textDecoder().decode(slice); const ret = textDecoder().decode(slice);
@ -673,6 +687,18 @@ impl<'a> Context<'a> {
}} }}
")); "));
} }
if self.config.nodejs_runtime_detect {
self.globals.push_str("
let getStringFromWasm = getStringFromWasmBrowser;
if (typeof window === 'undefined')
getStringFromWasm = getStringFromWasmNode;
");
} else if self.config.nodejs {
self.globals.push_str("const getStringFromWasm = getStringFromWasmNode;\n");
} else {
self.globals.push_str("const getStringFromWasm = getStringFromWasmBrowser;\n");
}
} }
fn expose_get_array_js_value_from_wasm(&mut self) { fn expose_get_array_js_value_from_wasm(&mut self) {

View File

@ -17,6 +17,7 @@ pub mod wasm2es6js;
pub struct Bindgen { pub struct Bindgen {
path: Option<PathBuf>, path: Option<PathBuf>,
nodejs: bool, nodejs: bool,
nodejs_runtime_detect: bool,
debug: bool, debug: bool,
typescript: bool, typescript: bool,
} }
@ -35,6 +36,7 @@ impl Bindgen {
Bindgen { Bindgen {
path: None, path: None,
nodejs: false, nodejs: false,
nodejs_runtime_detect: false,
debug: false, debug: false,
typescript: false, typescript: false,
} }
@ -50,6 +52,11 @@ impl Bindgen {
self self
} }
pub fn nodejs_runtime_detect(&mut self, detect: bool) -> &mut Bindgen {
self.nodejs_runtime_detect = detect;
self
}
pub fn debug(&mut self, debug: bool) -> &mut Bindgen { pub fn debug(&mut self, debug: bool) -> &mut Bindgen {
self.debug = debug; self.debug = debug;
self self

View File

@ -21,6 +21,7 @@ Options:
-h --help Show this screen. -h --help Show this screen.
--out-dir DIR Output directory --out-dir DIR Output directory
--nodejs Generate output for node.js, not the browser --nodejs Generate output for node.js, not the browser
--nodejs-runtime-detect Detect at runtime whether we're in node or a browser
--typescript Output a TypeScript definition file --typescript Output a TypeScript definition file
--debug Include otherwise-extraneous debug checks in output --debug Include otherwise-extraneous debug checks in output
-V --version Print the version number of wasm-bindgen -V --version Print the version number of wasm-bindgen
@ -29,6 +30,7 @@ Options:
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
struct Args { struct Args {
flag_nodejs: bool, flag_nodejs: bool,
flag_nodejs_runtime_detect: bool,
flag_typescript: bool, flag_typescript: bool,
flag_out_dir: Option<PathBuf>, flag_out_dir: Option<PathBuf>,
flag_debug: bool, flag_debug: bool,
@ -54,6 +56,7 @@ fn main() {
let mut b = Bindgen::new(); let mut b = Bindgen::new();
b.input_path(&input) b.input_path(&input)
.nodejs(args.flag_nodejs) .nodejs(args.flag_nodejs)
.nodejs_runtime_detect(args.flag_nodejs_runtime_detect)
.debug(args.flag_debug) .debug(args.flag_debug)
.typescript(args.flag_typescript); .typescript(args.flag_typescript);

View File

@ -3,6 +3,7 @@ extern crate test_support;
#[test] #[test]
fn works() { fn works() {
test_support::project() test_support::project()
.detect_node(true)
.file("src/lib.rs", r#" .file("src/lib.rs", r#"
#![feature(proc_macro)] #![feature(proc_macro)]