Skip to content

Commit

Permalink
Merge pull request #2176 from jakobhellermann/deno-target
Browse files Browse the repository at this point in the history
add deno target
  • Loading branch information
alexcrichton authored Jun 3, 2020
2 parents 36dcbb8 + 665785e commit 9c5a6df
Show file tree
Hide file tree
Showing 17 changed files with 415 additions and 110 deletions.
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));
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 @@ -509,7 +518,8 @@ impl OutputMode {
| OutputMode::Web
| OutputMode::Node {
experimental_modules: true,
} => true,
}
| OutputMode::Deno => true,
_ => false,
}
}
Expand Down Expand Up @@ -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 {
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

0 comments on commit 9c5a6df

Please sign in to comment.