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