文章目录
  1. 1. 创建wasm-bindgen项目
    1. 1.1. 使用wasm-pack来编译项目
  2. 2. 使用console.log
  3. 3. wasm-pack的使用

wasm-bingen是一个Rust库与命令行工具,解决wasm模块与Javascript之间的交互。 在Rust代码中使用#[wasm_bindgen]来将Javascript变量与方法导入到Rust代码,和将Rust代码中声明的方法导出到Javascript中。 wasm-bingen提供交互机制与定义基本类型,而crate js-sysweb-sys则是实现具体功能,分别将Javascript的变量与DOM变量导入到Rust代码中。

本文内容主要参考:

使用的工具:

  • cargo-generate 从git模板仓库来创建新的项目
  • wasm-pack 创建、编译Rust wasm项目
  • npm 用来创建web项目,在js中引用生成的wasm模

创建wasm-bindgen项目

这里使用cargo-generate来创建项目, 将根据模板wasm-pack-template来生成内容。命令wasm-pack new也能用来创建项目,不过底层也是依赖工具cargo-generate; 另外也能通过cargo new创建空白项目后在Cargo.toml中添加依赖wasm-bindgen依赖。

1
2
3
4
5
6
7
# 安装工具wasm-pack, cargo-generate
cargo install wasm-pack
cargo install cargo-generate
# 创建项目,提示输入项目名称时录入wasm-bind-hello, 或者通过参数--name指定项目名称
cargo generate --name wasm-bind-hello --git https://github.com/rustwasm/wasm-pack-template
cd wasm-bind-hello
ls

项目目录下的内容如下,

1
2
3
4
5
6
7
8
9
10
$ tree
├── Cargo.toml
├── LICENSE_APACHE
├── LICENSE_MIT
├── README.md
├── src
│   ├── lib.rs
│   └── utils.rs
└── tests
└── web.rs

Cargo.toml是Rust的配置文件。 依赖项[dependencies]中已经添加wasm-bindgen; 另外[lib]crate-type包含cdylib, 用于生成.wasm文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[package]
name = "wasm-bind-hello"
version = "0.1.0"
authors = ["Person"]
edition = "2018"

[lib]
crate-type = ["cdylib", "rlib"]

[features]
default = ["console_error_panic_hook"]

[dependencies]
wasm-bindgen = "0.2.84"

console_error_panic_hook = { version = "0.1.7", optional = true }

[dev-dependencies]
wasm-bindgen-test = "0.3.34"

[profile.release]
opt-level = "s"

src/lib.rs是示例库的Rust代码,内容如下。使用use wasm_bindgen::prelude::*;使用wasm_bindgen库中定义的功能,#[wasm_bindgen]用于标识要导入与导出的方法、变量; extern "C" 指明使用c方式调用外部函数,这里是将js中的alert函数引入到Rust中; Rust函数greet()导出到js
中使用,而函数体中又调用了js的方法alert

1
2
3
4
5
6
7
8
9
10
11
12
13
mod utils;

use wasm_bindgen::prelude::*;

#[wasm_bindgen]
extern "C" {
fn alert(s: &str);
}

#[wasm_bindgen]
pub fn greet() {
alert("Hello, wasm-bind-hello!");
}

src/utils.rs的内容如下,在这里没有使用到。

1
2
3
4
pub fn set_panic_hook() {
#[cfg(feature = "console_error_panic_hook")]
console_error_panic_hook::set_once();
}

使用wasm-pack来编译项目

接下来在项目目录下执行wasm-pack来编译项目, 构建产物的目标文件夹为pkg,包含wasm与_bg.js文件。wasm_bind_hello_bg.js实现wasm模块的导入与方法参数的处理,wasm_bind_hello.js用于js中引用Rust中导出的函数。

1
2
wasm-pack build
ls pkg
1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ tree pkg
├── package.json
├── README.md
├── wasm_bind_hello_bg.js
├── wasm_bind_hello_bg.wasm
├── wasm_bind_hello_bg.wasm.d.ts
├── wasm_bind_hello.d.ts
└── wasm_bind_hello.js

$ cat pkg/wasm_bind_hello.js
import * as wasm from "./wasm_bind_hello_bg.wasm";
import { __wbg_set_wasm } from "./wasm_bind_hello_bg.js";
__wbg_set_wasm(wasm);
export * from "./wasm_bind_hello_bg.js";

使用console.log

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
use wasm_bindgen::prelude::*;

#[wasm_bindgen(start)]
pub fn run() {
bare_bones();
using_a_macro();
using_web_sys();
}

#[wasm_bindgen]
extern "C" {
// 使用`js_namespace`绑定到`console.log(..)`,调用时只需要使用`log(..)`
#[wasm_bindgen(js_namespace = console)]
fn log(s: &str);

// 使用js_name指定要绑定的方法名,可以实现不同的别名调用同一个方法
#[wasm_bindgen(js_namespace = console, js_name = log)]
fn log_u32(a: u32);

// Multiple arguments too!
#[wasm_bindgen(js_namespace = console, js_name = log)]
fn log_many(a: &str, b: &str);
}

fn bare_bones() {
log("Hello from Rust!");
log_u32(42);
log_many("Logging", "many values!");
}

// 定义一个宏,类似于`println!`
macro_rules! console_log {
// Note that this is using the `log` function imported above during
// `bare_bones`
($($t:tt)*) => (log(&format_args!($($t)*).to_string()))
}

fn using_a_macro() {
console_log!("Hello {}!", "world");
console_log!("Let's print some numbers...");
console_log!("1 + 3 = {}", 1 + 3);
}

// 使用库`web_sys`中已经定义的方法
fn using_web_sys() {
use web_sys::console;

console::log_1(&"Hello using web-sys".into());

let js: JsValue = 4.into();
console::log_2(&"Logging arbitrary values looks like".into(), &js);
}

wasm-pack的使用

  • wasm-pack new hello-wasm 创建新的项目,依赖于cargo-generate
  • wasm-pack build 构建项目。使用--target参数指定不同构建目标,支持 bundler,nodejs,web,no-modules
  • wasm-pack publish将包发布到npm, wasm-pack login登录到仓库。
文章目录
  1. 1. 创建wasm-bindgen项目
    1. 1.1. 使用wasm-pack来编译项目
  2. 2. 使用console.log
  3. 3. wasm-pack的使用