parent
87d1b70593
commit
bf39e3ed80
@ -0,0 +1 @@ |
|||||||
|
book |
@ -0,0 +1,5 @@ |
|||||||
|
[book] |
||||||
|
authors = ["Ashley Williams"] |
||||||
|
multilingual = false |
||||||
|
src = "src" |
||||||
|
title = "Hello wasm-pack!" |
@ -0,0 +1,16 @@ |
|||||||
|
# Summary |
||||||
|
|
||||||
|
- [Prerequisites](./prerequisites.md) |
||||||
|
- [Setup](./setup.md) |
||||||
|
- [Commands](./commands/index.md) |
||||||
|
- [`init`](./commands/init.md) |
||||||
|
- [`build`](./commands/build.md) |
||||||
|
- [`pack` and `publish`](./command/pack-and-publish.md) |
||||||
|
- [Tutorial](./tutorial/index.md) |
||||||
|
- [Setup](./tutorial/setup.md) |
||||||
|
- [Getting Started](./tutorial/getting-started.md) |
||||||
|
- [Writing a Rust-WebAssembly Library](./tutorial/writing-a-rust-webassembly-library.md) |
||||||
|
- [Packaging and Publishing](./tutorial/packaging-and-publishing.md) |
||||||
|
- [Using your Library](./tutorial/using-your-library.md) |
||||||
|
- [Next Steps](./tutorial/next-steps.md) |
||||||
|
- [Contributing](./contributing.md) |
@ -0,0 +1 @@ |
|||||||
|
# pack and publish |
@ -0,0 +1 @@ |
|||||||
|
# Commands |
@ -0,0 +1 @@ |
|||||||
|
# Getting Started |
@ -0,0 +1 @@ |
|||||||
|
# Tutorial |
@ -0,0 +1,81 @@ |
|||||||
|
# Project Initialization |
||||||
|
|
||||||
|
Now that we've installed all of our tools and setup our npm account we can actually start coding! |
||||||
|
We'll be writing up a small crate that adds two numbers and outputs the numbers. While this will |
||||||
|
be a simple example, we're really trying to focus on how to use wasm-pack. You'll be provided links |
||||||
|
to other resources so you can make more complicated code to package and ship them to npm! |
||||||
|
|
||||||
|
Let's get started then! First off run this command to create our project: |
||||||
|
|
||||||
|
```bash |
||||||
|
$ cargo new --lib wasm-add |
||||||
|
``` |
||||||
|
|
||||||
|
This will create a new Rust project in a directory called `wasm-add`. We've also specified that |
||||||
|
we're building a library, since we'll be calling this code from JS. |
||||||
|
|
||||||
|
Now just: |
||||||
|
|
||||||
|
```bash |
||||||
|
$ cd wasm-add |
||||||
|
``` |
||||||
|
|
||||||
|
You'll find everything in here ready to get started. First though we'll need to add a dependency to |
||||||
|
our code and make a few small changes. Open up your `Cargo.toml` file. You should see something like |
||||||
|
this inside: |
||||||
|
|
||||||
|
```toml |
||||||
|
[package] |
||||||
|
name = "wasm-add" |
||||||
|
version = "0.1.0" |
||||||
|
authors = ["Michael Gattozzi <mgattozzi@gmail.com>"] |
||||||
|
|
||||||
|
[dependencies] |
||||||
|
``` |
||||||
|
|
||||||
|
This configuration file sets up everything we need to get started but we'll need a few extra fields |
||||||
|
and settings to get this to work for wasm and be ready for npm |
||||||
|
|
||||||
|
```toml |
||||||
|
[package] |
||||||
|
name = "wasm-add" |
||||||
|
version = "0.1.0" |
||||||
|
authors = ["Michael Gattozzi <mgattozzi@gmail.com>"] |
||||||
|
description = "Code used to demonstrate how to use wasm-pack" |
||||||
|
license = "MIT/Apache-2.0" |
||||||
|
repository = "https://github.com/mgattozzi/wasm-add" |
||||||
|
|
||||||
|
[lib] |
||||||
|
crate-type = ["cdylib"] |
||||||
|
|
||||||
|
[dependencies] |
||||||
|
wasm-bindgen = "0.2" |
||||||
|
``` |
||||||
|
|
||||||
|
First off lets look at the last three fields added to the package section `description`, `license`, |
||||||
|
and `repository`. npm requires this metadata and so `wasm-pack` won't package your code up until you |
||||||
|
have them set. There are more fields that you can add that are more specific to `crates.io` that you |
||||||
|
can find [here](https://doc.rust-lang.org/cargo/reference/manifest.html) but for the sake of this |
||||||
|
tutorial that's all you need for that section. |
||||||
|
|
||||||
|
You'll also notice we add a new section titled `[lib]`. In here we added this line: |
||||||
|
|
||||||
|
```toml |
||||||
|
crate-type = ["cdylib"] |
||||||
|
``` |
||||||
|
|
||||||
|
Normally Rust compiles the code for the library in a format meant for other Rust packages. We want |
||||||
|
our code to work with wasm though! We specify that it's a dynamic library that's C compatible. This |
||||||
|
sounds a bit weird but the `wasm32` target will know to interpret this option and instead produce |
||||||
|
a wasm binary properly. This is meant to get `cargo` to pass the right parameters to the compiler! |
||||||
|
|
||||||
|
Alright the last thing we added was this to the `[dependencies]` section: |
||||||
|
|
||||||
|
```toml |
||||||
|
wasm-bindgen = "0.2" |
||||||
|
``` |
||||||
|
|
||||||
|
This is the `wasm-bindgen` crate. We'll be using it very shortly to make our functions work nicely |
||||||
|
with wasm and not have to worry about a lot of nitty gritty details. |
||||||
|
|
||||||
|
We've got our package's metadata all set up, so let's actually write some code! |
@ -0,0 +1,17 @@ |
|||||||
|
# Introduction |
||||||
|
|
||||||
|
`wasm-pack` is a brand new tool designed to make packaging up binaries that include wasm (that may |
||||||
|
or may not have JS in them) and make publishing them on npm easy to do. We can't necessarily |
||||||
|
distribute Rust code to developers directly and expect them |
||||||
|
to build it from scratch. npm is used to install packages for frontend work but it doesn't know how |
||||||
|
to compile Rust! With wasm though it's not a problem. Once it's compiled it's all good to go. |
||||||
|
However, getting it ready to be distributed, packaging it up properly for npm, and then sending it |
||||||
|
to npm can be a bit of a hassle. `wasm-pack` is here to make that easier. |
||||||
|
|
||||||
|
We'll step through creating a simple Rust library, using `wasm-pack` to get it ready for |
||||||
|
distribution, sending it to npm, then using it as a package from npm to verify it works! |
||||||
|
|
||||||
|
As with all software in the early stages, this is bleeding edge! Expect some nicks and bruises! If |
||||||
|
you run into issues or a bug please file an issue over at it's [repo]. |
||||||
|
|
||||||
|
[repo]: https://github.com/rustwasm/wasm-pack/issues |
@ -0,0 +1,6 @@ |
|||||||
|
# Next Steps |
||||||
|
|
||||||
|
This was an introduction to wasm-pack but also using wasm code from npm. From here you could |
||||||
|
actually improve on the project setup, expand out what your wasm code can actually do, or expand out |
||||||
|
how you would use the package you've created. The whole wasm space is completely open so there's no |
||||||
|
limit to what you can and can't do really! Go out there and try some cool new things. Happy hacking! |
@ -0,0 +1,37 @@ |
|||||||
|
# Package Code for npm |
||||||
|
|
||||||
|
We've made our code so now we need to package it all up. In your project directory run the following |
||||||
|
command: |
||||||
|
|
||||||
|
```bash |
||||||
|
$ wasm-pack init --scope MYSCOPE |
||||||
|
``` |
||||||
|
|
||||||
|
where `MYSCOPE` is your npm username. Normally you could just type `wasm-pack init` but since |
||||||
|
other people are doing this tutorial as well we don't want conflicts with the `wasm-add` package |
||||||
|
name! This command when run does a few things: |
||||||
|
|
||||||
|
1. It'll compile your code to wasm if you haven't already |
||||||
|
2. It'll generate a pkg folder with the wasm file, a JS wrapper file around the wasm, your README, |
||||||
|
and a `package.json` file. |
||||||
|
|
||||||
|
This is everything you need to upload your code to npm! Let's do just that! |
||||||
|
|
||||||
|
First off you'll need to login to npm with the account you made earlier if you didn't already have |
||||||
|
one: |
||||||
|
|
||||||
|
```bash |
||||||
|
$ npm login |
||||||
|
``` |
||||||
|
|
||||||
|
Next you'll need to go into the `pkg` directory and actually upload the package: |
||||||
|
|
||||||
|
```bash |
||||||
|
$ cd pkg |
||||||
|
$ npm publish --access=public |
||||||
|
``` |
||||||
|
|
||||||
|
Now normally if things are not scoped you can just do `npm publish` but if you give it a scope |
||||||
|
you'll need to tell npm that this is actually public so it can publish it. We need to do that here |
||||||
|
since we gave our packages a scope to avoid conflicting with each other! Next up is actually running |
||||||
|
the code and verifying we got it from npm and how we can use that code. |
@ -0,0 +1,30 @@ |
|||||||
|
# Tools Setup |
||||||
|
|
||||||
|
## Rust |
||||||
|
|
||||||
|
If you haven't already, you'll need to install nightly Rust with the wasm toolchain! |
||||||
|
See [the setup section](setup.html) for more details. Once you've done that you'll need to install |
||||||
|
the latest version of `wasm-pack`. |
||||||
|
|
||||||
|
```bash |
||||||
|
$ cargo install wasm-pack |
||||||
|
``` |
||||||
|
|
||||||
|
## npm |
||||||
|
|
||||||
|
If you also have not installed npm already you'll need to do so! Follow the docs available on |
||||||
|
[npm](https://www.npmjs.com/get-npm). |
||||||
|
|
||||||
|
To confirm you've succeeded run: |
||||||
|
|
||||||
|
```bash |
||||||
|
$ npm --version |
||||||
|
``` |
||||||
|
|
||||||
|
You should see the version number pop out in your terminal if you installed it successfully! |
||||||
|
|
||||||
|
## npm account |
||||||
|
|
||||||
|
After you have npm installed you'll need to sign up for an account on npm if you have not already |
||||||
|
done so in order to complete the tutorial and so you can publish your package. The sign up page can |
||||||
|
be found [here](https://www.npmjs.com/signup). |
@ -0,0 +1,90 @@ |
|||||||
|
# Run The Code From npm |
||||||
|
|
||||||
|
Alright let's make a new small directory to test that we can now run this code and pull it from npm. |
||||||
|
|
||||||
|
```bash |
||||||
|
$ mkdir test |
||||||
|
$ cd test |
||||||
|
``` |
||||||
|
|
||||||
|
Now we need to create a `package.json` file that looks like this: |
||||||
|
|
||||||
|
```json |
||||||
|
{ |
||||||
|
"scripts": { |
||||||
|
"serve": "webpack-dev-server" |
||||||
|
}, |
||||||
|
"dependencies": { |
||||||
|
"@MYSCOPE/wasm-add": "^0.1.0" |
||||||
|
}, |
||||||
|
"devDependencies": { |
||||||
|
"webpack": "^4.0.1", |
||||||
|
"webpack-cli": "^2.0.10", |
||||||
|
"webpack-dev-server": "^3.1.0" |
||||||
|
} |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
where `MYSCOPE` is your npm username. You can expand this to be a more complete file but |
||||||
|
we're really just trying to verify that this works! |
||||||
|
|
||||||
|
Next up we'll need to create a small webpack configuration so that we can use the |
||||||
|
`webpack-dev-server` to serve the wasm file properly. It should be noted that webpack isn't |
||||||
|
a requirement. It's just what was chosen for this tutorial. You just need something to server the |
||||||
|
code! Here's what your `webpack.config.js` should look like: |
||||||
|
|
||||||
|
```javascript |
||||||
|
const path = require('path'); |
||||||
|
module.exports = { |
||||||
|
entry: "./index.js", |
||||||
|
output: { |
||||||
|
path: path.resolve(__dirname, "dist"), |
||||||
|
filename: "index.js", |
||||||
|
}, |
||||||
|
mode: "development" |
||||||
|
}; |
||||||
|
``` |
||||||
|
|
||||||
|
This tells webpack that if it's going to start things up use `index.js`. Before we do that though |
||||||
|
we'll need to setup a small html file. Create a new file called `index.html` and put this inside it: |
||||||
|
|
||||||
|
```html |
||||||
|
<!DOCTYPE html> |
||||||
|
<html> |
||||||
|
<head> |
||||||
|
<meta charset="utf-8"> |
||||||
|
<title>wasm-pack example</title> |
||||||
|
</head> |
||||||
|
<body> |
||||||
|
<script src="./index.js"></script> |
||||||
|
</body> |
||||||
|
</html> |
||||||
|
``` |
||||||
|
|
||||||
|
We're almost set. Now we need to setup our JS file so that we can run some wasm code! |
||||||
|
Make a file called `index.js` and put this inside of it: |
||||||
|
|
||||||
|
```javascript |
||||||
|
const js = import("@MYSCOPE/wasm-add/wasm_add.js"); |
||||||
|
js.then(js => { |
||||||
|
js.alert_add(3,2); |
||||||
|
}); |
||||||
|
``` |
||||||
|
|
||||||
|
Since web pack [can't load wasm synchronously yet](https://github.com/webpack/webpack/issues/6615) |
||||||
|
we are using the import statement above followed |
||||||
|
by the promise in order to load it properly. This is what lets us then call `alert_add`. We're |
||||||
|
importing from the `node_module` folder we haven't gotten yet so let's import all of our |
||||||
|
dependencies finally and run the example! |
||||||
|
|
||||||
|
```bash |
||||||
|
$ npm install |
||||||
|
$ npm run serve |
||||||
|
``` |
||||||
|
|
||||||
|
Then in a web browser navigate to `http://localhost:8080` you should see something like this: |
||||||
|
|
||||||
|
 |
||||||
|
|
||||||
|
If you did congrats you've successfully uploaded your first bit of wasm code to npm and used it |
||||||
|
properly! |
After Width: | Height: | Size: 21 KiB |
@ -0,0 +1,137 @@ |
|||||||
|
# Rust Code |
||||||
|
|
||||||
|
If you open up `src/lib.rs` you should see a file that looks like this: |
||||||
|
|
||||||
|
```rust |
||||||
|
#[cfg(test)] |
||||||
|
mod tests { |
||||||
|
#[test] |
||||||
|
fn it_works() { |
||||||
|
assert_eq!(2 + 2, 4); |
||||||
|
} |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
Let's quickly modify the test suite to work for what we'll be doing. It should look like this: |
||||||
|
|
||||||
|
```rust |
||||||
|
#[test] |
||||||
|
fn it_works() { |
||||||
|
assert_eq!(add(2, 2), 4); |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
We'll use this later to make sure our `add` function works! |
||||||
|
|
||||||
|
Now we need to add this to the top of the file: |
||||||
|
|
||||||
|
```rust |
||||||
|
#![feature(use_extern_macros, wasm_import_module, wasm_custom_section)] |
||||||
|
extern crate wasm_bindgen; |
||||||
|
use wasm_bindgen::prelude::*; |
||||||
|
``` |
||||||
|
|
||||||
|
Let's step through this line by line. First up is the list of nightly features. We're enabling this for |
||||||
|
the whole crate. What this means is that we will later tag code with an attribute and this will |
||||||
|
allow Rust to generate code that we don't have to write by hand. In our case it'll use |
||||||
|
`wasm-bindgen.` It should be noted that `#![feature(...)]` implies using the nightly |
||||||
|
compiler. This gated feature will hopefully be stabilized and landed soon so that you won't need it! |
||||||
|
|
||||||
|
`wasm-bindgen` knows how to make code that works well with wasm so we don't have to |
||||||
|
worry about it too much and just write Rust code for the most part. If you want to know the full |
||||||
|
extent of its capabilities check out the README on its repo which can be found |
||||||
|
[here](https://github.com/alexcrichton/wasm-bindgen). For our purposes we need to know that if we |
||||||
|
want functions to work with wasm easily we'll need it. |
||||||
|
|
||||||
|
The next line says we're importing the `wasm-bindgen` crate and the line after that imports the |
||||||
|
prelude from `wasm-bindgen`. The `extern crate` call lets the compiler know what crates to link in |
||||||
|
and the `prelude` contains all the types and functions that `wasm-bindgen` needs to work properly! |
||||||
|
|
||||||
|
Cool let's import the `alert` function from JS so that we can call it in our Rust code! |
||||||
|
|
||||||
|
```rust |
||||||
|
#[wasm_bindgen] |
||||||
|
extern { |
||||||
|
fn alert(s: &str); |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
Alright so we have our external bit of code and we have everything imported so let's write the |
||||||
|
actual `add` function, as well as an `add_alert` function that will use `add` in itself but also |
||||||
|
call `alert` to print out the results before returning the value. |
||||||
|
|
||||||
|
```rust |
||||||
|
#[wasm_bindgen] |
||||||
|
pub fn add(a: i32, b: i32) -> i32 { |
||||||
|
a + b |
||||||
|
} |
||||||
|
|
||||||
|
#[wasm_bindgen] |
||||||
|
pub fn alert_add(a: i32, b: i32) -> i32 { |
||||||
|
let c = add(a, b); |
||||||
|
alert(&format!("Hello from Rust! {} + {} = {}", a, b, c)); |
||||||
|
c |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
These functions are fairly straightforward if you're familiar with Rust, but if you're not we'll walk |
||||||
|
through it. Both functions take a value `a` and a value `b`. We have said that both are 32 bit |
||||||
|
integers (`i32`). We then say both will return an `i32`. The last line in a function returns the value |
||||||
|
if there is no semicolon. So in the `add` function the value of `a + b` gets calculated and it's |
||||||
|
value is returned! In the case of `alert_add` we store the value of the `add` function we just made |
||||||
|
into the variable `c`. We then call `alert` saying what the add operation looked like and what the |
||||||
|
value was! We then return what was inside `c`. Neat! |
||||||
|
|
||||||
|
This is all the Rust code we need to write. Your `lib.rs` file should look like this by now: |
||||||
|
|
||||||
|
```rust |
||||||
|
#![feature(use_extern_macros, wasm_import_module, wasm_custom_section)] |
||||||
|
extern crate wasm_bindgen; |
||||||
|
use wasm_bindgen::prelude::*; |
||||||
|
|
||||||
|
#[wasm_bindgen] |
||||||
|
extern { |
||||||
|
fn alert(s: &str); |
||||||
|
} |
||||||
|
|
||||||
|
#[wasm_bindgen] |
||||||
|
pub fn add(a: i32, b: i32) -> i32 { |
||||||
|
a + b |
||||||
|
} |
||||||
|
|
||||||
|
#[wasm_bindgen] |
||||||
|
pub fn alert_add(a: i32, b: i32) -> i32 { |
||||||
|
let c = add(a, b); |
||||||
|
alert(&format!("Hello from Rust! {} + {} = {}", a, b, c)); |
||||||
|
c |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn it_works() { |
||||||
|
assert_eq!(add(2, 2), 4); |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
Just to make sure that `add` works we'll run the test we wrote earlier: |
||||||
|
|
||||||
|
```bash |
||||||
|
$ cargo test |
||||||
|
``` |
||||||
|
|
||||||
|
You should get output that looks sort of like this: |
||||||
|
|
||||||
|
```bash |
||||||
|
Compiling wasm-add v0.1.1 (file:///home/michael/Code/wasm-add) |
||||||
|
Finished dev [unoptimized + debuginfo] target(s) in 0.54 secs |
||||||
|
Running target/debug/deps/wasm_add-5d5676e23e39dbea |
||||||
|
running 1 test |
||||||
|
test it_works ... ok |
||||||
|
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out |
||||||
|
``` |
||||||
|
|
||||||
|
Yay it all works! Notice we didn't add a test for `alert_add`. This is because Rust won't know what |
||||||
|
`alert` is unless the wasm code is running in the browser! Don't worry though. Once we package this |
||||||
|
code up and upload it to npm we'll then test out that function to make sure everything works like we |
||||||
|
expect it too! |
||||||
|
|
||||||
|
You can find all of the above code [here](https://github.com/mgattozzi/wasm-add). |
@ -0,0 +1 @@ |
|||||||
|
# Writing a Rust-WebAssembly Library |
Loading…
Reference in new issue