WebAssembly

These examples are written in a WAT (WebAssembly text format) DSL using Elixir macros. I plan to make it an open source library soon.

You can view the modules’ source on GitHub.

Custom HTML elements are used to load and bootstrap the Wasm modules in the browser:


Stateful Counter that renders to HTML

Server with initial HTML + Client side rendering:

If you view source, you can see the server renders initial HTML. And then the exact same .wasm module is loaded in the browser for interactivity.

0

Client side rendering only:

The initial HTML from the server is just a loader, with only the browser loading the wasm file.

Loading…

Lazy client-side rendering only:

Loading…
View $CounterHTML Wasm source
(module $CounterHTML
  (import "env" "buffer" (memory 1))
  (global $count (mut i32) (i32.const 0))
  (global $body_chunk_index (mut i32) (i32.const 0))
  (global $bump_offset (mut i32) (i32.const 1024))
  (data (i32.const 255) "<output class=\"flex p-4 bg-gray-800\">")
  (data (i32.const 293) "</output>")
  (data (i32.const 303) "\n<button data-action=\"increment\" class=\"mt-4 inline-block py-1 px-4 bg-white text-black rounded\">Increment</button>")
  (func $get_current (export "get_current") (result i32)
    (global.get $count)
  )
  (func $increment (export "increment") (result i32)
    (i32.add (global.get $count) (i32.const 1))
    (global.set $count)
    (global.get $count)
  )
  (func $rewind (export "rewind") 
    (local $i i32)
    (i32.const 0)
    (global.set $body_chunk_index)
    (i32.const 1024)
    (global.set $bump_offset)
    (i32.const 64)
    (local.set $i)
    (loop $Clear
      (i32.store (i32.add (local.get $i) (i32.const 1024)) (i32.const 0))
      (if (i32.gt_u (local.get $i) (i32.const 0))
        (then
          (i32.sub (local.get $i) (i32.const 1))
          (local.set $i)
          br $Clear
        )
      )
    )
  )
  (func $i32toa (param $value i32) (result i32)
    (local $working_offset i32)
    (local $digit i32)
    (i32.add (global.get $bump_offset) (i32.const 11))
    (global.set $bump_offset)
    (global.get $bump_offset)
    (local.set $working_offset)
    (loop $Digits
      (i32.sub (local.get $working_offset) (i32.const 1))
      (local.set $working_offset)
      (i32.rem_u (local.get $value) (i32.const 10))
      (local.set $digit)
      (i32.div_u (local.get $value) (i32.const 10))
      (local.set $value)
      (i32.store8 (local.get $working_offset) (i32.add (i32.const 48) (local.get $digit)))
      (i32.gt_u (local.get $value) (i32.const 0))
      br_if $Digits
    )
    (local.get $working_offset)
  )
  (func $next_body_chunk (export "next_body_chunk") (result i32)
    (block $Main (result i32)
      (if (i32.eq (global.get $body_chunk_index) (i32.const 0))
        (then
          (i32.const 255)
          br $Main
        )
      )
      (if (i32.eq (global.get $body_chunk_index) (i32.const 1))
        (then
          (call $i32toa (global.get $count))
          br $Main
        )
      )
      (if (i32.eq (global.get $body_chunk_index) (i32.const 2))
        (then
          (i32.const 293)
          br $Main
        )
      )
      (if (i32.eq (global.get $body_chunk_index) (i32.const 3))
        (then
          (i32.const 303)
          br $Main
        )
      )
      (i32.const 0)
    )
    (i32.add (global.get $body_chunk_index) (i32.const 1))
    (global.set $body_chunk_index)
  )
)

Form State Machine

    State:
    View $Form Wat source
    (module $Form
      (global $edited (export "edited") i32 (i32.const 1))
      (global $submitting (export "submitting") i32 (i32.const 2))
      (global $succeeded (export "succeeded") i32 (i32.const 3))
      (global $failed (export "failed") i32 (i32.const 4))
      (global $initial (export "initial") (mut i32) (i32.const 0))
      (global $state (mut i32) (i32.const 0))
      (global $edit_count (mut i32) (i32.const 0))
      (global $submitted_edit_count (mut i32) (i32.const 0))
      (func $get_current (export "get_current") (result i32)
        (global.get $state)
      )
      (func $get_edit_count (export "get_edit_count") (result i32)
        (global.get $edit_count)
      )
      (func $get_submitted_edit_count (export "get_submitted_edit_count") (result i32)
        (global.get $submitted_edit_count)
      )
      (func $user_can_edit? (export "user_can_edit?") (result i32)
        (i32.eqz (i32.eq (global.get $state) (global.get $submitting)))
      )
      (func $user_can_submit? (export "user_can_submit?") (result i32)
        (i32.eqz (i32.eq (global.get $state) (global.get $submitting)))
      )
      (func $user_did_edit (export "user_did_edit") 
        (if (i32.or (i32.eq (global.get $state) (global.get $initial)) (i32.or (i32.eq (global.get $state) (global.get $edited)) (i32.or (i32.eq (global.get $state) (global.get $succeeded)) (i32.eq (global.get $state) (global.get $failed)))))
          (then
            (global.get $edited)
            (global.set $state)
            (i32.add (global.get $edit_count) (i32.const 1))
            (global.set $edit_count)
          )
        )
      )
      (func $user_did_submit (export "user_did_submit") 
        (if (i32.eqz (i32.eq (global.get $state) (global.get $submitting)))
          (then
            (global.get $submitting)
            (global.set $state)
            (global.get $edit_count)
            (global.set $submitted_edit_count)
          )
        )
      )
      (func $destination_did_succeed (export "destination_did_succeed") 
        (if (i32.eq (global.get $state) (global.get $submitting))
          (then
            (global.get $succeeded)
            (global.set $state)
          )
        )
      )
      (func $destination_did_fail (export "destination_did_fail") 
        (if (i32.eq (global.get $state) (global.get $submitting))
          (then
            (global.get $failed)
            (global.set $state)
          )
        )
      )
    )
    

    Promise State Machine

      State:
      View $Promise Wat source
      (module $Promise
        (global $pending (export "pending") i32 (i32.const 0))
        (global $resolved (export "resolved") i32 (i32.const 1))
        (global $rejected (export "rejected") i32 (i32.const 2))
        (global $state (mut i32) (i32.const 0))
        (func $get_current (export "get_current") (result i32)
          (global.get $state)
        )
        (func $resolve (export "resolve") 
          (if (i32.eq (global.get $state) (global.get $pending))
            (then
              (global.get $resolved)
              (global.set $state)
            )
          )
        )
        (func $reject (export "reject") 
          (if (i32.eq (global.get $state) (global.get $pending))
            (then
              (global.get $rejected)
              (global.set $state)
            )
          )
        )
      )
      

      Dialog State Machine

        State:
        View $Dialog Wat source
        (module $Dialog
          (global $closed? (export "closed?") i32 (i32.const 0))
          (global $open? (export "open?") i32 (i32.const 1))
          (global $state (mut i32) (i32.const 0))
          (func $get_current (export "get_current") (result i32)
            (global.get $state)
          )
          (func $open (export "open") 
            (if (i32.eq (global.get $state) (global.get $closed?))
              (then
                (global.get $open?)
                (global.set $state)
              )
            )
          )
          (func $close (export "close") 
            (if (i32.eq (global.get $state) (global.get $open?))
              (then
                (global.get $closed?)
                (global.set $state)
              )
            )
          )
          (func $cancel (export "cancel") 
            (if (i32.eq (global.get $state) (global.get $open?))
              (then
                (global.get $closed?)
                (global.set $state)
              )
            )
          )
        )
        

        Offline Status State Machine

          State:
          View $OfflineStatus Wat source
          (module $OfflineStatus
            (global $offline? (export "offline?") i32 (i32.const 0))
            (global $online? (export "online?") i32 (i32.const 1))
            (global $listen_to_window (export "listen_to_window") i32 (i32.const 256))
            (global $state (export "state") (mut i32) (i32.const 0))
            (func $get_current (export "get_current") (result i32)
              (global.get $state)
            )
            (func $online (export "online") 
              (if (i32.eq (global.get $state) (global.get $offline?))
                (then
                  (global.get $online?)
                  (global.set $state)
                )
              )
            )
            (func $offline (export "offline") 
              (if (i32.eq (global.get $state) (global.get $online?))
                (then
                  (global.get $offline?)
                  (global.set $state)
                )
              )
            )
          )
          

          Escape HTML

          Resulting HTML:

          View $EscapeHTML Wasm source
          (module $EscapeHTML
            (import "env" "buffer" (memory 2))
            (func $escape (param $read_offset i32) (param $write_offset i32) (result i32)
              (local $char i32)
              (local $bytes_written i32)
              (i32.const 0)
              (local.set $bytes_written)
              (loop $EachChar (result i32)
                (block $Outer
                  (i32.load8_u (local.get $read_offset))
                  (local.set $char)
                  (if (i32.eq (local.get $char) (i32.const 38))
                    (then
                      (i32.store8 (i32.add (local.get $write_offset) (local.get $bytes_written)) (i32.const 38))
                      (i32.add (local.get $bytes_written) (i32.const 1))
                      (local.set $bytes_written)
                      (i32.store8 (i32.add (local.get $write_offset) (local.get $bytes_written)) (i32.const 97))
                      (i32.add (local.get $bytes_written) (i32.const 1))
                      (local.set $bytes_written)
                      (i32.store8 (i32.add (local.get $write_offset) (local.get $bytes_written)) (i32.const 109))
                      (i32.add (local.get $bytes_written) (i32.const 1))
                      (local.set $bytes_written)
                      (i32.store8 (i32.add (local.get $write_offset) (local.get $bytes_written)) (i32.const 112))
                      (i32.add (local.get $bytes_written) (i32.const 1))
                      (local.set $bytes_written)
                      (i32.store8 (i32.add (local.get $write_offset) (local.get $bytes_written)) (i32.const 59))
                      (i32.add (local.get $bytes_written) (i32.const 1))
                      (local.set $bytes_written)
                      br $Outer
                    )
                  )
                  (if (i32.eq (local.get $char) (i32.const 60))
                    (then
                      (i32.store8 (i32.add (local.get $write_offset) (local.get $bytes_written)) (i32.const 38))
                      (i32.add (local.get $bytes_written) (i32.const 1))
                      (local.set $bytes_written)
                      (i32.store8 (i32.add (local.get $write_offset) (local.get $bytes_written)) (i32.const 108))
                      (i32.add (local.get $bytes_written) (i32.const 1))
                      (local.set $bytes_written)
                      (i32.store8 (i32.add (local.get $write_offset) (local.get $bytes_written)) (i32.const 116))
                      (i32.add (local.get $bytes_written) (i32.const 1))
                      (local.set $bytes_written)
                      (i32.store8 (i32.add (local.get $write_offset) (local.get $bytes_written)) (i32.const 59))
                      (i32.add (local.get $bytes_written) (i32.const 1))
                      (local.set $bytes_written)
                      br $Outer
                    )
                  )
                  (if (i32.eq (local.get $char) (i32.const 62))
                    (then
                      (i32.store8 (i32.add (local.get $write_offset) (local.get $bytes_written)) (i32.const 38))
                      (i32.add (local.get $bytes_written) (i32.const 1))
                      (local.set $bytes_written)
                      (i32.store8 (i32.add (local.get $write_offset) (local.get $bytes_written)) (i32.const 103))
                      (i32.add (local.get $bytes_written) (i32.const 1))
                      (local.set $bytes_written)
                      (i32.store8 (i32.add (local.get $write_offset) (local.get $bytes_written)) (i32.const 116))
                      (i32.add (local.get $bytes_written) (i32.const 1))
                      (local.set $bytes_written)
                      (i32.store8 (i32.add (local.get $write_offset) (local.get $bytes_written)) (i32.const 59))
                      (i32.add (local.get $bytes_written) (i32.const 1))
                      (local.set $bytes_written)
                      br $Outer
                    )
                  )
                  (if (i32.eq (local.get $char) (i32.const 34))
                    (then
                      (i32.store8 (i32.add (local.get $write_offset) (local.get $bytes_written)) (i32.const 38))
                      (i32.add (local.get $bytes_written) (i32.const 1))
                      (local.set $bytes_written)
                      (i32.store8 (i32.add (local.get $write_offset) (local.get $bytes_written)) (i32.const 113))
                      (i32.add (local.get $bytes_written) (i32.const 1))
                      (local.set $bytes_written)
                      (i32.store8 (i32.add (local.get $write_offset) (local.get $bytes_written)) (i32.const 117))
                      (i32.add (local.get $bytes_written) (i32.const 1))
                      (local.set $bytes_written)
                      (i32.store8 (i32.add (local.get $write_offset) (local.get $bytes_written)) (i32.const 111))
                      (i32.add (local.get $bytes_written) (i32.const 1))
                      (local.set $bytes_written)
                      (i32.store8 (i32.add (local.get $write_offset) (local.get $bytes_written)) (i32.const 116))
                      (i32.add (local.get $bytes_written) (i32.const 1))
                      (local.set $bytes_written)
                      (i32.store8 (i32.add (local.get $write_offset) (local.get $bytes_written)) (i32.const 59))
                      (i32.add (local.get $bytes_written) (i32.const 1))
                      (local.set $bytes_written)
                      br $Outer
                    )
                  )
                  (if (i32.eq (local.get $char) (i32.const 39))
                    (then
                      (i32.store8 (i32.add (local.get $write_offset) (local.get $bytes_written)) (i32.const 38))
                      (i32.add (local.get $bytes_written) (i32.const 1))
                      (local.set $bytes_written)
                      (i32.store8 (i32.add (local.get $write_offset) (local.get $bytes_written)) (i32.const 35))
                      (i32.add (local.get $bytes_written) (i32.const 1))
                      (local.set $bytes_written)
                      (i32.store8 (i32.add (local.get $write_offset) (local.get $bytes_written)) (i32.const 51))
                      (i32.add (local.get $bytes_written) (i32.const 1))
                      (local.set $bytes_written)
                      (i32.store8 (i32.add (local.get $write_offset) (local.get $bytes_written)) (i32.const 57))
                      (i32.add (local.get $bytes_written) (i32.const 1))
                      (local.set $bytes_written)
                      (i32.store8 (i32.add (local.get $write_offset) (local.get $bytes_written)) (i32.const 59))
                      (i32.add (local.get $bytes_written) (i32.const 1))
                      (local.set $bytes_written)
                      br $Outer
                    )
                  )
                  (i32.store8 (i32.add (local.get $write_offset) (local.get $bytes_written)) (local.get $char))
                  (if (local.get $char)
                    (then
                      (i32.add (local.get $bytes_written) (i32.const 1))
                      (local.set $bytes_written)
                      br $Outer
                    )
                    (else
                      (local.get $bytes_written)
                      return
                    )
                  )
                )
                (i32.add (local.get $read_offset) (i32.const 1))
                (local.set $read_offset)
                br $EachChar
              )
            )
            (func $escape_html (export "escape_html") (result i32)
              (call $escape (i32.const 1024) (i32.const 2048))
            )
          )
          

          HTML Page via Request/Response

          Response:

          Status:
          Headers:
          View $HTMLPage Wasm source
          (module $HTMLPage
            (import "env" "buffer" (memory 2))
            (global $request_body_write_offset (export "request_body_write_offset") (mut i32) (i32.const 65536))
            (global $body_chunk_index (mut i32) (i32.const 0))
            (data (i32.const 255) "content-type: text/html;charset=utf-8\r\n")
            (data (i32.const 297) "<!doctype html>")
            (data (i32.const 313) "<h1>Good</h1>")
            (data (i32.const 327) "<h1>Bad</h1>")
            (func $get_request_body_write_offset (export "get_request_body_write_offset") (result i32)
              (global.get $request_body_write_offset)
            )
            (func $GET (export "GET") 
              (i32.const 0)
              (global.set $body_chunk_index)
            )
            (func $get_is_valid (result i32)
              (i32.eq (i32.load8_u (global.get $request_body_write_offset)) (i32.const 103))
            )
            (func $get_status (export "get_status") (result i32)
              (if (result i32) (call $get_is_valid)
                (then
                  (i32.const 200)
                )
                (else
                  (i32.const 400)
                )
              )
            )
            (func $get_headers (export "get_headers") (result i32)
              (i32.const 255)
            )
            (func $next_body_chunk (export "next_body_chunk") (result i32)
              (block $Main (result i32)
                (if (i32.eq (global.get $body_chunk_index) (i32.const 0))
                  (then
                    (i32.const 297)
                    br $Main
                  )
                )
                (if (i32.eq (global.get $body_chunk_index) (i32.const 1))
                  (then
                    (if (result i32) (call $get_is_valid)
                      (then
                        (i32.const 313)
                      )
                      (else
                        (i32.const 327)
                      )
                    )
                    br $Main
                  )
                )
                (i32.const 0)
              )
              (i32.add (global.get $body_chunk_index) (i32.const 1))
              (global.set $body_chunk_index)
            )
          )