diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000..7585238 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1 @@ +book diff --git a/docs/book.toml b/docs/book.toml new file mode 100644 index 0000000..0f3ec66 --- /dev/null +++ b/docs/book.toml @@ -0,0 +1,5 @@ +[book] +authors = ["Ashley Williams"] +multilingual = false +src = "src" +title = "Hello wasm-pack!" diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md new file mode 100644 index 0000000..8dda69e --- /dev/null +++ b/docs/src/SUMMARY.md @@ -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) diff --git a/docs/src/command/pack-and-publish.md b/docs/src/command/pack-and-publish.md new file mode 100644 index 0000000..181e274 --- /dev/null +++ b/docs/src/command/pack-and-publish.md @@ -0,0 +1 @@ +# pack and publish diff --git a/docs/build.md b/docs/src/commands/build.md similarity index 100% rename from docs/build.md rename to docs/src/commands/build.md diff --git a/docs/src/commands/index.md b/docs/src/commands/index.md new file mode 100644 index 0000000..61c515e --- /dev/null +++ b/docs/src/commands/index.md @@ -0,0 +1 @@ +# Commands diff --git a/docs/init.md b/docs/src/commands/init.md similarity index 100% rename from docs/init.md rename to docs/src/commands/init.md diff --git a/docs/pack-and-publish.md b/docs/src/commands/pack-and-publish.md similarity index 100% rename from docs/pack-and-publish.md rename to docs/src/commands/pack-and-publish.md diff --git a/docs/contributing.md b/docs/src/contributing.md similarity index 100% rename from docs/contributing.md rename to docs/src/contributing.md diff --git a/docs/prerequisites.md b/docs/src/prerequisites.md similarity index 100% rename from docs/prerequisites.md rename to docs/src/prerequisites.md diff --git a/docs/setup.md b/docs/src/setup.md similarity index 100% rename from docs/setup.md rename to docs/src/setup.md diff --git a/docs/src/tutorial/getting-started.md b/docs/src/tutorial/getting-started.md new file mode 100644 index 0000000..bad5562 --- /dev/null +++ b/docs/src/tutorial/getting-started.md @@ -0,0 +1 @@ +# Getting Started diff --git a/docs/src/tutorial/index.md b/docs/src/tutorial/index.md new file mode 100644 index 0000000..4f50ecc --- /dev/null +++ b/docs/src/tutorial/index.md @@ -0,0 +1 @@ +# Tutorial diff --git a/docs/src/tutorial/initialize.md b/docs/src/tutorial/initialize.md new file mode 100644 index 0000000..2860a71 --- /dev/null +++ b/docs/src/tutorial/initialize.md @@ -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 "] + +[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 "] +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! diff --git a/docs/src/tutorial/introduction.md b/docs/src/tutorial/introduction.md new file mode 100644 index 0000000..c77a449 --- /dev/null +++ b/docs/src/tutorial/introduction.md @@ -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 diff --git a/docs/src/tutorial/next-steps.md b/docs/src/tutorial/next-steps.md new file mode 100644 index 0000000..c621339 --- /dev/null +++ b/docs/src/tutorial/next-steps.md @@ -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! diff --git a/docs/src/tutorial/packaging-and-publishing.md b/docs/src/tutorial/packaging-and-publishing.md new file mode 100644 index 0000000..adf6912 --- /dev/null +++ b/docs/src/tutorial/packaging-and-publishing.md @@ -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. diff --git a/docs/src/tutorial/setup.md b/docs/src/tutorial/setup.md new file mode 100644 index 0000000..728ce0c --- /dev/null +++ b/docs/src/tutorial/setup.md @@ -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). diff --git a/docs/src/tutorial/using-your-library.md b/docs/src/tutorial/using-your-library.md new file mode 100644 index 0000000..ae7b0d1 --- /dev/null +++ b/docs/src/tutorial/using-your-library.md @@ -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 + + + + + wasm-pack example + + + + + +``` + +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: + +![An alert box saying "Hello from Rust! 3 + 2 = 5"](./wasm-pack/wasm-pack.png) + +If you did congrats you've successfully uploaded your first bit of wasm code to npm and used it +properly! diff --git a/docs/src/tutorial/wasm-pack.png b/docs/src/tutorial/wasm-pack.png new file mode 100644 index 0000000..02f51b1 Binary files /dev/null and b/docs/src/tutorial/wasm-pack.png differ diff --git a/docs/src/tutorial/writing-a-libary.md b/docs/src/tutorial/writing-a-libary.md new file mode 100644 index 0000000..71e9c78 --- /dev/null +++ b/docs/src/tutorial/writing-a-libary.md @@ -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). diff --git a/docs/src/tutorial/writing-a-rust-webassembly-library.md b/docs/src/tutorial/writing-a-rust-webassembly-library.md new file mode 100644 index 0000000..7701135 --- /dev/null +++ b/docs/src/tutorial/writing-a-rust-webassembly-library.md @@ -0,0 +1 @@ +# Writing a Rust-WebAssembly Library