2 unstable releases
0.2.0 | May 8, 2020 |
---|---|
0.1.0 | Mar 13, 2019 |
#10 in #vdom
Used in dodrio
195KB
3.5K
SLoC
Implementing dodrio
render components with JavaScript.
This crate provides a Rust type JsRender
that wraps a JavaScript object with a
render
method. JsRender
implements dodrio::Render
by calling its wrapped
object's render
method to get a JavaScript virtual DOM represented as a tree
of JavaScript values. It then converts this tree of JavaScript values into
dodrio
's normal bump-allocated virtual DOM representation.
This is likely much slower than rendering virtual DOMs directly into the bump
allocator from the Rust side of things! Additionally, the shape of the
JavaScript virtual DOM is a bit funky and unidiomatic. Keep in mind that this
crate exists as a proof of concept for integrating JavaScript components into
dodrio
-- which is itself also experimental -- and so this crate definitely
has some rough edges.
Example
Here is a JavaScript implementation of a rendering component:
class Greeting {
constructor(who) {
this.who = who;
}
render() {
return {
tagName: "p",
attributes: [
{
name: "class",
value: "greeting",
},
],
listeners: [
{
on: "click",
callback: this.onClick.bind(this),
}
],
children: [
"Hello, ",
{
tagName: "strong",
children: [this.who],
}
],
};
}
async onClick(vdom, event) {
// Be more excited!
this.who += "!";
// Schedule a re-render.
await vdom.render();
console.log("re-rendering finished!");
}
}
And here is a Rust rendering component that internally uses the JS rendering component:
use dodrio::{Node, Render, RenderContext, Vdom};
use dodrio_js_api::JsRender;
use js_sys::Object;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern {
// Import the JS `Greeting` class.
#[wasm_bindgen(extends = Object)]
#[derive(Clone, Debug)]
type Greeting;
// And the `Greeting` class's constructor.
#[wasm_bindgen(constructor)]
fn new(who: &str) -> Greeting;
}
/// This is our Rust rendering component that wraps the JS rendering component.
pub struct GreetingViaJs {
js: JsRender,
}
impl GreetingViaJs {
/// Create a new `GreetingViaJs`, which will internally create a new JS
/// `Greeting`.
pub fn new(who: &str) -> GreetingViaJs {
let js = JsRender::new(Greeting::new(who));
GreetingViaJs { js }
}
}
/// And finally the `Render` implementation! This adds a `<p>` element and some
/// text around whatever the inner JS `Greeting` component renders.
impl<'a> Render<'a> for GreetingViaJs {
fn render(&self, cx: &mut RenderContext<'a>) -> Node<'a> {
use dodrio::builder::*;
p(&cx)
.children([
text("JavaScript says: "),
self.js.render(cx),
])
.finish()
}
}
Dependencies
~7.5–10MB
~184K SLoC