Skip to content

Commit

Permalink
add --both flag
Browse files Browse the repository at this point in the history
  • Loading branch information
Robert Masen committed Jun 26, 2018
1 parent 3fd60a2 commit b057fdd
Show file tree
Hide file tree
Showing 14 changed files with 323 additions and 23 deletions.
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ matrix:
(cd examples/closures && sed -i 's/: "webpack-dev-server"/: "webpack"/' package.json && ./build.sh)
- |
(cd examples/comments && sed -i 's/: "webpack-dev-server"/: "webpack"/' package.json && ./build.sh)
- |
(cd examples/node-and-browser && sed -i 's/: "webpack-dev-server"/: "webpack"/' package.json && ./build.sh && npm start)
# Build the guide.
- rust: stable
Expand Down
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ members = [
"examples/asm.js",
"examples/char",
"examples/import_js",
"examples/comments"
"examples/comments",
"examples/node_and_browser"
]

[profile.release]
Expand Down
10 changes: 5 additions & 5 deletions crates/cli-support/src/js/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ impl<'a> Context<'a> {
if let Some(ref c) = comments {
self.globals.push_str(c);
}
let global = if self.config.nodejs {
let global = if self.config.nodejs || self.config.both {
if contents.starts_with("class") {
format!("{1}\nmodule.exports.{0} = {0};\n", name, contents)
} else {
Expand Down Expand Up @@ -359,7 +359,7 @@ impl<'a> Context<'a> {
.unwrap_or("wasm_bindgen"),
)
} else {
let import_wasm = if self.config.nodejs {
let import_wasm = if self.config.nodejs || self.config.both {
self.footer.push_str(&format!("wasm = require('./{}_bg');",
module_name));
format!("var wasm;")
Expand Down Expand Up @@ -869,7 +869,7 @@ impl<'a> Context<'a> {
self.global(&format!("
const TextEncoder = require('util').TextEncoder;
"));
} else if !(self.config.browser || self.config.no_modules) {
} else if !(self.config.browser || self.config.no_modules) || self.config.both {
self.global(&format!("
const TextEncoder = typeof self === 'object' && self.TextEncoder
? self.TextEncoder
Expand All @@ -889,7 +889,7 @@ impl<'a> Context<'a> {
self.global(&format!("
const TextDecoder = require('util').TextDecoder;
"));
} else if !(self.config.browser || self.config.no_modules) {
} else if !(self.config.browser || self.config.no_modules) || self.config.both {
self.global(&format!("
const TextDecoder = typeof self === 'object' && self.TextDecoder
? self.TextDecoder
Expand Down Expand Up @@ -1742,7 +1742,7 @@ impl<'a, 'b> SubContext<'a, 'b> {
let name = import.js_namespace.as_ref().map(|s| &**s).unwrap_or(item);

if self.cx.imported_names.insert(name.to_string()) {
if self.cx.config.nodejs {
if self.cx.config.nodejs || self.cx.config.both {
self.cx.imports.push_str(&format!("\
const {} = require('{}').{};\n\
", name, module, name));
Expand Down
75 changes: 58 additions & 17 deletions crates/cli-support/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ pub struct Bindgen {
nodejs: bool,
browser: bool,
no_modules: bool,
both: bool,
no_modules_global: Option<String>,
debug: bool,
typescript: bool,
Expand All @@ -40,6 +41,7 @@ impl Bindgen {
browser: false,
no_modules: false,
no_modules_global: None,
both: false,
debug: false,
typescript: false,
demangle: true,
Expand All @@ -66,6 +68,11 @@ impl Bindgen {
self
}

pub fn both(&mut self, both: bool) -> &mut Bindgen {
self.both = both;
self
}

pub fn no_modules_global(&mut self, name: &str) -> &mut Bindgen {
self.no_modules_global = Some(name.to_string());
self
Expand Down Expand Up @@ -178,13 +185,7 @@ impl Bindgen {

let wasm_path = out_dir.join(format!("{}_bg", stem)).with_extension("wasm");

if self.nodejs {
let js_path = wasm_path.with_extension("js");
let shim = self.generate_node_wasm_import(&module, &wasm_path);
File::create(&js_path)
.and_then(|mut f| f.write_all(shim.as_bytes()))
.with_context(|_| format!("failed to write `{}`", js_path.display()))?;
}
self.write_wasm_import(&module, &wasm_path)?;

let wasm_bytes = parity_wasm::serialize(module)?;
File::create(&wasm_path)
Expand All @@ -193,7 +194,56 @@ impl Bindgen {
Ok(())
}

fn write_wasm_import(&self, m: &Module, wasm_path: &PathBuf) -> Result<(), Error> {
let shim = if self.nodejs {
self.generate_node_wasm_import(m, &wasm_path)
} else if self.both {
self.generate_both_wasm_import(m, &wasm_path)
} else {
return Ok(())
};
let js_path = wasm_path.with_extension("js");
File::create(&js_path)
.and_then(|mut f| f.write_all(shim.as_bytes()))
.with_context(|_| format!("failed to write `{}`", js_path.display()))?;
Ok(())
}

fn generate_node_wasm_import(&self, m: &Module, path: &Path) -> String {
let mut shim = self.generate_import_shim(m);

shim.push_str(&format!("
const join = require('path').join;
const bytes = require('fs').readFileSync(join(__dirname, '{}'));
const wasmModule = new WebAssembly.Module(bytes);
const wasmInstance = new WebAssembly.Instance(wasmModule, imports);
module.exports = wasmInstance.exports;
", path.file_name().unwrap().to_str().unwrap()
));

reset_indentation(&shim)
}

fn generate_both_wasm_import(&self, m: &Module, path: &Path) -> String {
reset_indentation(&format!("
const bytesScript = `const join = require('path').join;
require('fs').readFileSync(join(__dirname, '{path}'));`;
module.exports = resolve();
function resolve() {{
if (typeof self === 'object') {{
return require('./{path}');
}} else {{
{import}
const bytes = eval(bytesScript);
const wasmModule = new WebAssembly.Module(bytes);
return new WebAssembly.Instance(wasmModule, imports).exports;
}}
}}
",path = path.file_name().unwrap().to_str().unwrap(),
import = &self.generate_import_shim(m)))
}

fn generate_import_shim(&self, m: &Module) -> String {
let mut imports = BTreeSet::new();
if let Some(i) = m.import_section() {
for i in i.entries() {
Expand All @@ -206,16 +256,7 @@ impl Bindgen {
for module in imports {
shim.push_str(&format!("imports['{0}'] = require('{0}');\n", module));
}

shim.push_str(&format!("
const join = require('path').join;
const bytes = require('fs').readFileSync(join(__dirname, '{}'));
const wasmModule = new WebAssembly.Module(bytes);
const wasmInstance = new WebAssembly.Instance(wasmModule, imports);
module.exports = wasmInstance.exports;
", path.file_name().unwrap().to_str().unwrap()));

reset_indentation(&shim)
shim
}
}

Expand Down
3 changes: 3 additions & 0 deletions crates/cli/src/bin/wasm-bindgen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Options:
--browser Generate output that only works in a browser
--no-modules Generate output that only works in a browser (without modules)
--no-modules-global VAR Name of the global variable to initialize
--both Generate output that will work with both node.js and webpack
--typescript Output a TypeScript definition file (on by default)
--no-typescript Don't emit a *.d.ts file
--debug Include otherwise-extraneous debug checks in output
Expand All @@ -40,6 +41,7 @@ struct Args {
flag_nodejs: bool,
flag_browser: bool,
flag_no_modules: bool,
flag_both: bool,
flag_typescript: bool,
flag_no_typescript: bool,
flag_out_dir: Option<PathBuf>,
Expand Down Expand Up @@ -83,6 +85,7 @@ fn rmain(args: &Args) -> Result<(), Error> {
.nodejs(args.flag_nodejs)
.browser(args.flag_browser)
.no_modules(args.flag_no_modules)
.both(args.flag_both)
.debug(args.flag_debug)
.demangle(!args.flag_no_demangle)
.typescript(typescript);
Expand Down
17 changes: 17 additions & 0 deletions examples/node_and_browser/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
name = "node-and-browser"
version = "0.1.0"
authors = ["Robert Masen <[email protected]>"]

[lib]
crate-type = ["cdylib"]

[dependencies]
# Here we're using a path dependency to use what's already in this repository,
# but you'd use the commented out version below if you're copying this into your
# project.
wasm-bindgen = { path = "../.." }
#wasm-bindgen = "0.2"
[dependencies.pulldown-cmark]
version = "0.1.2"
default-features = false
23 changes: 23 additions & 0 deletions examples/node_and_browser/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Node and Browser


This directory is an example of using the `#[wasm_bindgen]` macro to create an
entry point that's callable from both the browser and Node.js.

You can build the example locally with:

```
$ ./build.sh
```
This will build the project and spin up `webpack-dev-server` which makes it viewable at http://localhost:8080
(or a higher port if 8080 is already bound).

To see this project used in Node.js you can exit the instance of `webpack-dev-server` and run

```
$ npm start
```

This will read in the `wasm-bindgen` (README.md)[../../README.md] file and convert it to HTML
you can find the results in `./out.html` once it is finished.

19 changes: 19 additions & 0 deletions examples/node_and_browser/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/bin/sh

set -ex

# Build the `hello_world.wasm` file using Cargo/rustc
cargo +nightly build --target wasm32-unknown-unknown

# Run the `wasm-bindgen` CLI tool to postprocess the wasm file emitted by the
# Rust compiler to emit the JS support glue that's necessary
#
# Here we're using the version of the CLI in this repository, but for external
# usage you'd use the commented out version below
cargo +nightly run --manifest-path ../../crates/cli/Cargo.toml --bin wasm-bindgen -- ../../target/wasm32-unknown-unknown/debug/node_and_browser.wasm --out-dir . --both
# wasm-bindgen ../../target/wasm32-unknown-unknown/hello_world.wasm --out-dir .

# Finally, package everything up using Webpack and start a server so we can
# browse the result
npm install
npm run serve
54 changes: 54 additions & 0 deletions examples/node_and_browser/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<html>
<head>
<style>
html,
body {
width: 100%;
height: 100%;
padding: 0;
border: 0;
margin: 0;
}
* {
box-sizing: border-box;
}
#app-container {
width: calc(100% - 20px);
height: calc(100% - 20px);
padding: 10px;
background: slategray;
display: flex;
flex-flow: row;
justify-content: space-between;
align-items: flex-start;
align-content: flex-start;
}
#md-container,
#html-container {
width: calc(50% - 10px);
height: 100%;
padding: 0 5px;
}
#html-container {
background: white;
}
#md-input-box {
resize: none;
width: 100%;
height: 100%;
}
</style>
<link href="https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/2.10.0/github-markdown.min.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="app-container">
<div id="md-container">
<textarea id="md-input-box"></textarea>
</div>
<div id="html-container" class="markdown-body">
<div id="rendered"></div>
</div>
</div>
<script src="index.js"></script>
</body>
</html>
48 changes: 48 additions & 0 deletions examples/node_and_browser/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
let wasm;
import('./node_and_browser.js').then(w => {
console.log('wasm_cmark_parse resolved');
wasm = w;
ready();
});

function parseMD(md) {
console.log('parseMD');
return wasm.parse_markdown(md);
}

let debounce;
function ready() {
console.log('ready');
renderMD();
let input = getInput();
if (!input) throw new Error('Unable to find MD input');
input.addEventListener('keyup', () => {
if (!debounce) {
debounce = setTimeout(renderMD, 2000);
} else {
clearTimeout(debounce);
debounce = setTimeout(renderMD, 2000);
}
});
}
function renderMD() {
console.log('renderMD');
debounce = null;
let input = getInput();
if (!input) throw new Error('Unable to find MD input');
let md = input.value;
let html = parseMD(md);
let target = getHTML();
if (!target) throw new Error('Unable to find div to render HTML');
target.innerHTML = html;
}

function getInput() {
console.log('getInput');
return document.getElementById('md-input-box');
}

function getHTML() {
console.log('getHTML');
return document.getElementById('rendered');
}
Loading

0 comments on commit b057fdd

Please sign in to comment.