Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add deno target #2176

Merged
merged 5 commits into from
Jun 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ members = [
"examples/char",
"examples/closures",
"examples/console_log",
"examples/deno",
"examples/dom",
"examples/duck-typed-interfaces",
"examples/fetch",
Expand Down
12 changes: 11 additions & 1 deletion azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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:
Expand Down
3 changes: 3 additions & 0 deletions ci/azure-install-deno.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
steps:
- script: curl -fsSL https://deno.land/x/install/install.sh | sh
displayName: "install deno"
120 changes: 100 additions & 20 deletions crates/cli-support/src/js/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,8 @@ impl<'a> Context<'a> {
| OutputMode::Node {
experimental_modules: true,
}
| OutputMode::Web => {
| OutputMode::Web
| OutputMode::Deno => {
if contents.starts_with("function") {
let body = &contents[8..];
if export_name == definition_name {
Expand Down Expand Up @@ -269,6 +270,63 @@ impl<'a> Context<'a> {
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));
jakobhellermann marked this conversation as resolved.
Show resolved Hide resolved
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
/// `--target no-modules`, `--target web`, or for bundlers. This is the very
/// last step performed in `finalize`.
Expand Down Expand Up @@ -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
// the wasm file as if it were an ES module and let the
// bundler/runtime take care of it.
Expand Down Expand Up @@ -443,7 +513,8 @@ impl<'a> Context<'a> {
| OutputMode::Node {
experimental_modules: true,
}
| OutputMode::Web => {
| OutputMode::Web
| OutputMode::Deno => {
for (module, items) in crate::sorted_iter(&self.js_imports) {
imports.push_str("import { ");
for (i, (item, rename)) in items.iter().enumerate() {
Expand Down Expand Up @@ -1238,27 +1309,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.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(())
}
Expand Down
21 changes: 11 additions & 10 deletions crates/cli-support/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ enum OutputMode {
Web,
NoModules { global: String },
Node { experimental_modules: bool },
Deno,
}

enum Input {
Expand Down Expand Up @@ -210,6 +211,14 @@ impl Bindgen {
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> {
match &mut self.mode {
OutputMode::NoModules { global } => *global = name.to_string(),
Expand Down Expand Up @@ -526,7 +535,8 @@ impl OutputMode {
| OutputMode::Web
| OutputMode::Node {
experimental_modules: true,
} => true,
}
| OutputMode::Deno => true,
_ => false,
}
}
Expand Down Expand Up @@ -554,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,
Expand Down
73 changes: 73 additions & 0 deletions crates/cli/src/bin/wasm-bindgen-test-runner/deno.rs
Original file line number Diff line number Diff line change
@@ -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),
)
}
Loading