Search documentation of Plushie

# WASM Deployment

Copy Markdown View Source

Plushie apps can run in the browser via WebAssembly. The renderer compiles to WASM using `wasm-pack`, producing a JavaScript module and a `.wasm` binary that can be served from any static file host.

## Prerequisites

- Rust toolchain with the `wasm32-unknown-unknown` target: `rustup target add wasm32-unknown-unknown`
- wasm-pack: install via https://rustwasm.github.io/wasm-pack/
- Plushie Rust source checkout: set `PLUSHIE_RUST_SOURCE_PATH` to the local `plushie-rust` directory. The WASM build requires the `plushie-renderer-wasm` crate, which lives in the source checkout.

## Building

    # Build the WASM renderer (debug, for development)
    PLUSHIE_RUST_SOURCE_PATH=~/projects/plushie-rust mix plushie.build --wasm

    # Build with optimizations (for production)
    PLUSHIE_RUST_SOURCE_PATH=~/projects/plushie-rust mix plushie.build --wasm --release

    # Build both native binary and WASM in one command
    PLUSHIE_RUST_SOURCE_PATH=~/projects/plushie-rust mix plushie.build --bin --wasm

The build produces two files:

- `plushie_renderer_wasm.js` (JavaScript glue module)
- `plushie_renderer_wasm_bg.wasm` (compiled WebAssembly binary)

By default these are installed to the WASM output directory configured via `config :plushie, :wasm_dir` or the `--wasm-dir` CLI flag.

## Configuration

Set artifact and output preferences in `config.exs`:

    config :plushie,
      artifacts: [:bin, :wasm],              # build both by default
      wasm_dir: "priv/static/wasm"          # WASM output directory

CLI flags override config:

    mix plushie.build --wasm --wasm-dir assets/wasm

## Serving the output

The WASM files are static assets. Serve them from any web server or CDN. The `.wasm` file should be served with the `application/wasm` MIME type for optimal browser loading.

With Phoenix:

    # In endpoint.ex, ensure the WASM directory is served as static:
    plug Plug.Static,
      at: "/",
      from: :my_app,
      gzip: true,
      only: ~w(wasm css fonts images js favicon.ico robots.txt)

With a standalone static server:

    cd priv/static
    python3 -m http.server 8080

## Web page integration

The JavaScript module exports an initialization function. Load it from an HTML page:

    <!DOCTYPE html>
    <html>
    <head>
      <meta charset="utf-8" />
      <title>My Plushie App</title>
      <style>
        body { margin: 0; overflow: hidden; }
        canvas { width: 100vw; height: 100vh; }
      </style>
    </head>
    <body>
      <canvas id="plushie-canvas"></canvas>
      <script type="module">
        import init from "./plushie_renderer_wasm.js";
        await init();
      </script>
    </body>
    </html>

The WASM renderer connects back to the Elixir backend over a WebSocket to receive the wire protocol messages (snapshots, patches) and send events. Your Elixir app runs on the server; the WASM renderer runs in the browser.

## Limitations vs native

The WASM renderer has several differences from the native renderer:

- No native file dialogs. Platform effects like `Effect.file_open` are not available. File operations must use browser APIs (e.g., `<input type="file">` via JavaScript interop) or be handled server-side.
- No clipboard access without user gesture. Browser security policies restrict clipboard operations to user-initiated events.
- No system notifications. The Web Notifications API can be used as an alternative via JavaScript interop.
- No multi-window. WASM apps render into a single canvas element. Multiple windows are not supported.
- Performance. The WASM renderer uses software rendering. Complex scenes with many animated elements may be slower than the native GPU-accelerated renderer.
- Startup time. The `.wasm` binary must be downloaded and compiled by the browser on first load. Use `--release` builds and enable gzip/brotli compression on your server to minimize this.
- No native widgets. Native widget crates that compile Rust code for the renderer are not currently supported in WASM builds. Only pure Elixir widgets work.

## Development workflow

During development, use the native renderer (`mix plushie.gui`) for fast iteration. Build and test the WASM version periodically to catch browser-specific issues:

    # Develop with native renderer
    mix plushie.gui MyApp --watch

    # Periodically verify WASM build
    mix plushie.build --wasm
    # Serve and test in browser

## Download vs build

`mix plushie.download --wasm` downloads a precompiled WASM renderer for released versions. This skips the Rust toolchain requirement but does not support native widgets (which require a custom build). For most apps using only built-in and pure Elixir widgets, the precompiled download is sufficient.

← Previous Page Shared State
Next Page → Accessibility