Merge pull request #17 from ashleygwilliams/bindgen

feature: cargo/wasm-bindgen build step
master
ashley williams 7 years ago committed by GitHub
commit cb0e5683a1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      .gitignore
  2. 2
      .travis.yml
  3. 53
      README.md
  4. 171
      examples/js-hello-world/Cargo.lock
  5. 49
      src/bindgen.rs
  6. 45
      src/build.rs
  7. 27
      src/lib.rs
  8. 18
      src/main.rs
  9. 17
      tests/wasm-pack.rs

4
.gitignore vendored

@ -1,4 +1,4 @@
/target
**/target
**/*.rs.bk
/pkg
**/pkg

@ -3,7 +3,7 @@ sudo: false
cache:
cargo
rust:
- stable
- nightly
script:
- cargo test

@ -28,22 +28,53 @@ this project is written in rust. [get rust] to work on this project.
## 💃 commands
- `help`: display available commands
- 🐣 `init`:
- generate a `package.json`
- run [wasm-bindgen] [NOT IMPLEMENTED]
- 🐣 `init`: create necessary files for js interop and npm publishing
- optionally pass a path to a dir that contains a `Cargo.toml`, e.g.:
`wasm-pack init examples/js-hello-world`
- 🍱 `pack`: create a tarball but don't push to the npm registry [NOT IMPLEMENTED]
- 🎆 `publish`: create a tarball and publish to the npm registry [NOT IMPLEMENTED]
## ⚙ what's it do?
## ⚙ how to use
right now? not much. here's the plan:
1. write a crate in Rust.
2. add `wasm-bindgen` to your `Cargo.toml`:
- [x] read data from `Cargo.toml`
- [ ] run [wasm-bindgen]
- [ ] read JS dependency data from your compiled wasm (see [rust-wasm/36])
- [x] write data to `package.json`
- [ ] log you in to npm
- [ ] publish package to npm registry
```toml
[lib]
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = { git = 'https://github.com/alexcrichton/wasm-bindgen' }
```
3. add this to the top of your `src/lib.rs`:
```rust
#![feature(proc_macro)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
```
4. annotate your public functions with `#[wasm_bindgen]` and `#[no_mangle]`, for example:
```rust
#[wasm_bindgen]
extern {
fn alert(s: &str);
}
#[wasm_bindgen]
#[no_mangle]
pub extern fn greet(name: &str) {
alert(&format!("Hello, {}!", name));
}
```
5. install this tool: `cargo install wasm-pack`
6. run `wasm-pack init`, optionally, pass a path to a dir that contains your `Cargo.toml`
7. this tool generates files in a `pkg` dir. to publish to npm, `cd pkg` and then `npm publish`
(in the future you'll be able to use this tool to publish)
[rust-wasm/36]: https://github.com/rust-lang-nursery/rust-wasm/issues/36
[wasm-bindgen]: https://github.com/alexcrichton/wasm-bindgen

@ -0,0 +1,171 @@
[[package]]
name = "dtoa"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "fnv"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "itoa"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "js-hello-world"
version = "0.1.0"
dependencies = [
"wasm-bindgen 0.1.0 (git+https://github.com/alexcrichton/wasm-bindgen)",
]
[[package]]
name = "num-traits"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "proc-macro2"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "quote"
version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "quote"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde"
version = "1.0.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde_derive"
version = "1.0.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive_internals 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_derive_internals"
version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
"synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_json"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "syn"
version = "0.11.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "syn"
version = "0.12.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "synom"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "unicode-xid"
version = "0.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-xid"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "wasm-bindgen"
version = "0.1.0"
source = "git+https://github.com/alexcrichton/wasm-bindgen#31853ad0ba1e4e75384056a57cd6040854f58226"
dependencies = [
"wasm-bindgen-macro 0.1.0 (git+https://github.com/alexcrichton/wasm-bindgen)",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.1.0"
source = "git+https://github.com/alexcrichton/wasm-bindgen#31853ad0ba1e4e75384056a57cd6040854f58226"
dependencies = [
"proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.12.13 (registry+https://github.com/rust-lang/crates.io-index)",
"wasm-bindgen-shared 0.1.0 (git+https://github.com/alexcrichton/wasm-bindgen)",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.1.0"
source = "git+https://github.com/alexcrichton/wasm-bindgen#31853ad0ba1e4e75384056a57cd6040854f58226"
dependencies = [
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
]
[metadata]
"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
"checksum itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8324a32baf01e2ae060e9de58ed0bc2320c9a2833491ee36cd3b4c414de4db8c"
"checksum num-traits 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3c2bd9b9d21e48e956b763c9f37134dc62d9e95da6edb3f672cacb6caf3cd3"
"checksum proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cd07deb3c6d1d9ff827999c7f9b04cdfd66b1b17ae508e14fe47b620f2282ae0"
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
"checksum quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1eca14c727ad12702eb4b6bfb5a232287dcf8385cb8ca83a3eeaf6519c44c408"
"checksum serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)" = "db99f3919e20faa51bb2996057f5031d8685019b5a06139b1ce761da671b8526"
"checksum serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)" = "f4ba7591cfe93755e89eeecdbcc668885624829b020050e6aec99c2a03bd3fd0"
"checksum serde_derive_internals 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6e03f1c9530c3fb0a0a5c9b826bdd9246a5921ae995d75f512ac917fc4dd55b5"
"checksum serde_json 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "57781ed845b8e742fc2bf306aba8e3b408fe8c366b900e3769fbc39f49eb8b39"
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
"checksum syn 0.12.13 (registry+https://github.com/rust-lang/crates.io-index)" = "517f6da31bc53bf080b9a77b29fbd0ff8da2f5a2ebd24c73c2238274a94ac7cb"
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
"checksum wasm-bindgen 0.1.0 (git+https://github.com/alexcrichton/wasm-bindgen)" = "<none>"
"checksum wasm-bindgen-macro 0.1.0 (git+https://github.com/alexcrichton/wasm-bindgen)" = "<none>"
"checksum wasm-bindgen-shared 0.1.0 (git+https://github.com/alexcrichton/wasm-bindgen)" = "<none>"

@ -0,0 +1,49 @@
use std::process::Command;
pub fn cargo_install_wasm_bindgen() {
let output = Command::new("cargo")
.arg("install")
.arg("--git")
.arg("https://github.com/alexcrichton/wasm-bindgen")
.output()
.unwrap_or_else(|e| panic!("failed to execute process: {}", e));
if output.status.success() {
let s = String::from_utf8_lossy(&output.stdout);
println!(
"✅ cargo_install_wasm_bindgen succeeded and stdout was:\n{}",
s
);
} else {
let s = String::from_utf8_lossy(&output.stderr);
print!(
"⛔ cargo_install_wasm_bindgen failed and stderr was:\n{}",
s
);
}
}
pub fn wasm_bindgen_build(path: &str, name: &str) {
let binary_name = name.replace("-", "_");
let path_to_wasm = format!("target/wasm32-unknown-unknown/release/{}.wasm", binary_name);
let output = Command::new("wasm-bindgen")
.current_dir(path)
.arg(&path_to_wasm)
.arg("--out-dir")
.arg("./pkg")
.output()
.unwrap_or_else(|e| panic!("failed to execute process: {}", e));
if output.status.success() {
let s = String::from_utf8_lossy(&output.stdout);
println!("✅ wasm_bindgen_build succeeded and stdout was:\n{}", s);
println!("🏄<200d>♀ ready to go!");
} else {
let s = String::from_utf8_lossy(&output.stderr);
print!("⛔ wasm_bindgen_build failed and stderr was:\n{}", s);
}
}

@ -0,0 +1,45 @@
use std::process::Command;
pub fn rustup_add_wasm_target() {
let output = Command::new("rustup")
.arg("target")
.arg("add")
.arg("wasm32-unknown-unknown")
.output()
.unwrap_or_else(|e| panic!("failed to execute process: {}", e));
if output.status.success() {
let s = String::from_utf8_lossy(&output.stdout);
println!(
"✅ rustup_add_wasm_target succeeded and stdout was:\n{}",
s
);
} else {
let s = String::from_utf8_lossy(&output.stderr);
print!("⛔ rustup_add_wasm_target failed and stderr was:\n{}", s);
}
}
pub fn cargo_build_wasm(path: &str) {
let output = Command::new("cargo")
.current_dir(path)
.arg("build")
.arg("--release")
.arg("--target")
.arg("wasm32-unknown-unknown")
.output()
.unwrap_or_else(|e| panic!("failed to execute process: {}", e));
if output.status.success() {
let s = String::from_utf8_lossy(&output.stdout);
println!("✅ cargo_build_wasm succeeded and stdout was:\n{}", s);
println!("🏎 💨 compiled to wasm!");
} else {
let s = String::from_utf8_lossy(&output.stderr);
print!("⛔ cargo_build_wasm failed and stderr was:\n{}", s);
}
}

@ -31,16 +31,20 @@ struct NpmPackage {
version: String,
license: String,
repository: Repository,
files: Vec<String>,
}
#[derive(Serialize)]
struct Repository {
#[serde(rename = "type")] ty: String,
#[serde(rename = "type")]
ty: String,
url: String,
}
fn read_cargo_toml(path: &str) -> Result<CargoManifest, Error> {
let mut cargo_file = File::open(format!("{}/Cargo.toml", path))?;
let path_to_manifest = format!("{}/Cargo.toml", path);
println!("👩🍳 reading {}", path_to_manifest);
let mut cargo_file = File::open(path_to_manifest)?;
let mut cargo_contents = String::new();
cargo_file.read_to_string(&mut cargo_contents)?;
@ -49,6 +53,9 @@ fn read_cargo_toml(path: &str) -> Result<CargoManifest, Error> {
impl CargoManifest {
fn into_npm(self) -> NpmPackage {
let filename = self.package.name.replace("-", "_");
let js_file = format!("{}.js", filename);
let wasm_file = format!("{}_wasm.wasm", filename);
NpmPackage {
name: self.package.name,
description: self.package.description,
@ -58,22 +65,30 @@ impl CargoManifest {
ty: "git".to_string(),
url: self.package.repository,
},
files: vec![js_file, wasm_file],
}
}
}
fn create_pkg_dir() -> Result<(), Error> {
fs::create_dir_all("./pkg")?;
fn create_pkg_dir(path: &str) -> Result<(), Error> {
let path_to_pkg_dir = format!("{}/pkg", path);
fs::create_dir_all(path_to_pkg_dir)?;
Ok(())
}
/// Generate a package.json file inside in `./pkg`.
pub fn write_package_json(path: &str) -> Result<(), Error> {
create_pkg_dir()?;
let mut pkg_file = File::create("./pkg/package.json")?;
create_pkg_dir(path)?;
let path_to_pkg_file = format!("{}/pkg/package.json", path);
let mut pkg_file = File::create(path_to_pkg_file)?;
let crate_data = read_cargo_toml(path)?;
let npm_data = crate_data.into_npm();
let npm_json = serde_json::to_string(&npm_data)?;
pkg_file.write_all(npm_json.as_bytes())?;
println!("✍ wrote a package.json!");
Ok(())
}
pub fn get_crate_name(path: &str) -> Result<String, Error> {
Ok(read_cargo_toml(path)?.package.name)
}

@ -2,6 +2,9 @@
extern crate quicli;
extern crate wasm_pack;
mod build;
mod bindgen;
use quicli::prelude::*;
/// 📦 ✨ pack and publish your wasm!
@ -29,11 +32,16 @@ enum Command {
main!(|args: Cli, log_level: verbosity| match args.cmd {
Command::Init { path } => {
match path {
Some(p) => wasm_pack::write_package_json(&p)?,
None => wasm_pack::write_package_json(".")?,
}
println!("✍ wrote a package.json!");
let crate_path = match path {
Some(p) => p,
None => ".".to_string(),
};
build::rustup_add_wasm_target();
build::cargo_build_wasm(&crate_path);
wasm_pack::write_package_json(&crate_path)?;
bindgen::cargo_install_wasm_bindgen();
let name = wasm_pack::get_crate_name(&crate_path)?;
bindgen::wasm_bindgen_build(&crate_path, &name);
}
Command::Pack { .. } => {
println!("🎒 packed up your package!");

@ -2,6 +2,21 @@ extern crate wasm_pack;
use std::fs;
#[test]
fn it_gets_the_crate_name_default_path() {
assert!(wasm_pack::get_crate_name(".").is_ok());
assert_eq!(wasm_pack::get_crate_name(".").unwrap(), "wasm-pack");
}
#[test]
fn it_gets_the_crate_name_provided_path() {
assert!(wasm_pack::get_crate_name("./examples/js-hello-world").is_ok());
assert_eq!(
wasm_pack::get_crate_name("./examples/js-hello-world").unwrap(),
"js-hello-world"
);
}
#[test]
fn it_creates_a_package_json_default_path() {
assert!(wasm_pack::write_package_json(".").is_ok());
@ -11,5 +26,5 @@ fn it_creates_a_package_json_default_path() {
#[test]
fn it_creates_a_package_json_provided_path() {
assert!(wasm_pack::write_package_json("./examples/js-hello-world").is_ok());
assert!(fs::metadata("./pkg/package.json").is_ok());
assert!(fs::metadata("./examples/js-hello-world/pkg/package.json").is_ok());
}

Loading…
Cancel
Save