WebAssembly (Emscripten)
Relevant source files
The following files were used as context for generating this wiki page:
The WebAssembly (Wasm) port of AtomVM enables the execution of Erlang and Elixir applications within modern web browsers and NodeJS environments. Utilizing the Emscripten SDK, this port translates the AtomVM virtual machine into Wasm and JavaScript, providing a bridge between the BEAM runtime and web-native technologies like the DOM and Web APIs.
In the browser, AtomVM typically runs in a web worker to avoid blocking the main UI thread, using specific synchronization mechanisms such as SharedArrayBuffer and Emscripten's proxy-to-pthread features. This allows for complex, concurrent Erlang logic to operate alongside JavaScript-driven user interfaces.
Sources: doc/src/atomvm-internals.md:522-530, doc/src/getting-started-guide.md:611-615
Architecture and Execution Model
The Wasm port supports two primary execution environments: NodeJS and the Web. The NodeJS build uses NODERAWFS for direct file system access, while the Web build relies on the Fetch API or preloaded files to load BEAM and AVM modules.
Threading and Concurrency
AtomVM for WebAssembly relies on pthreads for internal management even when Symmetric Multi-Processing (SMP) is disabled. In a browser environment, the main function is proxied to a web worker. This architectural choice is necessary because the browser's main thread cannot sustain the continuous loop required by AtomVM's schedulers without freezing the UI.
The following diagram illustrates the relationship between the JavaScript main thread and the AtomVM worker:
The interaction between threads allows Erlang processes to trigger JavaScript execution and vice versa.
Sources: doc/src/atomvm-internals.md:522-539
Interaction with JavaScript
AtomVM provides specific NIFs (Native Implemented Functions) within the emscripten module to allow Erlang processes to interact with the JavaScript environment.
Script Execution
Erlang processes can execute JavaScript code via emscripten:run_script/2. This function supports different execution modes:
- Synchronous (Main Thread): The Erlang process waits for the main thread to complete the script.
- Asynchronous (Main Thread): The script is dispatched to the main thread, and the Erlang process continues immediately.
- Worker Thread: Execution occurs within the worker thread, which blocks the Erlang scheduler for the duration of the script.
Sources: examples/emscripten/run_script.html:36-44, doc/src/atomvm-internals.md:539-543
Call and Cast Mechanisms
JavaScript can communicate with the Erlang runtime using call and cast functions.
- Cast: A fire-and-forget message enqueued for a target Erlang process.
- Call: A promise-based request where JavaScript awaits a response from Erlang.
| Feature | Description |
|---|---|
| Cast | Enqueues a message; message is freed after processing. |
| Call | Uses JS Promises. Erlang returns a result via promise_resolve/2 or promise_reject/2. |
| Resources | Promises are encapsulated in Erlang resources to ensure proper cleanup via GC. |
Sources: doc/src/atomvm-internals.md:546-562, examples/emscripten/call_cast.html:31-35
Browser Integration and Events
The Emscripten port allows Erlang processes to register for and handle standard HTML5 events.
HTML5 Event Support
Applications can listen for various event types, including:
- Keyboard: keypress, keyup, keydown.
- Mouse: click, mousedown, mouseup, dblclick, mousemove, mouseenter, mouseleave.
- Touch: touchstart, touchend, touchmove, touchcancel.
- UI/Others: resize, scroll, focus, blur, and wheel events.
Sources: examples/emscripten/html5_events.html:64-135
Data Flow for Events
When an event occurs in the browser, the data is mapped into Erlang terms and sent to the registered process.
Deployment and Security Requirements
Running AtomVM in a browser imposes specific security requirements due to the use of SharedArrayBuffer.
Server Configuration
To execute AtomVM files, the web server MUST serve the files over localhost or HTTPS and include specific COOP (Cross-Origin-Opener-Policy) and COEP (Cross-Origin-Embedder-Policy) headers.
| Header | Required Value |
|---|---|
Cross-Origin-Opener-Policy | same-origin |
Cross-Origin-Embedder-Policy | require-corp |
Sources: doc/src/getting-started-guide.md:623-630
Required Files
A standard web deployment requires three primary files:
AtomVM.js: The JavaScript glue code.AtomVM.worker.js: The worker script for background execution.AtomVM.wasm: The compiled WebAssembly binary.
Sources: doc/src/getting-started-guide.md:611-620
Conclusion
The WebAssembly (Emscripten) port of AtomVM extends the reach of Erlang/Elixir applications to the web platform. By leveraging web workers for scheduling and providing a robust JS-Erlang bridge through promises and event mapping, it allows developers to build highly concurrent web applications using BEAM languages while maintaining full access to modern browser capabilities.