Crates.io | px-wsdom |
lib.rs | px-wsdom |
version | 0.0.2 |
source | src |
created_at | 2024-12-10 00:24:41.003298 |
updated_at | 2024-12-10 00:24:41.003298 |
description | roundtrip-free Rust to JavaScript *remote method invocation* or *distributed objects* system |
homepage | |
repository | https://github.com/wishawa/wsdom |
max_upload_size | |
id | 1477922 |
size | 11,305 |
"LiveView" frameworks like Phoenix LiveView, LiveViewJS, and Dioxus LiveView are amazing. But why limit ourselves to LiveView? Why not LiveEverything?
WSDOM is a Rust → JavaScript Remote Method Invocation or Distributed Objects system. It lets Rust code hold JavaScript objects and call methods/functions over the network.
WSDOM can be used to add network-dependent functionalities to webpages without writing JS code or making API endpoints. It can also be integrated into "LiveView"-style Rust web frameworks to expose access to the full Web API.
Here is an example using WSDOM to put <div>Hello World!</div>
on a webpage.
// 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/");
Our full "Hello World!" code is available here.
.d.ts
TypeScript definitions.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
}
does not block on the network at all; it will finish in microseconds.
let val_retrieved: f64 = val.retrieve_float().await;
println!("the value of (cos^[100])(1.0) computed in JavaScript is {val_retrieved}");
the .await
will take one network roundtrip.Math.cos
calls in our loop above throws,
the Rust loop will still complete all 100 iterations without panic or any sort of warning (see How It Works for why).
As you might expect, this means code using WSDOM are very painful to debug.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!");
}
Hosted examples are available. When viewing them, I recommend opening your browser's network devtool to see the WebSocket traffic.
WSDOM serves a similar role as web-sys (and a bit of js-sys too), but instead of running your Rust in WebAssembly in the same browser, we let you run your Rust code away across a WebSocket connection.
WSDOM's translation of JS API to Rust is different from web-sys.
We translate from TypeScript declarations, rather than directly from WebIDLs.
The network gap also means our optional types take the form of JsNullable<_>
(compared to the Option<_>
of web-sys).
WSDOM and jsdom are similar in that we both expose the web browser's API outside a web browser. jsdom does so by implementing the API themselves. WSDOM does so by forwarding calls to a real web browser running across a WebSocket connection.
The How It Works document describes how WSDOM works in more details.
The crate is on crates.io and the documentation is on docs.rs.
Use WSDOM at your own risk. It is alpha-quality at best.
The Rust code produced by our .d.ts
loader might change between WSDOM versions.