Merge pull request #2176 from jakobhellermann/deno-target

add deno target
This commit is contained in:
Alex Crichton 2020-06-03 16:20:30 -05:00 committed by GitHub
commit 9c5a6dfff6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 415 additions and 110 deletions

View File

@ -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",

View File

@ -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:

View File

@ -0,0 +1,3 @@
steps:
- script: curl -fsSL https://deno.land/x/install/install.sh | sh
displayName: "install deno"

View File

@ -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(())
} }

View File

@ -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,

View 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),
)
}

View File

@ -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(())
} }

View File

@ -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));

View File

@ -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
View 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
View 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
View 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
View File

@ -0,0 +1 @@
/deno.wasm

View 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
View 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
View File

@ -0,0 +1,3 @@
import { greet } from "./pkg/deno.js";
greet("Deno");

View File

@ -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