1 个不稳定版本
0.0.1 | 2024年3月15日 |
---|
#235 in #远程
1.5MB
17K SLoC
"LiveView" 框架,如 Phoenix LiveView、LiveViewJS 和 Dioxus LiveView 都很棒。但我们为什么要限制自己使用 LiveView 呢?为什么不尝试 LiveEverything 呢?
WSDOM
WSDOM 是一个无需往返的 Rust → JavaScript 远程方法调用 或 分布式对象 系统。它允许 Rust 代码持有 JavaScript 对象,并通过网络调用方法/函数。
WSDOM 可以用来添加网络依赖的功能到网页,而无需编写 JS 代码或创建 API 端点。它还可以集成到 "LiveView" 风格的 Rust 网页框架中,以暴露对完整 Web API 的访问。
快速示例
以下是一个使用 WSDOM 将 <div>Hello World!</div>
放置在网页上的示例。
// this Rust code runs on your web server
fn hello(browser: wsdom::Browser) {
let document = wsdom::dom::document(&browser) // get hold of a Document object
let body = document.get_body(); // get the <body /> of that document object
let elem = document.create_element(&"div", &wsdom::undefined()); // create a <div />
elem.set_inner_text(&"Hello World!"); // set the text
body.append_child(&elem); // add the <div /> to the <body />
}
// this JavaScript code runs on the browser
WSDOMConnectWebSocket("ws://my-website.domain:4000/");
我们的完整 "Hello World!" 代码可以在 这里 找到。
关键特性(和反特性)
- WSDOM 根据
.d.ts
TypeScript 定义生成基于 强类型 的 Rust 存根。 - 使用 WSDOM 调用 JS 代码是 无需往返 的。这段 Rust 代码
根本不会在网络上阻塞;它将在微秒内完成。let mut val: JsNumber = browser.new_value(&1.0); for _ in 0..100 { val = wsdom::js::Math::cos(&browser, &val); // Math.cos on the JS side }
- 无需往返调用之所以可能,是因为 WSDOM 在 JS 端保持值,仅在明确请求时才将它们发送回 Rust。要获取上面循环计算出的值,可以这样操作
的let val_retrieved: f64 = val.retrieve_float().await; println!("the value of (cos^[100])(1.0) computed in JavaScript is {val_retrieved}");
.await
将需要一次网络往返。
- 无需往返调用之所以可能,是因为 WSDOM 在 JS 端保持值,仅在明确请求时才将它们发送回 Rust。要获取上面循环计算出的值,可以这样操作
- 由于无需往返的设计,WSDOM 基本上 无法处理 JS 异常。
- 如果我们上面的循环中的
Math.cos
调用抛出异常,Rust 循环仍将完成所有 100 次迭代,而不会崩溃或发出任何警告(有关原因,请参阅 How It Works)。正如你所预期的那样,这意味着使用 WSDOM 的代码 非常难以调试。
- 如果我们上面的循环中的
- WSDOM 是 单向的。Rust 代码可以调用 JS 代码,但不能反过来。
- 为了使事件处理成为可能,我们提供了基于 Future 的交互性;我们将 JS 回调连接到可以在 Rust 端等待的流。
async fn example(browser: Browser, button: &HTMLElement) { let (stream, callback) = wsdom::callback::new_callback::<MouseEvent>(&browser); button.add_event_listener(&"click", &callback, &wsdom::undefined()); let _click_event: MouseEvent = stream.next().await; // wait for the Stream to yield println!("button was clicked on the browser!"); }
- 为了使事件处理成为可能,我们提供了基于 Future 的交互性;我们将 JS 回调连接到可以在 Rust 端等待的流。
- WSDOM 是 传输无关、框架无关 和 执行器无关 的。话虽如此,我们提供了一个集成库,方便您在 Axum 网页框架(使用 Tokio 执行器)上使用 WebSocket 快速入门。
示例
托管示例可供使用。查看它们时,我建议您打开浏览器中的网络开发工具来查看 WebSocket 流量。
- 计数器示例:[代码](https://github.com/examples/many-examples/src/counter.rs) [演示](http://141.145.215.129:4000/counter)
- 音频 API 示例:[代码](https://github.com/examples/many-examples/src/audio.rs) [演示](http://141.145.215.129:4000/audio)
- 画布 API 示例:[代码](https://github.com/examples/many-examples/src/canvas.rs) [演示](http://141.145.215.129:4000/canvas)
比较
web-sys
WSDOM 与 web-sys 扮演着类似的角色(以及一点 js-sys),但不同之处在于,我们不是在同一个浏览器中运行您的 Rust 代码作为 WebAssembly,而是让您通过 WebSocket 连接运行您的 Rust 代码。
WSDOM 将 JS API 转换为 Rust 的方式与 web-sys 不同。我们是从 TypeScript 声明中转换的,而不是直接从 WebIDL 中转换。网络差距还意味着我们的可选类型以 JsNullable<_>
(与 web-sys 的 Option<_>
相比)的形式出现。
jsdom
WSDOM 和 jsdom 类似,我们都在网页浏览器外部公开了网页浏览器的 API。jsdom 是通过自己实现 API 来实现的。WSDOM 是通过转发调用到在 WebSocket 连接上运行的真正网页浏览器来实现的。
详情
《工作原理》文档更详细地描述了 WSDOM 的工作方式。
该软件包位于 crates.io,文档位于 docs.rs。
免责声明
请自行承担使用 WSDOM 的风险。它最多是 alpha 质量。
我们的 .d.ts
加载器生成的 Rust 代码可能在 WSDOM 版本之间发生变化。
依赖关系
~1.5–2.3MB
~49K SLoC