使用wasm-pack构建和发布Rust WebAssembly
概述
WebAssembly(通常简称为Wasm)是一种新的代码格式,允许在Web浏览器中运行接近原生性能的应用程序。Rust是一种系统编程语言,以其安全性、并发性和性能而闻名。将Rust编译为WebAssembly并集成到Web应用程序中,可以充分利用这两种技术的优势。
安装wasm-pack
首先,你需要安装wasm-pack
,这是一个Rust工具,用于构建和打包Rust WebAssembly项目。你可以从官方GitHub仓库获取安装指南。
创建Rust WebAssembly项目
使用cargo
,Rust的包管理器和构建工具,来创建一个新的库项目:
cargo new --lib my_wasm_project
cd my_wasm_project
这里--lib
参数告诉Cargo创建一个库而不是二进制项目,因为WebAssembly模块通常作为库被Web应用程序使用。
添加依赖
在Cargo.toml
文件中添加wasm-bindgen
作为依赖项:
[dependencies]
wasm-bindgen = "0.2"
使用wasm-bindgen
wasm-bindgen
是一个宏,它允许你将Rust代码暴露给JavaScript。你需要在Rust代码中使用这个宏来定义你想要在JavaScript中使用的函数和类型。
创建一个lib.rs
文件,并使用wasm_bindgen
宏:
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn say_hello() -> String {
"Hello from Rust!".to_string()
}
这里#[wasm_bindgen]
宏将say_hello
函数暴露给JavaScript。
构建项目
使用wasm-pack
构建你的项目:
wasm-pack build --target web
这将编译你的Rust代码为WebAssembly,并生成一个包含JavaScript胶水代码的pkg
目录。
将WebAssembly模块导入到JavaScript
在构建完成后,你可以在JavaScript中导入生成的模块。首先,确保你的HTML文件链接了生成的JavaScript文件:
<script type="module">
import init, { say_hello } from './pkg/my_wasm_project.js';
async function run() {
await init(); // 初始化WebAssembly模块
console.log(say_hello()); // 调用Rust函数
}
run();
</script>
这里使用了ES6模块语法来导入init
函数和say_hello
函数。init
函数是必需的,它初始化WebAssembly模块。
扩展Rust和JavaScript的数据交互
基本数据类型交互
在Rust和JavaScript之间传递基本数据类型(如字符串、布尔值和数字)相对简单。以下是一些示例:
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn get_greeting(name: &str) -> String {
format!("Hello, {}!", name)
}
#[wasm_bindgen]
pub fn is_valid(num: u32) -> bool {
num > 10
}
#[wasm_bindgen]
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
在JavaScript中调用这些函数:
const greeting = get_greeting("Alice");
console.log(greeting); // 输出: Hello, Alice!
const isValid = is_valid(15);
console.log(isValid); // 输出: true
const sum = add(5, 10);
console.log(sum); // 输出: 15
数组和复杂对象
对于数组和对象,你可以定义相应的Rust结构体,并使用wasm_bindgen
来序列化和反序列化:
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
#[derive(Clone)]
pub struct Person {
name: String,
age: u32,
}
#[wasm_bindgen]
impl Person {
#[wasm_bindgen(constructor)]
pub fn new(name: String, age: u32) -> Person {
Person { name, age }
}
#[wasm_bindgen(method)]
pub fn get_info(&self) -> String {
format!("{} is {} years old", self.name, self.age)
}
}
在JavaScript中创建和使用:
const person = new Person("Bob", 30);
console.log(person.get_info()); // 输出: Bob is 30 years old
异步通信:Rust的Future与JavaScript的Promise
在Web开发中,异步操作非常常见。JavaScript使用Promise来处理异步操作,而Rust使用Future
。wasm-bindgen
提供了一种方式来桥接这两种异步模型。
Rust中的Future
首先,你需要一个可以返回Future
的Rust函数:
use wasm_bindgen::prelude::*;
use js_sys::Promise;
use wasm_bindgen_futures::future_to_promise;
#[wasm_bindgen]
pub fn fetch_data() -> Promise {
let future = async {
// 模拟异步操作
let data = "Some data".to_string();
// 返回结果
JsValue::from_str(&data)
};
future_to_promise(future)
}
这里使用了wasm-bindgen-futures
库来将Rust的Future
转换为JavaScript的Promise
。
JavaScript中的Promise
在JavaScript中,你可以像处理普通Promise一样处理这个异步函数:
fetch_data().then(data => {
console.log(data); // 输出: Some data
});
总结
通过上述步骤,你可以将Rust代码编译为WebAssembly,并使用wasm-bindgen
宏将其暴露给JavaScript。这为开发高性能的Web应用程序提供了一种新的方法,结合了Rust的安全性和WebAssembly的性能。
此外,通过wasm-bindgen
和wasm-bindgen-futures
,你可以在Rust和JavaScript之间进行复杂的数据类型交互和异步通信,进一步扩展了WebAssembly在Web开发中的应用范围。
进一步阅读
通过这些资源,你可以更深入地了解如何使用Rust和WebAssembly开发Web应用程序,并有效地处理异步数据交互。
转载自:https://juejin.cn/post/7388056383642697782