wasm-bindgen
的设计
本节旨在深入探讨 wasm-bindgen
在 Rust 中的内部工作原理,特别是针对 Rust。如果您在未来很长时间后阅读本文,它可能不再是最新的,但请随时打开一个问题,我们会尽力回答问题或更新它!
基础:ES 模块
关于 wasm-bindgen
的第一件事是,它从根本上建立在 ES 模块的概念之上。换句话说,这个工具认为 wasm 文件应该被视为 ES 模块。这意味着您可以从正常的 JS 文件中import
wasm 文件,使用其export
-ed 功能等。
现在不幸的是,在撰写本文时,wasm 交互的接口并不十分丰富。Wasm 模块只能调用函数或导出仅处理i32
、i64
、f32
和 f64
的函数。太糟糕了!
这就是这个项目发挥作用的地方。wasm-bindgen
的目标是使用更丰富的类型(如类、JS 对象、Rust 结构体、字符串等)来增强 wasm 模块的“ABI”。请记住,所有内容都基于 ES 模块!这意味着编译器实际上正在生成一个“损坏”的 wasm 文件。例如,由 rustc 发出的 wasm 文件没有我们想要的接口。相反,它需要 wasm-bindgen
工具来后处理该文件,生成一个 foo.js
和 foo_bg.wasm
文件。foo.js
文件是 JS 中表达的所需接口(类、类型、字符串等),而 foo_bg.wasm
模块只是一个实现细节(它只是从原始 foo.wasm
文件中稍微修改而来)。
随着时间的推移,WebAssembly 中更多功能的稳定(如组件模型),JS 文件预计会越来越小。它不太可能完全消失,但 wasm-bindgen
旨在紧密跟踪 WebAssembly 规范和提案,以尽可能优化 JS/Rust。
基础 #2:在 Rust 中不具侵入性
在更 Rust 一面的事情上,wasm-bindgen
crate 的设计目标是尽可能减少对 Rust crate 的影响。理想情况下,在关键位置添加一些 #[wasm_bindgen]
属性,然后您就可以开始使用了。该属性力求既不发明新的语法,又能与当今的现有习惯用法协同工作。
例如,一个库可能会在正常的 Rust 中公开一个函数,如下所示
# #![allow(unused_variables)] #fn main() { pub fn greet(name: &str) -> String { // ... } #}
使用 #[wasm_bindgen]
,您只需要将其导出到 JS 中
# #![allow(unused_variables)] #fn main() { #[wasm_bindgen] pub fn greet(name: &str) -> String { // ... } #}
此外,这种设计在 Rust 中的最小干预应该让我们能够轻松地利用即将推出的组件模型提案。理想情况下,您只需升级 wasm-bindgen
-the-crate 以及您的工具链,您就可以立即获得对组件模型的原始访问权限!(不过这还需要一段时间……)