1 先判断:也许你的 crate 已经能跑 Wasm!
-
排查阻碍因素
- 直接文件/网络 I/O
- 块式(同步)I/O
std::thread
线程创建- 并不受支持的 C 系统库绑定
-
快速验证
rustup target add wasm32-unknown-unknown
cargo build --target wasm32-unknown-unknown
能编译=“理论可用”。要 100% 确认 & 持续可用 → 加入 CI 测试(§6)。
2 添加 Wasm 支持的关键步骤
2.1 把 I/O 从库中“切”出去
浏览器只有 异步 I/O,且无文件系统。
让调用者负责获取字节切片,再传给库。
// ❌ 旧:直接读文件
pub fn parse_thing(path: &Path) -> Result<MyThing, MyError> {let bytes = std::fs::read(path)?;parse_thing_inner(&bytes)
}// ✅ 新:纯逻辑函数 + helper
pub fn parse_thing(bytes: &[u8]) -> Result<MyThing, MyError> { /* … */ }
pub fn parse_thing_from_file(path: &Path) -> Result<MyThing, MyError> {parse_thing(&std::fs::read(path)?)
}
2.2 条件依赖 wasm-bindgen
如果实在要访问 JS 环境(DOM、Fetch 等):
[target.'cfg(target_arch = "wasm32")'.dependencies]
wasm-bindgen = "0.2"
js-sys = "0.3"
web-sys = { version = "0.3", features = ["Window", "Response"] }
Tip:把 JS 交互封装进 #[cfg(target_arch = "wasm32")] mod js;
中,保持 API 跨平台一致。
2.3 避免 同步 I/O → 拥抱 Future
use futures::Future;pub async fn do_work<F>(reader: F) -> MyOtherThing
whereF: Future<Output = MyThing>,
{let item = reader.await;// …
}
在 Web 端
reader
可用fetch()
实现;在本地可用 Tokio 非阻塞文件读取。
2.4 避免 线程 或让用户“自带线程”
-
2025 年浏览器已在 跨源隔离 (COOP+COEP) 环境下开放 Wasm 线程,但仍非所有站点都能启用;Safari 仍缺省关闭。([Apryse][1], [queue.acm.org][2])
-
建议:
- 用
#[cfg(target_arch = "wasm32")]
禁用线程路径; - 或提供 trait 让调用者决定如何并行。
- 用
trait WorkPool {fn spawn<Fut: Future<Output = ()> + 'static + Send>(&self, fut: Fut);
}
3 持续集成:保证 永不回退
# .github/workflows/ci.yml 片段
- name: Install wasm targetrun: rustup target add wasm32-unknown-unknown- name: Check compilerun: cargo check --target wasm32-unknown-unknown
仅用
cargo check
即可捕获大部分编译错误,速度快。
4 单元测试:Node.js & Headless Browser
-
添加依赖
[dev-dependencies] wasm-bindgen-test = "0.3"
-
编写测试
use wasm_bindgen_test::*;wasm_bindgen_test_configure!(run_in_browser);#[wasm_bindgen_test] fn parse_roundtrip() {// … }
-
运行
cargo install wasm-pack wasm-pack test --headless --chrome
集成到 CI 后,每次 PR 都能验证浏览器行为。
5 版本管理与生态兼容
组件 | 2025 推荐版本 | 说明 |
---|---|---|
wasm-bindgen | 0.2.92+ | 兼容 Rust 1.77+,支持 Component Model 预览 |
wasm-pack | 0.12.2 | 新增 --vite 模板,默认生成 ESM |
wasm-bindgen-futures | 0.4.42 | 与 Future /async 接口对接 |
wasm-mt (可选) | 0.3 | 简化 Web Worker 线程协调 ([GitHub][3]) |
6 Checklist
-
cargo check --target wasm32-unknown-unknown
通过 - I/O 抽象成字节/流;无阻塞调用
-
#[cfg]
屏蔽std::fs
,std::net
,std::thread
- JS 交互封装在
wasm-bindgen
模块 - CI 添加 wasm 目标 + 浏览器测试
- 发布前
wasm-pack build --release
验证 npm 包元数据
7 结语
- 最小可行支持:先让代码 能编;再抽象 I/O、线程,保证 API 稳定。
- 长期维护:CI 双目标(native & wasm)、浏览器自动测试、定期升级依赖。
- 未来展望:WASI 0.3 + Component Model 正在进入稳定通道,Rust 生态将进一步简化跨平台发布流程。([Uno Platform][4])
做好以上步骤,你的通用 crate 就能“既跑桌面又跑浏览器”,社区受众瞬间扩大数倍。祝迁移顺利!