Skip to content

Instantly share code, notes, and snippets.

@bcardarella
Created July 7, 2025 15:36
Show Gist options
  • Save bcardarella/2a357fdf0193771dcc6c234ac5364c50 to your computer and use it in GitHub Desktop.
Save bcardarella/2a357fdf0193771dcc6c234ac5364c50 to your computer and use it in GitHub Desktop.

PhoenixLiveViewWasm

Build the Wasm bundle with:

mix bundle_phoenix_live_view --phoenix v1.8.0-rc.3 --phoenix-live-view v1.1.0-rc.1

There is a Rust plugin that handles interfacing between JS and Elixir at priv/browser_plugin/src/lib.rs.

To define a function in Elixir that Wasm can call, use the defimport macro:

defmodule Element do
  use WasmImports

  # arguments `pid` of type `i32` and `name` of type `string`.
  # return type is `string`.
  defimport get_attribute([pid: :i32, name: :string], :string) do
    [{_, pid}] = :ets.lookup(:element_pids, pid)
    pid
      |> GenDOM.Element.get()
      |> GenDOM.Element.get_attribute(name)
  end
end

The equivalent declaration in Rust is:

// this "element" name comes from the `imports` key in the Wasmex config.
// methods are collected from the `Element` module with `Element.imports()`.
#[link(wasm_import_module = "element")]
unsafe extern "C" {
    unsafe fn get_attribute(
        // datatypes other than string are passed through as normal numerics.
        element: i32,

        // string arguments become a memory address and length.
        // `defimport` will automatically decode the string.
        name: i32,
        name_len: i32,
        
        // string return type becomes a memory address and length.
        // `defimport` will automatically write to these pointers.
        out_addr: i32,
        out_len: i32
    );
}

You can use the helper Buffer type in the Rust plugin to convert an addr/len pair into a string:

// make an empty buffer:
let mut buffer = Buffer { addr: 0, len: 0 };
// run the Elixir function:
unsafe {
  get_attribute(
    pid,
    // convert name string to addr/len pair:
    name.as_ptr() as i32,
    name.len() as i32,
    // pass buffer pointers for result:
    &buffer.addr as *const i32 as i32,
    &buffer.len as *const i32 as i32
  )
};
// convert the buffer to a string and return:
return buffer.as_str();

When you change the Rust code, you need to rebuild the Wasm bundle with the command at the top of the README.

Right now, all of the logic is implemented in the tests test/phoenix_live_view_wasm_test.exs.

runtime.js Is used as the entrypoint for JS. It can import phoenix_live_view as well. Changes to runtime.js also require rebuilding the Wasm bundle.

Installation

If available in Hex, the package can be installed by adding phoenix_live_view_wasm to your list of dependencies in mix.exs:

def deps do
  [
    {:phoenix_live_view_wasm, "~> 0.1.0"}
  ]
end

Documentation can be generated with ExDoc and published on HexDocs. Once published, the docs can be found at https://hexdocs.pm/phoenix_live_view_wasm.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment