写了三年 Rust,今天才发现它的 WebAssembly target 从来不是同一个——这件事被 WASI 0.3 彻底原生化了

写了三年 Rust,今天才发现它的 WebAssembly target 从来不是同一个——这件事被 WASI 0.3 彻底原生化了


Rust 团队 2026 年给自己立了个 flag:让 Wasm Component 在 Rust 里真正能用。这意味着同时推进三个编译器 target,每一个都对应不同的场景和不同的成熟度——但很少有人一次性把这三路的区别说清楚。

wasm32-unknown-unknown:最常用,也最脆弱

这是大多数 Rust Wasm 项目的起点。你 rustup target add wasm32-unknown-unknown 之后,cargo build –target wasm32-unknown-unknown 就能跑。它的问题在于:没有标准库,没有系统接口,写文件?不行。发 HTTP?不行。一切 I/O 都要自己通过 wasm-bindgen 绑定到 JavaScript API 上。

这个 target 实际上依赖的是浏览器或者 Node.js 的 JavaScript 宿主环境。Rust 官方文档自己都说,这个 target “rather brittle”(相当脆弱)。

wasm32-wasip2 / wasm32-wasip3:系统接口的入口

如果你想在 Wasm 里读写文件、发 HTTP 请求,wasm32-unknown-unknown 给不了你,要用 WASI target。WASI(WebAssembly System Interface)是一套标准化的系统接口,让 Wasm 模块可以调用操作系统级别的能力。

wasm32-wasip2 是目前最稳定的 WASI target,Wasmtime 和各种边缘运行时都支持。但它有一个致命缺陷:没有原生异步支持。所有 I/O 操作都是同步的,你要么阻塞线程(高并发场景不可接受),要么自己实现事件循环(等于在 Wasm 里又跑了一套异步运行时)。

wasm32-wasip3 就是来解决这个问题的。WASI 0.3 规范在 2026 年 6 月 11 日正式 ratified,把 streamfuture 这两个类型直接做进了 Component Model 的 ABI 里。这意味着:Rust 的 async/await 终于可以在 Wasm 层面原生使用了,不需要任何回调轮询。代价是:目前 wasm32-wasip3 还是 Tier 3(最低档),不在 Rust CI 的标准测试矩阵里,而且需要 wasi-sdk 22 以上版本。

wasm32-component:跨语言拼图的关键

前两个 target 输出的是 core wasm module,wasm32-component 输出的是 WebAssembly Component。这是两个层面的东西:core module 是二进制指令块,Component 在此之上加了一层接口描述(WIT)和类型安全的跨语言边界。

Component 才是 Bytecode Alliance 真正想让你用的东西。它的价值在于:一份 WIT 接口定义,Rust / Go / Python / JavaScript 各自生成绑定,组装在一起时二进制层面零拷贝。你不需要 JSON 序列化,不需要 HTTP,不需要任何进程间通信协议——编译器帮你把类型对类型直接翻译了。

但代价是:浏览器目前还没有原生支持 Component Model。Chromium / Firefox / Safari 都还在讨论实现路径。这意味着 wasm32-component 目前是纯服务端/边缘计算的故事。

三路并存才是现实

所以今天 Rust 写 Wasm,面临的是一个三叉路口:

  • 想在浏览器里跑?用 wasm32-unknown-unknown,接受没有系统接口的约束
  • 想在边缘运行时跑高性能异步逻辑?用 wasm32-wasip3,但工具链还在追赶
  • 想做真正的跨语言组件组合?用 wasm32-component,但先别指望浏览器

WASI 0.3 把最关键的异步能力补上了,这是从 0.2 到 0.3 最实质的跨越。在此之前,Wasm 的异步 I/O 是个”谁用谁自己实现”的状态;现在标准直接管了。但 wasm32-wasip3 本身升 Tier 3 还没多久,生产项目用它需要接受工具链的不确定性。

下一步是什么

如果你现在在选型阶段:优先用 wasm32-wasip2 跑生产,wasm32-wasip3 做技术储备关注。wasm32-component 是值得投入的方向,但先把 WIT 接口设计好——这是组件化里唯一不能 later 的部分。

如果你在维护一个 wasm32-unknown-unknown 项目,不要指望它自然迁移到 WASI target:两个 target 的执行模型完全不同,JavaScript 绑定 vs 系统接口调用,改起来比你想象的更接近重写。

一个判断标准:你的 Wasm 模块现在有没有在 wasm-bindgen 里手动绑定 fetch()?有的话,先不要动。WASI 的世界等它成熟一点再说。

评论区

0 条评论

登录后可评论。

铁锈·Rust工具链 14 阅读