Elm i Rust med Webassembly
Booster 2019
Sindre Ilebekk Johansen, Iterate AS
(@sindreij)
Elm - A delightful language for reliable webapps
Rust - Empowering everyone to build reliable and efficient software.
type alias Model =
{ count : Int }
init : Model
init =
{ count = 0 }
type Msg
= Increment
| Decrement
update : Msg -> Model -> Model
update msg model =
case msg of
Increment ->
{ model | count = model.count + 1 }
Decrement ->
{ model | count = model.count - 1 }
view : Model -> Html Msg
view model =
div []
[ button [ onClick Increment ] [ text "+1" ]
, div [] [ text <| String.fromInt model.count ]
, button [ onClick Decrement ] [ text "-1" ]
]
type alias Model =
{ count : Int }
init : Model
init =
{ count = 0 }
view : Model -> Html Msg
view model =
div []
[ button [ onClick Increment ] [ text "+1" ]
, div [] [ text <| String.fromInt model.count ]
, button [ onClick Decrement ] [ text "-1" ]
]
type Msg
= Increment
| Decrement
update : Msg -> Model -> Model
update msg model =
case msg of
Increment ->
{ model | count = model.count + 1 }
Decrement ->
{ model | count = model.count - 1 }
MODEL
view
VDOM
render
DOM
Update
MODEL'
VDOM'
msg
view
#[derive(Clone)]
struct Model {
counter: i32,
}
fn init() -> Model {
Model { counter: 0 }
}
enum Msg {
Increment,
Decrement,
}
fn update(msg: &Msg, model: &Model) -> Model {
let mut model = model.clone();
match msg {
Msg::Increment => model.counter += 1,
Msg::Decrement => model.counter -= 1,
}
model
}
fn view(model: &Model) -> Html<Msg> {
div(
&[],
&[
button(&[on_click(Msg::Increment)], &[text("+")]),
div(&[], &[text(&model.counter.to_string())]),
button(&[on_click(Msg::Decrement)], &[text("-")]),
],
)
}
type alias Model =
{ count : Int }
init : Model
init =
{ count = 0 }
type Msg
= Increment
| Decrement
update : Msg -> Model -> Model
update msg model =
case msg of
Increment ->
{ model | count = model.count + 1 }
Decrement ->
{ model | count = model.count - 1 }
view : Model -> Html Msg
view model =
div []
[ button [ onClick Increment ] [ text "+1" ]
, div [] [ text <| String.fromInt model.count ]
, button [ onClick Decrement ] [ text "-1" ]
]
fn div(children: &[Html]) -> Html {
[???]
}
fn button(children: &[Html]) -> Html {
[???]
}
fn text(s: &str) -> Html {
[???]
}
pub struct Model {
counter: i32,
}
fn init() -> Model {
Model { counter: 0 }
}
fn view(model: &Model) -> Html {
div(
&[
button(&[text("+")]),
div(&[text(&model.counter.to_string())]),
button(&[text("-")]),
],
)
}
enum Html {
Tag {
name: String,
children: Vec<Html>,
},
Text(String),
}
<div>
<a>Hello World</a>
<p>This is a test</p>
</div>
name
children
fn div(children: &[Html]) -> Html {
Html::Tag {
name: "div".to_string(),
children: children.to_vec(),
}
}
fn button(children: &[Html]) -> Html {
Html::Tag {
name: "button".to_string(),
children: children.to_vec(),
}
}
fn text(s: &str) -> Html {
Html::Text(s.to_string())
}
#[wasm_bindgen]
pub fn start() {
let model = init();
let vdom = view(&model);
render(&vdom)
.expect("Error rendering");
}
magi (wasm-pack + wasm-bindgen)
// index.js
import * as wasm from '../pkg';
wasm.start();
fn create_node(vdom: &Html) -> Result<Node, JsValue> {
let window = web_sys::window()?;
let document = window.document()?
match vdom {
Html::Tag {
name,
attrs,
children,
} => {
let res: HtmlElement = document
.create_element(&name)?
.dyn_into()?;
let res: Node = res.into();
for child in children {
let node = create_node(&child)?;
res.append_child(&node)?;
}
Ok(res)
}
Html::Text(text) => {
let res = document.create_text_node(&text);
Ok(res.into())
}
}
}
function create_node(vdom) {
let document = window.document;
if (vdom.type === 'tag') {
let res = document.createElement(vdom.name);
vdom.children.forEach(child => {
let node = create_node(child);
res.appendChild(node);
})
return res;
}
else if (vdom.type === 'text') {
let res = document.createTextNode(vdom.text);
return res;
}
}
fn render(vdom: &Html) -> Result<Node, JsValue> {
let window = web_sys::window()?;
let document = window.document()?;
let parent: Node = document
.get_element_by_id("app")?
.into();
let root = create_node(vdom)?;
parent.append_child(&root)?;
}
function render(vdom) {
let document = window.document;
let parent = document.getElementById("app");
let root = create_node(vdom);
parent.appendChild(&root)?;
}
MODEL
view
VDOM
render
DOM
Update
MODEL'
view
VDOM'
???
msg
https://github.com/sindreij/willow
@sindreij
Elm i Rust med Webassembly
By sindreij
Elm i Rust med Webassembly
Boosterconf 2019
- 1,364