diff --git a/Cargo.toml b/Cargo.toml index 05d3fe82..505c98b2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -65,6 +65,7 @@ members = [ "examples/char", "examples/closures", "examples/console_log", + "examples/deno", "examples/dom", "examples/duck-typed-interfaces", "examples/fetch", diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 968a12fb..10d29b26 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -167,7 +167,7 @@ jobs: - script: mv _package.json package.json && npm install && rm package.json displayName: "run npm install" - 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 && ln -fs ../../node_modules . && npm run build -- --output-path $BUILD_ARTIFACTSTAGINGDIRECTORY/exbuild/$dir) || exit 1; @@ -178,6 +178,16 @@ jobs: artifactName: examples1 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 displayName: "Build raytrace examples" steps: diff --git a/ci/azure-install-deno.yml b/ci/azure-install-deno.yml new file mode 100644 index 00000000..b995c7c8 --- /dev/null +++ b/ci/azure-install-deno.yml @@ -0,0 +1,3 @@ +steps: + - script: curl -fsSL https://deno.land/x/install/install.sh | sh + displayName: "install deno" diff --git a/crates/cli-support/src/js/mod.rs b/crates/cli-support/src/js/mod.rs index a26a489d..60a6b2a5 100644 --- a/crates/cli-support/src/js/mod.rs +++ b/crates/cli-support/src/js/mod.rs @@ -294,6 +294,8 @@ impl<'a> Context<'a> { } 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'; @@ -1283,27 +1285,36 @@ impl<'a> Context<'a> { } fn expose_text_processor(&mut self, s: &str, args: &str) -> Result<(), Error> { - if self.config.mode.nodejs() { - let name = self.import_name(&JsImport { - name: JsImportName::Module { - module: "util".to_string(), - name: s.to_string(), - }, - fields: Vec::new(), - })?; - self.global(&format!("let cached{} = new {}{};", s, name, args)); - } else if !self.config.mode.always_run_in_browser() && !self.config.mode.deno() { - self.global(&format!( - " + match &self.config.mode { + OutputMode::Node { .. } => { + let name = self.import_name(&JsImport { + name: JsImportName::Module { + module: "util".to_string(), + name: s.to_string(), + }, + fields: Vec::new(), + })?; + self.global(&format!("let cached{} = new {}{};", s, name, args)); + } + OutputMode::Bundler { + browser_only: false, + } => { + self.global(&format!( + " const l{0} = typeof {0} === 'undefined' ? \ (0, module.require)('util').{0} : {0};\ ", - s - )); - self.global(&format!("let cached{0} = new l{0}{1};", s, args)); - } else { - self.global(&format!("let cached{0} = new {0}{1};", s, args)); - } + s + )); + self.global(&format!("let cached{0} = new l{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(()) } diff --git a/crates/cli-support/src/lib.rs b/crates/cli-support/src/lib.rs index ffbed9c1..1e73d534 100755 --- a/crates/cli-support/src/lib.rs +++ b/crates/cli-support/src/lib.rs @@ -564,15 +564,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 { match self { OutputMode::Web => true, @@ -580,13 +571,6 @@ impl OutputMode { } } - fn deno(&self) -> bool { - match self { - OutputMode::Deno { .. } => true, - _ => false, - } - } - fn esm_integration(&self) -> bool { match self { OutputMode::Bundler { .. } diff --git a/examples/deno/Cargo.toml b/examples/deno/Cargo.toml new file mode 100644 index 00000000..b296e909 --- /dev/null +++ b/examples/deno/Cargo.toml @@ -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" diff --git a/examples/deno/README.md b/examples/deno/README.md new file mode 100644 index 00000000..3df58384 --- /dev/null +++ b/examples/deno/README.md @@ -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. diff --git a/examples/deno/build.sh b/examples/deno/build.sh new file mode 100755 index 00000000..722cb11f --- /dev/null +++ b/examples/deno/build.sh @@ -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 diff --git a/examples/deno/crate/.gitignore b/examples/deno/crate/.gitignore new file mode 100644 index 00000000..09c2139a --- /dev/null +++ b/examples/deno/crate/.gitignore @@ -0,0 +1 @@ +/deno.wasm diff --git a/examples/deno/defined-in-js.js b/examples/deno/defined-in-js.js new file mode 100644 index 00000000..51490b86 --- /dev/null +++ b/examples/deno/defined-in-js.js @@ -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}`; + } +} diff --git a/examples/deno/src/lib.rs b/examples/deno/src/lib.rs new file mode 100644 index 00000000..bee2ec64 --- /dev/null +++ b/examples/deno/src/lib.rs @@ -0,0 +1,37 @@ +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] +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)); + log(&x.render()); +} diff --git a/examples/deno/test.ts b/examples/deno/test.ts new file mode 100644 index 00000000..e61a3133 --- /dev/null +++ b/examples/deno/test.ts @@ -0,0 +1,3 @@ +import { greet } from "./pkg/deno.js"; + +greet("Deno"); diff --git a/guide/src/reference/deployment.md b/guide/src/reference/deployment.md index c0c8323f..7ff38610 100644 --- a/guide/src/reference/deployment.md +++ b/guide/src/reference/deployment.md @@ -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 | | [`web`] | Directly loadable in a web browser | | [`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 | [`bundler`]: #bundlers [`web`]: #without-a-bundler [`no-modules`]: #without-a-bundler [`nodejs`]: #nodejs +[`deno`]: #Deno ## 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 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 -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`. ## 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, 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 If you'd like to deploy compiled WebAssembly to NPM, then the tool for the job