Popcorn's Architecture
View SourceMain Architecture
Popcorn runs Elixir code in web browsers by compiling the AtomVM runtime to WebAssembly (Wasm) and executing user code bundle within an isolated iframe environment.
The main browser window hosts your JavaScript code and the Popcorn client JS library. The communication with iframe happens through the postMessage() API.
Executing Wasm module in iframe prevents crashes from affecting the main application and enables independent error handling (e.g. restarting the module in case of hangs). The iframe loads the Wasm module which initializes AtomVM and loads your compiled Elixir bytecode.
graph TB
subgraph "Main browser Window"
JS[JavaScript application]
Lib[Popcorn library]
end
subgraph "Isolated iframe"
IFrame[AtomVM runtime and communication code]
Bundle[Elixir bytecode Bundle]
Workers@{ shape: processes, label: "Worker threads" }
end
JS --> Lib
Lib <-->|"postMessage()"| IFrame
Bundle --> IFrame
IFrame <--> WorkersPatching Mechanism
Popcorn uses a custom patching mechanism to make Elixir and Erlang standard library work with AtomVM's limitations.
The patching system:
- Takes
.beamfiles from known versions of Erlang and Elixir - Decompiles them, adding custom patches to work around missing functionality in AtomVM
- Adds custom modules like
:emscriptento the standard library - Recompiles all of them and bundles into
.avmbytecode bundle
The patching is currently not exposed to users.
Runtime Initialization diagram
sequenceDiagram
participant MW as Main Window
participant IF as iframe
participant WM as WASM Module
participant AVM as AtomVM
participant EA as Elixir App
MW->>IF: Create iframe, load scripts
IF->>WM: Initialize WASM module
WM->>AVM: Start AtomVM runtime
AVM->>EA: Load and start application
EA->>AVM: Wasm.send_elixir_ready()
AVM->>WM: Elixir ready signal
WM->>IF: Runtime initialized
IF->>MW: Ready for communication