@ -32,20 +34,21 @@ This project requires Rust 1.30.0 or later.
## 🎙️ Commands
- [`init` (⚠️ DEPRECATED)](https://rustwasm.github.io/wasm-pack/book/commands/init.html): This command has been deprecated since release `0.5.0`, in favor of `build`. `0.4.2` and previous use this command.
- [`build`](https://rustwasm.github.io/wasm-pack/book/commands/build.html): Generate an npm wasm pkg from a rustwasm crate
- [`test`](https://rustwasm.github.io/wasm-pack/book/commands/test.html): Run browser tests
- [`pack` and `publish`](https://rustwasm.github.io/wasm-pack/book/commands/pack-and-publish.html): Create a tarball of your rustwasm pkg and/or publish to a registry
## 📝 Logging
We generate a `wasm-pack.log` file if `wasm-pack` errors on you, and you can
customize the log verbosity using the verbosity flag.
`wasm-pack` uses [`env_logger`] to produces logs when `wasm-pack` runs.
| `nodejs` | Outputs JS that uses CommonJS modules, for use with a `require` statement. `main` key in `package.json`. |
| `nomodules` | Outputs JS that use no modules. `browser` key in `package.json`. |
| `browser` | Outputs JS that uses ES6 modules, primarily for use with `import` statements and/or bundlers such as `webpack`. `module` key in `package.json`. `sideEffects: false` by default. |
| *not specified* or `bundler` | [Bundler][bundlers] | Outputs JS that is suitable for interoperation with a Bundler like Webpack. You'll `import` the JS and the `module` key is specified in `package.json`. `sideEffects: false` is by default. |
| `nodejs` | [Node.js][deploy-nodejs] | Outputs JS that uses CommonJS modules, for use with a `require` statement. `main` key in `package.json`. |
| `web` | [Native in browser][deploy-web] | Outputs JS that can be natively imported as an ES module in a browser, but the WebAssembly must be manually instantiated and loaded. |
| `no-modules` | [Native in browser][deploy-web] | Same as `web`, except the JS is included on a page and modifies global state, and doesn't support as many `wasm-bindgen` features as `web` |
We'll start with the most important part of `lib.rs` -- the two `#[wasm_bindgen]` functions (which you can find at the bottom of the file). In many cases, this is the only part of `lib.rs` you will need to modify.
## 1. `#[wasm_bindgen]` functions
The `#[wasm_bindgen]` attribute indicates that the function below it will be accessible both in JavaScript and Rust.
```rust
#[wasm_bindgen]
extern {
fn alert(s: &str);
}
```
The `extern` block imports the external JavaScript function `alert` into Rust. This declaration is required to call `alert` from Rust. By declaring it in this way, `wasm-bindgen` will create JavaScript stubs for `alert` which allow us to pass strings back and forth between Rust and JavaScript.
We can see that the `alert` function requires a single parameter `s` of type `&str`, a string. In Rust, any string literal such as `"Hello, test-wasm!"` is of type `&str`. So, `alert` could be called by writing `alert("Hello, test-wasm!");`.
We knew to declare `alert` in this way because it is how we would call `alert` in JavaScript -- by passing it a string argument.
```rust
#[wasm_bindgen]
pub fn greet() {
alert("Hello, test-wasm!");
}
```
If we were to write the `greet` function without the `#[wasm_bindgen]` attribute, then `greet` would not be easily accessible within JavaScript. Furthermore, we wouldn't be able to natively convert certain types such as `&str` between JavaScript and Rust. So, both the `#[wasm_bindgen]` attribute and the prior import of `alert` allow `greet` to be called from JavaScript.
This is all you need to know to interface with JavaScript, at least to start! You can learn a bunch more by reading the
This statement declares a new module named `utils` that is defined by the contents of `utils.rs`. Equivalently, we could place the contents of `utils.rs` inside the `utils` declaration, replacing the line with:
```rust
mod utils {
// contents of utils.rs
}
```
Either way, the contents of `utils.rs` define a single public function `set_panic_hook`. Because we are placing it inside the `utils` module, we will be able to call the function directly by writing `utils::set_panic_hook()`. We will discuss how and why to use this function in `src/utils.rs`.
```rust
use cfg_if::cfg_if;
```
`use` allows us to conveniently refer to parts of a crate or module. For example, suppose the crate `cfg_if` contains a function `func`. It is always possible to call this function directly by writing `cfg_if::func()`. However, this is often tedious to write. If we first specify `use cfg_if::func;`, then `func` can be called by just writing `func()` instead. You can learn more about how Rust let's you
write modular code in [this chapter of the book](https://doc.rust-lang.org/book/ch07-02-modules-and-use-to-control-scope-and-privacy.html).
With this in mind, this `use` allows us to call the macro `cfg_if!` inside the crate `cfg_if` without writing `cfg_if::cfg_if!`. We use `cfg_if!` to configure `wee_alloc`, which we will talk more about in a [separate section](./wee_alloc.md):
We immediately notice that `cfg_if!` is a macro because it ends in `!`, similarly to other Rust macros such as `println!` and `vec!`. A macro is directly replaced by other code during compile time.
During compile time, `cfg_if!` evaluates the `if` statement. This tests whether the feature `wee_alloc` is present in the `[features]` section of `Cargo.toml` (among other possible ways to set it).
As we saw earlier, the `default` vector in `[features]` only contains `"console_error_panic_hook"` and not `"wee_alloc"`. So, in this case, the `cfg_if!` block will be replaced by no code at all, and hence the default memory allocator will be used instead of `wee_alloc`.
```rust
use wasm_bindgen::prelude::*;
```
Many modules contain a prelude, a list of things that should be automatically imported. This allows common features of the module to be conveniently accessed without a lengthy prefix. For example, in this file we can use `#[wasm_bindgen]` only because it is brought into scope by the prelude.
The asterisk at the end of this `use` indicates that everything inside the module `wasm_bindgen::prelude` (i.e. the module `prelude` inside the crate `wasm_bindgen`) can be referred to without prefixing it with `wasm_bindgen::prelude`.
For example, `#[wasm_bindgen]` could also be written as `#[wasm_bindgen::prelude::wasm_bindgen]`, although this is not recommended.
The purpose of `utils.rs` is to define the `utils` module, which contains a single function `set_panic_hook`. This function becomes part of the `utils` module in `lib.rs`, as described in the preceding section.
If the `console_error_panic_hook` feature is not enabled, then `set_panic_hook` is defined to be an inlined empty function. So, there is no run-time performance or code-size penalty incurred by its use.
2. [What is `console_error_panic_hook`?](#a2-what-is-console_error_panic_hook)
---
## 1. Defining `set_panic_hook`
```rust
use cfg_if::cfg_if;
```
This allows us to write `cfg_if!` instead of `cfg_if::cfg_if!`, identically to the line in `src/lib.rs`.
```rust
cfg_if! {
if #[cfg(feature = "console_error_panic_hook")] {
extern crate console_error_panic_hook;
pub use self::console_error_panic_hook::set_once as set_panic_hook;
} else {
#[inline]
pub fn set_panic_hook() {}
}
}
```
As described in the preceding section, the macro `cfg_if!` evaluates the `if` statement during compile time. This is possible because it is essentially testing whether `"console_error_panic_hook"` is defined in the `[features]` section of `Cargo.toml`, which is available during compile time.
The entire macro block will either be replaced with the statements in the `if` block or with those in the `else` block. These two cases are now described in turn:
```rust
extern crate console_error_panic_hook;
pub use self::console_error_panic_hook::set_once as set_panic_hook;
```
Due to the `use` statement, the function `self::console_error_panic_hook::set_once` can now be accessed more conveniently as `set_panic_hook`. Due to `pub`, this function will be publicly accessible outside of the `utils` module as `utils::set_panic_hook`.
```rust
#[inline]
pub fn set_panic_hook() {}
```
An inline function replaces the function call with the contents of the function during compile time. Here, `set_panic_hook` is defined to be an empty inline function. This allows the use of `set_panic_hook` without any run-time or code-size performance penalty if the feature is not enabled.
## 2. What is `console_error_panic_hook`?
The crate `console_error_panic_hook` enhances error messages in the web browser. This allows you to easily debug WebAssembly code.
Let's compare error messages before and after enabling the feature:
**After:** `"panicked at 'index out of bounds: the len is 3 but the index is 4', libcore/slice/mod.rs:2046:10"`
To do this, a panic hook for WebAssembly is provided that logs panics to the developer console via the JavaScript `console.error` function.
Note that although the template sets up the function, your error messages will not automatically be enhanced. To enable the enhanced errors, call the function `utils::set_panic_hook()` in `lib.rs` when your code first runs. The function may be called multiple times if needed.
For more details, see the [`console_error_panic_hook` repository](https://github.com/rustwasm/console_error_panic_hook).
Reducing the size of compiled WebAssembly code is important, since it is often transmitted over the Internet or placed on embedded devices.
*Want to learn more about code sizein the rustwasm toolchain? Check out this [documentation](https://rustwasm.github.io/docs/book/reference/code-size.html).
> `wee_alloc` is a tiny allocator designed for WebAssembly that has a (pre-compression) code-size footprint of only a single kilobyte.
[An analysis](http://fitzgeraldnick.com/2018/02/09/wee-alloc.html) suggests that over half of the bare minimum WebAssembly memory footprint is required by Rust's default memory allocator. Yet, WebAssembly code often does not require a sophisticated allocator, since it often just requests a couple of large initial allocations.
`wee_alloc` trades off size for speed. Although it has a tiny code-size footprint, it is relatively slow if additional allocations are needed.
For even more details, see the [`wee_alloc` repository](https://github.com/rustwasm/wee_alloc).
## Enabling `wee_alloc`
In `lib.rs`, we have the configuration for `wee_alloc` inside a `cfg_if!` macro:
This code block is intended to initialize `wee_alloc` as the global memory allocator, but only if the `wee_alloc` feature is enabled in `Cargo.toml`.
To do so we need to append `"wee_alloc"` to the `default` vector in `Cargo.toml`. Then, the `cfg_if!` block is replaced with the contents of the `if` block, shown above.
`wee_alloc` currently relies on features only available in Rust nightly. As such it requires you to use the nightly toolchain for compilation. If you have [Rustup](https://rustup.rs/) set up, you can install the nightly toolchain as follows:
None=>bail!("We can't figure out what your Rust version is- which means you might not have Rust installed. Please install Rust version 1.30.0 or higher."),
}
}
/// Checks if `wasm-pack` is updated to the latest version