Popcorn. Wasm
(Popcorn v0.4.0-next.3)
View Source
Connects Elixir processes to JavaScript in the browser page.
Receiving messages
JavaScript calls to popcorn.send(target, payload) deliver {:wasm, payload} to the target process.
Use is_message/1 in guards to match for it.
Use Popcorn.Proxy for GenServer calls and casts.
Values
From JS side:
- strings become binaries.
- arrays become lists.
- plain objects become maps with string keys.
atom()andtuple()helpers send atoms and tuples. Atoms must already exist in the VM.
From VM side:
- Tuples become arrays.
- Most atoms become strings, with exception of
true,falseandnil(mapped tonull). - PID handles refer to processes in the VM.
Outside the browser
Use available?/0 to check if your code is running natively or in the browser.
On a native VM, JavaScript calls use a no-op mock so Popcorn applications can run in tests.
Summary
Types
A JavaScript message with a payload decoded into Elixir terms.
An opaque handle that keeps a JavaScript value alive.
Functions
Returns true if running in the browser.
Waits until the JavaScript Popcorn instance has finished booting.
Matches a message/0 sent from JavaScript.
Runs a JavaScript function on the page and waits for its result.
See run_js/3.
Sends a message to the JavaScript callbacks registered with popcorn.onEvent().
Types
@type message() :: {:wasm, payload :: term()}
A JavaScript message with a payload decoded into Elixir terms.
@type run_js_opts() :: [{:timeout, timeout()}]
@opaque tracked_value()
An opaque handle that keeps a JavaScript value alive.
Return new TrackedValue(value, cleanup) from JavaScript function to create a handle.
Pass the handle in run_js/3 arguments to access the original value.
The runtime calls cleanup function after BEAM garbage collection releases the handle, or when the VM stops.
Note: Garbage collection does not guarantee prompt cleanup. For time-sensitive resources, call an idempotent cleanup function explicitly. This ensures you can call it yourself or it can be called by Popcorn.
Functions
@spec available?() :: boolean()
Returns true if running in the browser.
@spec await_ready(run_js_opts()) :: :ok | {:error, :timeout}
Waits until the JavaScript Popcorn instance has finished booting.
Use this only from asynchronous work whose process startup has already been
acknowledged, such as the body of a supervised Task:
children = [
{Task, &MyApp.API.run/0}
]
def run do
with :ok <- Popcorn.Wasm.await_ready(),
{:ok, _value} <- Popcorn.Wasm.run_js("() => initializeBrowser()") do
:ok
end
endOptions
:timeout- the reply timeout, or:infinity. Defaults to5_000ms.
Notes
- Do not call this function from
Application.start/2,GenServer.init/1, a childstart_linkpath that has not returned, or an OTP start phase — it will deadlock.
Matches a message/0 sent from JavaScript.
@spec run_js(String.t(), map(), run_js_opts()) :: {:ok, term()} | {:error, :timeout | {:js, term()}}
Runs a JavaScript function on the page and waits for its result.
code defines a function with the signature (args, {send, call, cast}) => result.
The bridge converts the args map to JavaScript values and awaits any returned promise.
It returns {:ok, value} with the result converted to Elixir terms or {:error, {:js, reason}}.
A timeout returns {:error, :timeout} and does not cancel JavaScript execution.
The page's Content Security Policy must permit JavaScript evaluation with unsafe-eval.
JS
The send helper sends a message to a BEAM process.
The call and cast helpers use Popcorn.Proxy to contact GenServers.
These helpers return promises with the same result objects as their JavaScript API counterparts.
Notes:
- Calls during application startup run before
popcorn.boot()resolves. - Do not await a
callto the process that executesrun_js/3. It will cause deadlocks.
Options
:timeout- the reply timeout, or:infinity. Defaults to5_000ms.
Examples
Popcorn.Wasm.run_js("({n}) => n + 1", %{n: 1})
#=> {:ok, 2}Use a tracked_value/0 for values such as DOM elements:
{:ok, element} = Popcorn.Wasm.run_js("() => new TrackedValue(document.body)")
Popcorn.Wasm.run_js!("({element}) => { element.textContent = 'Ready'; }", %{element: element})
@spec run_js!(String.t(), map(), run_js_opts()) :: term()
See run_js/3.
@spec send(term()) :: :ok
Sends a message to the JavaScript callbacks registered with popcorn.onEvent().