By
Vika Zhou
2024-02-02
更新日期:2025-11-24
wasm-bingen是一个Rust库与命令行工具,解决wasm模块与Javascript之间的交互。 在Rust代码中使用#[wasm_bindgen]来将Javascript变量与方法导入到Rust代码,和将Rust代码中声明的方法导出到Javascript中。 wasm-bingen提供交互机制与定义基本类型,而crate js-sys与web-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 cargo install wasm-pack cargo install cargo-generate cargo generate --name wasm-bind-hello --git https://github.com/rustwasm/wasm-pack-template cd wasm-bind-hellols
项目目录下的内容如下,
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 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" { #[wasm_bindgen(js_namespace = console)] fn log (s: &str ); #[wasm_bindgen(js_namespace = console, js_name = log)] fn log_u32 (a: u32 ); #[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!" ); } macro_rules! console_log { ($($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 ); } 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登录到仓库。