mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-03-15 17:50:51 +00:00
Merge pull request #2176 from jakobhellermann/deno-target
add deno target
This commit is contained in:
commit
9c5a6dfff6
@ -65,6 +65,7 @@ members = [
|
|||||||
"examples/char",
|
"examples/char",
|
||||||
"examples/closures",
|
"examples/closures",
|
||||||
"examples/console_log",
|
"examples/console_log",
|
||||||
|
"examples/deno",
|
||||||
"examples/dom",
|
"examples/dom",
|
||||||
"examples/duck-typed-interfaces",
|
"examples/duck-typed-interfaces",
|
||||||
"examples/fetch",
|
"examples/fetch",
|
||||||
|
@ -167,7 +167,7 @@ jobs:
|
|||||||
- script: mv _package.json package.json && npm install && rm package.json
|
- script: mv _package.json package.json && npm install && rm package.json
|
||||||
displayName: "run npm install"
|
displayName: "run npm install"
|
||||||
- script: |
|
- script: |
|
||||||
for dir in `ls examples | grep -v README | grep -v asm.js | grep -v raytrace | grep -v without-a-bundler | grep -v websockets | grep -v webxr`; do
|
for dir in `ls examples | grep -v README | grep -v asm.js | grep -v raytrace | grep -v without-a-bundler | grep -v websockets | grep -v webxr | grep -v deno`; do
|
||||||
(cd examples/$dir &&
|
(cd examples/$dir &&
|
||||||
ln -fs ../../node_modules . &&
|
ln -fs ../../node_modules . &&
|
||||||
npm run build -- --output-path $BUILD_ARTIFACTSTAGINGDIRECTORY/exbuild/$dir) || exit 1;
|
npm run build -- --output-path $BUILD_ARTIFACTSTAGINGDIRECTORY/exbuild/$dir) || exit 1;
|
||||||
@ -178,6 +178,16 @@ jobs:
|
|||||||
artifactName: examples1
|
artifactName: examples1
|
||||||
targetPath: '$(Build.ArtifactStagingDirectory)'
|
targetPath: '$(Build.ArtifactStagingDirectory)'
|
||||||
|
|
||||||
|
- job: test_deno
|
||||||
|
displayName: "Build and test the deno example"
|
||||||
|
steps:
|
||||||
|
- template: ci/azure-install-rust.yml
|
||||||
|
- script: rustup target add wasm32-unknown-unknown
|
||||||
|
displayName: "install wasm target"
|
||||||
|
- template: ci/azure-install-deno.yml
|
||||||
|
- script: cd examples/deno && ./build.sh && $HOME/.deno/bin/deno run --allow-read test.ts
|
||||||
|
displayName: "build and run deno example"
|
||||||
|
|
||||||
- job: build_raytrace
|
- job: build_raytrace
|
||||||
displayName: "Build raytrace examples"
|
displayName: "Build raytrace examples"
|
||||||
steps:
|
steps:
|
||||||
|
3
ci/azure-install-deno.yml
Normal file
3
ci/azure-install-deno.yml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
steps:
|
||||||
|
- script: curl -fsSL https://deno.land/x/install/install.sh | sh
|
||||||
|
displayName: "install deno"
|
@ -143,7 +143,8 @@ impl<'a> Context<'a> {
|
|||||||
| OutputMode::Node {
|
| OutputMode::Node {
|
||||||
experimental_modules: true,
|
experimental_modules: true,
|
||||||
}
|
}
|
||||||
| OutputMode::Web => {
|
| OutputMode::Web
|
||||||
|
| OutputMode::Deno => {
|
||||||
if contents.starts_with("function") {
|
if contents.starts_with("function") {
|
||||||
let body = &contents[8..];
|
let body = &contents[8..];
|
||||||
if export_name == definition_name {
|
if export_name == definition_name {
|
||||||
@ -269,6 +270,63 @@ impl<'a> Context<'a> {
|
|||||||
reset_indentation(&shim)
|
reset_indentation(&shim)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// generates somthing like
|
||||||
|
// ```js
|
||||||
|
// import * as import0 from './snippets/.../inline1.js';
|
||||||
|
// ```,
|
||||||
|
//
|
||||||
|
// ```js
|
||||||
|
// const imports = {
|
||||||
|
// __wbindgen_placeholder__: {
|
||||||
|
// __wbindgen_throw: function(..) { .. },
|
||||||
|
// ..
|
||||||
|
// },
|
||||||
|
// './snippets/deno-65e2634a84cc3c14/inline1.js': import0,
|
||||||
|
// }
|
||||||
|
// ```
|
||||||
|
fn generate_deno_imports(&self) -> (String, String) {
|
||||||
|
let mut imports = String::new();
|
||||||
|
let mut wasm_import_object = "const imports = {\n".to_string();
|
||||||
|
|
||||||
|
wasm_import_object.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);
|
||||||
|
wasm_import_object.push_str(&format!("{}: {},\n", &import.name, js.trim()));
|
||||||
|
}
|
||||||
|
|
||||||
|
wasm_import_object.push_str("\t},\n");
|
||||||
|
|
||||||
|
// e.g. snippets without parameters
|
||||||
|
let import_modules = self
|
||||||
|
.module
|
||||||
|
.imports
|
||||||
|
.iter()
|
||||||
|
.map(|import| &import.module)
|
||||||
|
.filter(|module| module.as_str() != PLACEHOLDER_MODULE);
|
||||||
|
for (i, module) in import_modules.enumerate() {
|
||||||
|
imports.push_str(&format!("import * as import{} from '{}'\n", i, module));
|
||||||
|
wasm_import_object.push_str(&format!(" '{}': import{},", module, i))
|
||||||
|
}
|
||||||
|
|
||||||
|
wasm_import_object.push_str("\n};\n\n");
|
||||||
|
|
||||||
|
(imports, wasm_import_object)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_deno_wasm_loading(&self, module_name: &str) -> String {
|
||||||
|
// Deno removed support for .wasm imports in https://github.com/denoland/deno/pull/5135
|
||||||
|
// the issue for bringing it back is https://github.com/denoland/deno/issues/5609.
|
||||||
|
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
|
/// Performs the task of actually generating the final JS module, be it
|
||||||
/// `--target no-modules`, `--target web`, or for bundlers. This is the very
|
/// `--target no-modules`, `--target web`, or for bundlers. This is the very
|
||||||
/// last step performed in `finalize`.
|
/// last step performed in `finalize`.
|
||||||
@ -331,6 +389,18 @@ impl<'a> Context<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OutputMode::Deno => {
|
||||||
|
let (js_imports, wasm_import_object) = self.generate_deno_imports();
|
||||||
|
imports.push_str(&js_imports);
|
||||||
|
footer.push_str(&wasm_import_object);
|
||||||
|
|
||||||
|
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
|
// 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
|
// the wasm file as if it were an ES module and let the
|
||||||
// bundler/runtime take care of it.
|
// bundler/runtime take care of it.
|
||||||
@ -443,7 +513,8 @@ impl<'a> Context<'a> {
|
|||||||
| OutputMode::Node {
|
| OutputMode::Node {
|
||||||
experimental_modules: true,
|
experimental_modules: true,
|
||||||
}
|
}
|
||||||
| OutputMode::Web => {
|
| OutputMode::Web
|
||||||
|
| OutputMode::Deno => {
|
||||||
for (module, items) in crate::sorted_iter(&self.js_imports) {
|
for (module, items) in crate::sorted_iter(&self.js_imports) {
|
||||||
imports.push_str("import { ");
|
imports.push_str("import { ");
|
||||||
for (i, (item, rename)) in items.iter().enumerate() {
|
for (i, (item, rename)) in items.iter().enumerate() {
|
||||||
@ -1238,27 +1309,36 @@ impl<'a> Context<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn expose_text_processor(&mut self, s: &str, args: &str) -> Result<(), Error> {
|
fn expose_text_processor(&mut self, s: &str, args: &str) -> Result<(), Error> {
|
||||||
if self.config.mode.nodejs() {
|
match &self.config.mode {
|
||||||
let name = self.import_name(&JsImport {
|
OutputMode::Node { .. } => {
|
||||||
name: JsImportName::Module {
|
let name = self.import_name(&JsImport {
|
||||||
module: "util".to_string(),
|
name: JsImportName::Module {
|
||||||
name: s.to_string(),
|
module: "util".to_string(),
|
||||||
},
|
name: s.to_string(),
|
||||||
fields: Vec::new(),
|
},
|
||||||
})?;
|
fields: Vec::new(),
|
||||||
self.global(&format!("let cached{} = new {}{};", s, name, args));
|
})?;
|
||||||
} else if !self.config.mode.always_run_in_browser() {
|
self.global(&format!("let cached{} = new {}{};", s, name, args));
|
||||||
self.global(&format!(
|
}
|
||||||
"
|
OutputMode::Bundler {
|
||||||
|
browser_only: false,
|
||||||
|
} => {
|
||||||
|
self.global(&format!(
|
||||||
|
"
|
||||||
const l{0} = typeof {0} === 'undefined' ? \
|
const l{0} = typeof {0} === 'undefined' ? \
|
||||||
(0, module.require)('util').{0} : {0};\
|
(0, module.require)('util').{0} : {0};\
|
||||||
",
|
",
|
||||||
s
|
s
|
||||||
));
|
));
|
||||||
self.global(&format!("let cached{0} = new l{0}{1};", s, args));
|
self.global(&format!("let cached{0} = new l{0}{1};", s, args));
|
||||||
} else {
|
}
|
||||||
self.global(&format!("let cached{0} = new {0}{1};", s, args));
|
OutputMode::Deno
|
||||||
}
|
| OutputMode::Web
|
||||||
|
| OutputMode::NoModules { .. }
|
||||||
|
| OutputMode::Bundler { browser_only: true } => {
|
||||||
|
self.global(&format!("let cached{0} = new {0}{1};", s, args))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -74,6 +74,7 @@ enum OutputMode {
|
|||||||
Web,
|
Web,
|
||||||
NoModules { global: String },
|
NoModules { global: String },
|
||||||
Node { experimental_modules: bool },
|
Node { experimental_modules: bool },
|
||||||
|
Deno,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Input {
|
enum Input {
|
||||||
@ -210,6 +211,14 @@ impl Bindgen {
|
|||||||
Ok(self)
|
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> {
|
pub fn no_modules_global(&mut self, name: &str) -> Result<&mut Bindgen, Error> {
|
||||||
match &mut self.mode {
|
match &mut self.mode {
|
||||||
OutputMode::NoModules { global } => *global = name.to_string(),
|
OutputMode::NoModules { global } => *global = name.to_string(),
|
||||||
@ -509,7 +518,8 @@ impl OutputMode {
|
|||||||
| OutputMode::Web
|
| OutputMode::Web
|
||||||
| OutputMode::Node {
|
| OutputMode::Node {
|
||||||
experimental_modules: true,
|
experimental_modules: true,
|
||||||
} => true,
|
}
|
||||||
|
| OutputMode::Deno => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -537,15 +547,6 @@ impl OutputMode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn always_run_in_browser(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
OutputMode::Web => true,
|
|
||||||
OutputMode::NoModules { .. } => true,
|
|
||||||
OutputMode::Bundler { browser_only } => *browser_only,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn web(&self) -> bool {
|
fn web(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
OutputMode::Web => true,
|
OutputMode::Web => true,
|
||||||
|
73
crates/cli/src/bin/wasm-bindgen-test-runner/deno.rs
Normal file
73
crates/cli/src/bin/wasm-bindgen-test-runner/deno.rs
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
use std::ffi::OsString;
|
||||||
|
use std::fs;
|
||||||
|
use std::path::Path;
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
|
use anyhow::{Context, Error};
|
||||||
|
|
||||||
|
use crate::node::{exec, SHARED_SETUP};
|
||||||
|
|
||||||
|
pub fn execute(
|
||||||
|
module: &str,
|
||||||
|
tmpdir: &Path,
|
||||||
|
args: &[OsString],
|
||||||
|
tests: &[String],
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let mut js_to_execute = format!(
|
||||||
|
r#"import * as wasm from "./{0}.js";
|
||||||
|
|
||||||
|
{console_override}
|
||||||
|
|
||||||
|
// global.__wbg_test_invoke = f => f();
|
||||||
|
|
||||||
|
// Forward runtime arguments. These arguments are also arguments to the
|
||||||
|
// `wasm-bindgen-test-runner` which forwards them to deno which we
|
||||||
|
// forward to the test harness. this is basically only used for test
|
||||||
|
// filters for now.
|
||||||
|
cx.args(Deno.args.slice(1));
|
||||||
|
|
||||||
|
const ok = await cx.run(tests.map(n => wasm.__wasm[n]));
|
||||||
|
if (!ok) Deno.exit(1);
|
||||||
|
|
||||||
|
const tests = [];
|
||||||
|
"#,
|
||||||
|
module,
|
||||||
|
console_override = SHARED_SETUP,
|
||||||
|
);
|
||||||
|
|
||||||
|
for test in tests {
|
||||||
|
js_to_execute.push_str(&format!("tests.push('{}')\n", test));
|
||||||
|
}
|
||||||
|
|
||||||
|
let js_path = tmpdir.join("run.js");
|
||||||
|
fs::write(&js_path, js_to_execute).context("failed to write JS file")?;
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Augment `NODE_PATH` so things like `require("tests/my-custom.js")` work
|
||||||
|
// and Rust code can import from custom JS shims. This is a bit of a hack
|
||||||
|
// and should probably be removed at some point.
|
||||||
|
let path = env::var("NODE_PATH").unwrap_or_default();
|
||||||
|
let mut path = env::split_paths(&path).collect::<Vec<_>>();
|
||||||
|
path.push(env::current_dir().unwrap());
|
||||||
|
path.push(tmpdir.to_path_buf());
|
||||||
|
let extra_node_args = env::var("NODE_ARGS")
|
||||||
|
.unwrap_or_default()
|
||||||
|
.split(",")
|
||||||
|
.map(|s| s.to_string())
|
||||||
|
.filter(|s| !s.is_empty())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
exec(
|
||||||
|
Command::new("node")
|
||||||
|
.env("NODE_PATH", env::join_paths(&path).unwrap())
|
||||||
|
.args(&extra_node_args)
|
||||||
|
.arg(&js_path)
|
||||||
|
.args(args),
|
||||||
|
)*/
|
||||||
|
exec(
|
||||||
|
Command::new("deno")
|
||||||
|
.arg("run")
|
||||||
|
.arg("--allow-read")
|
||||||
|
.arg(&js_path)
|
||||||
|
.args(args),
|
||||||
|
)
|
||||||
|
}
|
@ -22,11 +22,19 @@ use wasm_bindgen_cli_support::Bindgen;
|
|||||||
#[global_allocator]
|
#[global_allocator]
|
||||||
static ALLOC: std::alloc::System = std::alloc::System;
|
static ALLOC: std::alloc::System = std::alloc::System;
|
||||||
|
|
||||||
|
mod deno;
|
||||||
mod headless;
|
mod headless;
|
||||||
mod node;
|
mod node;
|
||||||
mod server;
|
mod server;
|
||||||
mod shell;
|
mod shell;
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
|
enum TestMode {
|
||||||
|
Node,
|
||||||
|
Deno,
|
||||||
|
Browser,
|
||||||
|
}
|
||||||
|
|
||||||
fn main() -> anyhow::Result<()> {
|
fn main() -> anyhow::Result<()> {
|
||||||
env_logger::init();
|
env_logger::init();
|
||||||
let mut args = env::args_os().skip(1);
|
let mut args = env::args_os().skip(1);
|
||||||
@ -81,14 +89,21 @@ fn main() -> anyhow::Result<()> {
|
|||||||
// That's done on a per-test-binary basis with the
|
// That's done on a per-test-binary basis with the
|
||||||
// `wasm_bindgen_test_configure` macro, which emits a custom section for us
|
// `wasm_bindgen_test_configure` macro, which emits a custom section for us
|
||||||
// to read later on.
|
// to read later on.
|
||||||
let mut node = true;
|
|
||||||
if let Some(section) = wasm.customs.remove_raw("__wasm_bindgen_test_unstable") {
|
let custom_section = wasm.customs.remove_raw("__wasm_bindgen_test_unstable");
|
||||||
node = !section.data.contains(&0x01);
|
let test_mode = match custom_section {
|
||||||
}
|
Some(section) if section.data.contains(&0x01) => TestMode::Browser,
|
||||||
|
Some(_) => bail!("invalid __wasm_bingen_test_unstable value"),
|
||||||
|
None if std::env::var("WASM_BINDGEN_USE_DENO").is_ok() => TestMode::Deno,
|
||||||
|
None => TestMode::Node,
|
||||||
|
};
|
||||||
|
|
||||||
let headless = env::var("NO_HEADLESS").is_err();
|
let headless = env::var("NO_HEADLESS").is_err();
|
||||||
let debug = env::var("WASM_BINDGEN_NO_DEBUG").is_err();
|
let debug = env::var("WASM_BINDGEN_NO_DEBUG").is_err();
|
||||||
|
|
||||||
// Gracefully handle requests to execute only node or only web tests.
|
// Gracefully handle requests to execute only node or only web tests.
|
||||||
|
let node = test_mode == TestMode::Node;
|
||||||
|
|
||||||
if env::var_os("WASM_BINDGEN_TEST_ONLY_NODE").is_some() {
|
if env::var_os("WASM_BINDGEN_TEST_ONLY_NODE").is_some() {
|
||||||
if !node {
|
if !node {
|
||||||
println!(
|
println!(
|
||||||
@ -131,9 +146,13 @@ integration test.\
|
|||||||
// Make the generated bindings available for the tests to execute against.
|
// Make the generated bindings available for the tests to execute against.
|
||||||
shell.status("Executing bindgen...");
|
shell.status("Executing bindgen...");
|
||||||
let mut b = Bindgen::new();
|
let mut b = Bindgen::new();
|
||||||
|
match test_mode {
|
||||||
|
TestMode::Node => b.nodejs(true)?,
|
||||||
|
TestMode::Deno => b.deno(true)?,
|
||||||
|
TestMode::Browser => b.web(true)?,
|
||||||
|
};
|
||||||
|
|
||||||
b.debug(debug)
|
b.debug(debug)
|
||||||
.nodejs(node)?
|
|
||||||
.web(!node)?
|
|
||||||
.input_module(module, wasm)
|
.input_module(module, wasm)
|
||||||
.keep_debug(false)
|
.keep_debug(false)
|
||||||
.emit_start(false)
|
.emit_start(false)
|
||||||
@ -141,44 +160,45 @@ integration test.\
|
|||||||
.context("executing `wasm-bindgen` over the wasm file")?;
|
.context("executing `wasm-bindgen` over the wasm file")?;
|
||||||
shell.clear();
|
shell.clear();
|
||||||
|
|
||||||
// If we're executing in node.js, that module will take it from here.
|
let args: Vec<_> = args.collect();
|
||||||
if node {
|
|
||||||
return node::execute(&module, &tmpdir, &args.collect::<Vec<_>>(), &tests);
|
match test_mode {
|
||||||
|
TestMode::Node => node::execute(&module, &tmpdir, &args, &tests)?,
|
||||||
|
TestMode::Deno => deno::execute(&module, &tmpdir, &args, &tests)?,
|
||||||
|
TestMode::Browser => {
|
||||||
|
let srv = server::spawn(
|
||||||
|
&if headless {
|
||||||
|
"127.0.0.1:0".parse().unwrap()
|
||||||
|
} else {
|
||||||
|
"127.0.0.1:8000".parse().unwrap()
|
||||||
|
},
|
||||||
|
headless,
|
||||||
|
&module,
|
||||||
|
&tmpdir,
|
||||||
|
&args,
|
||||||
|
&tests,
|
||||||
|
)
|
||||||
|
.context("failed to spawn server")?;
|
||||||
|
let addr = srv.server_addr();
|
||||||
|
|
||||||
|
// TODO: eventually we should provide the ability to exit at some point
|
||||||
|
// (gracefully) here, but for now this just runs forever.
|
||||||
|
if !headless {
|
||||||
|
println!(
|
||||||
|
"Interactive browsers tests are now available at http://{}",
|
||||||
|
addr
|
||||||
|
);
|
||||||
|
println!("");
|
||||||
|
println!("Note that interactive mode is enabled because `NO_HEADLESS`");
|
||||||
|
println!("is specified in the environment of this process. Once you're");
|
||||||
|
println!("done with testing you'll need to kill this server with");
|
||||||
|
println!("Ctrl-C.");
|
||||||
|
return Ok(srv.run());
|
||||||
|
}
|
||||||
|
|
||||||
|
thread::spawn(|| srv.run());
|
||||||
|
headless::run(&addr, &shell, timeout)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise we're executing in a browser. Spawn a server which serves up
|
|
||||||
// the local generated files over an HTTP server.
|
|
||||||
let srv = server::spawn(
|
|
||||||
&if headless {
|
|
||||||
"127.0.0.1:0".parse().unwrap()
|
|
||||||
} else {
|
|
||||||
"127.0.0.1:8000".parse().unwrap()
|
|
||||||
},
|
|
||||||
headless,
|
|
||||||
&module,
|
|
||||||
&tmpdir,
|
|
||||||
&args.collect::<Vec<_>>(),
|
|
||||||
&tests,
|
|
||||||
)
|
|
||||||
.context("failed to spawn server")?;
|
|
||||||
let addr = srv.server_addr();
|
|
||||||
|
|
||||||
// TODO: eventually we should provide the ability to exit at some point
|
|
||||||
// (gracefully) here, but for now this just runs forever.
|
|
||||||
if !headless {
|
|
||||||
println!(
|
|
||||||
"Interactive browsers tests are now available at http://{}",
|
|
||||||
addr
|
|
||||||
);
|
|
||||||
println!("");
|
|
||||||
println!("Note that interactive mode is enabled because `NO_HEADLESS`");
|
|
||||||
println!("is specified in the environment of this process. Once you're");
|
|
||||||
println!("done with testing you'll need to kill this server with");
|
|
||||||
println!("Ctrl-C.");
|
|
||||||
return Ok(srv.run());
|
|
||||||
}
|
|
||||||
|
|
||||||
thread::spawn(|| srv.run());
|
|
||||||
headless::run(&addr, &shell, timeout)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,38 @@ use std::process::Command;
|
|||||||
|
|
||||||
use anyhow::{Context, Error};
|
use anyhow::{Context, Error};
|
||||||
|
|
||||||
|
// depends on the variable 'wasm' and initializes te WasmBindgenTestContext cx
|
||||||
|
pub const SHARED_SETUP: &str = r#"
|
||||||
|
const handlers = {};
|
||||||
|
|
||||||
|
const wrap = method => {
|
||||||
|
const og = console[method];
|
||||||
|
const on_method = `on_console_${method}`;
|
||||||
|
console[method] = function (...args) {
|
||||||
|
og.apply(this, args);
|
||||||
|
if (handlers[on_method]) {
|
||||||
|
handlers[on_method](args);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// override `console.log` and `console.error` etc... before we import tests to
|
||||||
|
// ensure they're bound correctly in wasm. This'll allow us to intercept
|
||||||
|
// all these calls and capture the output of tests
|
||||||
|
wrap("debug");
|
||||||
|
wrap("log");
|
||||||
|
wrap("info");
|
||||||
|
wrap("warn");
|
||||||
|
wrap("error");
|
||||||
|
|
||||||
|
cx = new wasm.WasmBindgenTestContext();
|
||||||
|
handlers.on_console_debug = wasm.__wbgtest_console_debug;
|
||||||
|
handlers.on_console_log = wasm.__wbgtest_console_log;
|
||||||
|
handlers.on_console_info = wasm.__wbgtest_console_info;
|
||||||
|
handlers.on_console_warn = wasm.__wbgtest_console_warn;
|
||||||
|
handlers.on_console_error = wasm.__wbgtest_console_error;
|
||||||
|
"#;
|
||||||
|
|
||||||
pub fn execute(
|
pub fn execute(
|
||||||
module: &str,
|
module: &str,
|
||||||
tmpdir: &Path,
|
tmpdir: &Path,
|
||||||
@ -15,41 +47,13 @@ pub fn execute(
|
|||||||
let mut js_to_execute = format!(
|
let mut js_to_execute = format!(
|
||||||
r#"
|
r#"
|
||||||
const {{ exit }} = require('process');
|
const {{ exit }} = require('process');
|
||||||
|
const wasm = require("./{0}");
|
||||||
|
|
||||||
const handlers = {{}};
|
{console_override}
|
||||||
|
|
||||||
const wrap = method => {{
|
|
||||||
const og = console[method];
|
|
||||||
const on_method = `on_console_${{method}}`;
|
|
||||||
console[method] = function (...args) {{
|
|
||||||
og.apply(this, args);
|
|
||||||
if (handlers[on_method]) {{
|
|
||||||
handlers[on_method](args);
|
|
||||||
}}
|
|
||||||
}};
|
|
||||||
}};
|
|
||||||
|
|
||||||
// override `console.log` and `console.error` etc... before we import tests to
|
|
||||||
// ensure they're bound correctly in wasm. This'll allow us to intercept
|
|
||||||
// all these calls and capture the output of tests
|
|
||||||
wrap("debug");
|
|
||||||
wrap("log");
|
|
||||||
wrap("info");
|
|
||||||
wrap("warn");
|
|
||||||
wrap("error");
|
|
||||||
|
|
||||||
global.__wbg_test_invoke = f => f();
|
global.__wbg_test_invoke = f => f();
|
||||||
|
|
||||||
async function main(tests) {{
|
async function main(tests) {{
|
||||||
const wasm = require("./{0}");
|
|
||||||
|
|
||||||
cx = new wasm.WasmBindgenTestContext();
|
|
||||||
handlers.on_console_debug = wasm.__wbgtest_console_debug;
|
|
||||||
handlers.on_console_log = wasm.__wbgtest_console_log;
|
|
||||||
handlers.on_console_info = wasm.__wbgtest_console_info;
|
|
||||||
handlers.on_console_warn = wasm.__wbgtest_console_warn;
|
|
||||||
handlers.on_console_error = wasm.__wbgtest_console_error;
|
|
||||||
|
|
||||||
// Forward runtime arguments. These arguments are also arguments to the
|
// Forward runtime arguments. These arguments are also arguments to the
|
||||||
// `wasm-bindgen-test-runner` which forwards them to node which we
|
// `wasm-bindgen-test-runner` which forwards them to node which we
|
||||||
// forward to the test harness. this is basically only used for test
|
// forward to the test harness. this is basically only used for test
|
||||||
@ -63,7 +67,8 @@ pub fn execute(
|
|||||||
|
|
||||||
const tests = [];
|
const tests = [];
|
||||||
"#,
|
"#,
|
||||||
module
|
module,
|
||||||
|
console_override = SHARED_SETUP,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Note that we're collecting *JS objects* that represent the functions to
|
// Note that we're collecting *JS objects* that represent the functions to
|
||||||
@ -109,7 +114,7 @@ pub fn execute(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
fn exec(cmd: &mut Command) -> Result<(), Error> {
|
pub fn exec(cmd: &mut Command) -> Result<(), Error> {
|
||||||
use std::os::unix::prelude::*;
|
use std::os::unix::prelude::*;
|
||||||
Err(Error::from(cmd.exec())
|
Err(Error::from(cmd.exec())
|
||||||
.context("failed to execute `node`")
|
.context("failed to execute `node`")
|
||||||
@ -117,7 +122,7 @@ fn exec(cmd: &mut Command) -> Result<(), Error> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
fn exec(cmd: &mut Command) -> Result<(), Error> {
|
pub fn exec(cmd: &mut Command) -> Result<(), Error> {
|
||||||
use std::process;
|
use std::process;
|
||||||
let status = cmd.status()?;
|
let status = cmd.status()?;
|
||||||
process::exit(status.code().unwrap_or(3));
|
process::exit(status.code().unwrap_or(3));
|
||||||
|
@ -22,7 +22,7 @@ Options:
|
|||||||
--out-dir DIR Output directory
|
--out-dir DIR Output directory
|
||||||
--out-name VAR Set a custom output filename (Without extension. Defaults to crate name)
|
--out-name VAR Set a custom output filename (Without extension. Defaults to crate name)
|
||||||
--target TARGET What type of output to generate, valid
|
--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]
|
and the default is [bundler]
|
||||||
--no-modules-global VAR Name of the global variable to initialize
|
--no-modules-global VAR Name of the global variable to initialize
|
||||||
--browser Hint that JS should only be compatible with a browser
|
--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)?,
|
"web" => b.web(true)?,
|
||||||
"no-modules" => b.no_modules(true)?,
|
"no-modules" => b.no_modules(true)?,
|
||||||
"nodejs" => b.nodejs(true)?,
|
"nodejs" => b.nodejs(true)?,
|
||||||
|
"deno" => b.deno(true)?,
|
||||||
s => bail!("invalid encode-into mode: `{}`", s),
|
s => bail!("invalid encode-into mode: `{}`", s),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
11
examples/deno/Cargo.toml
Normal file
11
examples/deno/Cargo.toml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
[package]
|
||||||
|
name = "deno"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["The wasm-bindgen Developers"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
wasm-bindgen = "0.2.63"
|
16
examples/deno/README.md
Normal file
16
examples/deno/README.md
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# Using deno
|
||||||
|
|
||||||
|
You can build the example with
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ ./build.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
and test it with
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ deno run --allow-read test.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
The `--allow-read` flag is needed because the wasm file is read during runtime.
|
||||||
|
This will be fixed when https://github.com/denoland/deno/issues/5609 is resolved.
|
7
examples/deno/build.sh
Executable file
7
examples/deno/build.sh
Executable file
@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -eux
|
||||||
|
|
||||||
|
cargo build --target wasm32-unknown-unknown --release
|
||||||
|
cargo run --package wasm-bindgen-cli --bin wasm-bindgen -- \
|
||||||
|
--out-dir pkg --target deno ${CARGO_TARGET_DIR:-../../target}/wasm32-unknown-unknown/release/deno.wasm
|
1
examples/deno/crate/.gitignore
vendored
Normal file
1
examples/deno/crate/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/deno.wasm
|
17
examples/deno/defined-in-js.js
Normal file
17
examples/deno/defined-in-js.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
export class MyClass {
|
||||||
|
constructor() {
|
||||||
|
this._number = 42;
|
||||||
|
}
|
||||||
|
|
||||||
|
get number() {
|
||||||
|
return this._number;
|
||||||
|
}
|
||||||
|
|
||||||
|
set number(n) {
|
||||||
|
return (this._number = n);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return `My number is: ${this.number}`;
|
||||||
|
}
|
||||||
|
}
|
42
examples/deno/src/lib.rs
Normal file
42
examples/deno/src/lib.rs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
|
#[wasm_bindgen(module = "/defined-in-js.js")]
|
||||||
|
extern "C" {
|
||||||
|
type MyClass;
|
||||||
|
|
||||||
|
#[wasm_bindgen(constructor)]
|
||||||
|
fn new() -> MyClass;
|
||||||
|
|
||||||
|
#[wasm_bindgen(method, getter)]
|
||||||
|
fn number(this: &MyClass) -> u32;
|
||||||
|
#[wasm_bindgen(method, setter)]
|
||||||
|
fn set_number(this: &MyClass, number: u32) -> MyClass;
|
||||||
|
#[wasm_bindgen(method)]
|
||||||
|
fn render(this: &MyClass) -> String;
|
||||||
|
}
|
||||||
|
|
||||||
|
// lifted from the `console_log` example
|
||||||
|
#[wasm_bindgen]
|
||||||
|
extern "C" {
|
||||||
|
#[wasm_bindgen(js_namespace = console)]
|
||||||
|
fn log(s: &str);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen(inline_js = "export function add(a, b) { return a + b; }")]
|
||||||
|
extern "C" {
|
||||||
|
fn add(a: u32, b: u32) -> u32;
|
||||||
|
}
|
||||||
|
#[wasm_bindgen(inline_js = "export function test() {}")]
|
||||||
|
extern "C" {
|
||||||
|
fn test();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn greet(name: String) {
|
||||||
|
log(&format!("Hello from {}!", name)); // should output "Hello from Rust!"
|
||||||
|
|
||||||
|
let x = MyClass::new();
|
||||||
|
assert_eq!(x.number(), add(40, 2));
|
||||||
|
test();
|
||||||
|
log(&x.render());
|
||||||
|
}
|
3
examples/deno/test.ts
Normal file
3
examples/deno/test.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import { greet } from "./pkg/deno.js";
|
||||||
|
|
||||||
|
greet("Deno");
|
@ -14,12 +14,14 @@ should behave the same way in this respect. The values possible here are:
|
|||||||
| [`bundler`] | Suitable for loading in bundlers like Webpack |
|
| [`bundler`] | Suitable for loading in bundlers like Webpack |
|
||||||
| [`web`] | Directly loadable in a web browser |
|
| [`web`] | Directly loadable in a web browser |
|
||||||
| [`nodejs`] | Loadable via `require` as a Node.js module |
|
| [`nodejs`] | Loadable via `require` as a Node.js module |
|
||||||
|
| [`deno`] | Loadable using imports from Deno modules |
|
||||||
| [`no-modules`] | Like `web`, but older and doesn't use ES modules |
|
| [`no-modules`] | Like `web`, but older and doesn't use ES modules |
|
||||||
|
|
||||||
[`bundler`]: #bundlers
|
[`bundler`]: #bundlers
|
||||||
[`web`]: #without-a-bundler
|
[`web`]: #without-a-bundler
|
||||||
[`no-modules`]: #without-a-bundler
|
[`no-modules`]: #without-a-bundler
|
||||||
[`nodejs`]: #nodejs
|
[`nodejs`]: #nodejs
|
||||||
|
[`deno`]: #Deno
|
||||||
|
|
||||||
## Bundlers
|
## Bundlers
|
||||||
|
|
||||||
@ -69,7 +71,7 @@ documentation, but the highlights of this output are:
|
|||||||
The CLI also supports an output mode called `--target no-modules` which is
|
The CLI also supports an output mode called `--target no-modules` which is
|
||||||
similar to the `web` target in that it requires manual initialization of the
|
similar to the `web` target in that it requires manual initialization of the
|
||||||
wasm and is intended to be included in web pages without any further
|
wasm and is intended to be included in web pages without any further
|
||||||
postprocessing. See the [without a bundler example][nomex] for some more
|
postprocessing. See the [without a bundler example][nomex] for some more
|
||||||
information about `--target no-modules`.
|
information about `--target no-modules`.
|
||||||
|
|
||||||
## Node.js
|
## Node.js
|
||||||
@ -88,6 +90,18 @@ as it has a JS shim generated as well).
|
|||||||
Note that this method requires a version of Node.js with WebAssembly support,
|
Note that this method requires a version of Node.js with WebAssembly support,
|
||||||
which is currently Node 8 and above.
|
which is currently Node 8 and above.
|
||||||
|
|
||||||
|
## Deno
|
||||||
|
|
||||||
|
**`--target deno`**
|
||||||
|
|
||||||
|
To deploy WebAssembly to Deno, use the `--target deno` flag.
|
||||||
|
To then import your module inside deno, use
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// @deno-types="./out/crate_name.d.ts"
|
||||||
|
import { yourFunction } from "./out/crate_name.js";
|
||||||
|
```
|
||||||
|
|
||||||
## NPM
|
## NPM
|
||||||
|
|
||||||
If you'd like to deploy compiled WebAssembly to NPM, then the tool for the job
|
If you'd like to deploy compiled WebAssembly to NPM, then the tool for the job
|
||||||
|
Loading…
x
Reference in New Issue
Block a user