Javascript is dead! Long live Javascript!

An adventure in sans JS web programming

whoami

  • πŸ§™πŸ»β€β™€οΈ Magical code witch πŸ§™πŸ»β€β™€οΈ
  • πŸ•ΈοΈ Runs AS207960 πŸ•ΈοΈ
  • User of πŸ¦€ rust πŸ¦€ and 🐍 python 🐍
  • https://magicalcodewit.ch

πŸ“œ A brief history of JS πŸ“œ

  • First appeared in 1995
  • Doesn't actually have that much to do with Java
  • Supported by every major browser
  • A bit on the slow side
  • New features prove problematic

πŸ˜•

πŸ†• WASM πŸ†•

The new kid on the block

But why?

  • Native or near native speed
  • Support for any non garbage collected language (gc support incoming)
  • OS level threading
  • Still sandboxed, so can't be too naughty
  • JavaScript is sticking around

Support?

Oh great so I can just write my websites in this new ✨ WebAssembly ✨ thing

πŸ™ƒ Well, eh not quite πŸ™ƒ

Issue number 1

Instantiation


WebAssembly.instantiateStreaming(fetch('expmale.wasm'), importObject)
.then(results => {
  // Do something
});
                

Issue number 2

The DOM

Issue number 3

Data types

Issue number 4

Memory management

Issue number 5

Its friggin assembly

(module
  (func $i (import "imports" "imported_func") (param i32))
  (func (export "exported_func")
    i32.const 42
    call $i
  )
)
					

Ok so how do I actually use this thing?

wasm-pack, wasm-bindgen, create-wasm-app, web-sys

wasm-pack

wasm-bindgen

extern crate wasm_bindgen;

use wasm_bindgen::prelude::*;

#[wasm_bindgen]
extern {
    pub fn alert(s: &str);
}

#[wasm_bindgen]
pub fn greet(name: &str) {
    alert(&format!("Hello, {}!", name));
}
            

create-wasm-app

web-sys

let window = web_sys::window()
                .expect("no global `window` exists");
let document = window.document()
                .expect("should have a document on window");
let body = document.body()
                .expect("document should have a body");

let val = document.create_element("p")?;
val.set_inner_html("Hello from Rust!");

body.append_child(&val)?;
                

web-sys fetch

let mut opts = RequestInit::new();
opts.method("GET");
opts.mode(RequestMode::Cors);
let request = Request::new_with_str_and_init(
  "https://api.github.com/repos/rustwasm/wasm-bindgen/", &opts,
)?;
request.headers()
  .set("Accept", "application/vnd.github.v3+json")?;
let window = web_sys::window().unwrap();
let resp_value =
  JsFuture::from(window.fetch_with_request(&request)).await?;
let resp: Response = resp_value.dyn_into().unwrap();
let json = JsFuture::from(resp.json()?).await?;
json.into_serde().unwrap();

JSX? RSX?

let col = "red";
let elm = html! {
    <div>
        <h1 style={format!("color:{};", col)}>Hello world</h1>
        <div>
          <h2 onClick=|| {alert("Hello again!");} >Click me</h2>
        </div>
        <Timer/>
    </div>
};
wasact::render(elm).unwrap();

Proc macros

#[proc_macro_hack]
pub fn html(_item: TokenStream) -> TokenStream {
    let input = match Element::parse(
        &mut _item.into_iter().peekable()
    ) {
        Ok(i) => i,
        Err(e) => panic!("Error parsing RSX: {}", e)
    };
    input.into_tokens()
}
fn into_tokens(self) -> TokenStream {
  TokenStream::from_iter::<Vec<TokenTree>>(vec![
    proc_macro::Punct::new(':', proc_macro::Spacing::Joint).into(),
    proc_macro::Punct::new(':', proc_macro::Spacing::Alone).into(),
    proc_macro::Ident::new("wasact", proc_macro::Span::call_site()).into(),
    proc_macro::Punct::new(':', proc_macro::Spacing::Joint).into(),
    proc_macro::Punct::new(':', proc_macro::Spacing::Alone).into(),
    proc_macro::Ident::new("Element", proc_macro::Span::call_site()).into(),
    proc_macro::Punct::new(':', proc_macro::Spacing::Joint).into(),
    proc_macro::Punct::new(':', proc_macro::Spacing::Alone).into(),
    proc_macro::Ident::new("Text", proc_macro::Span::call_site()).into(),
    proc_macro::Group::new(
      proc_macro::Delimiter::Parenthesis,
      TokenStream::from_iter::<Vec<TokenTree>>(vec![
        proc_macro::Literal::string(&self.0).into(),
        proc_macro::Punct::new('.', proc_macro::Spacing::Alone).into(),
        proc_macro::Ident::new("to_string", proc_macro::Span::call_site()).into(),
        proc_macro::Group::new(proc_macro::Delimiter::Parenthesis, TokenStream::new()).into()
      ]),
    ).into()
  ])
}

The code

github.com/theenbyperor/wasact

Any questions?

  • Email: [email protected]
  • Website: https://magicalcodewit.ch
  • Twitter: @TheEnbyperor
  • GitHub: TheEnbyperor (GitHub sponsors available)