An open API service indexing awesome lists of open source software.

https://github.com/elixir-volt/phoenix_vapor

Vue templates as native Phoenix LiveView rendered structs — compile Vue syntax to %Phoenix.LiveView.Rendered{} via Vapor IR
https://github.com/elixir-volt/phoenix_vapor

Last synced: about 1 month ago
JSON representation

Vue templates as native Phoenix LiveView rendered structs — compile Vue syntax to %Phoenix.LiveView.Rendered{} via Vapor IR

Awesome Lists containing this project

README

          

# Phoenix Vapor

Vue template syntax compiled to native `%Phoenix.LiveView.Rendered{}` structs via Rust NIFs.

```elixir
defmodule MyAppWeb.CounterLive do
use MyAppWeb, :live_view
use PhoenixVapor

def mount(_params, _session, socket), do: {:ok, assign(socket, count: 0)}

def render(assigns) do
~VUE"""


{{ count }}


+

"""
end

def handle_event("inc", _, socket), do: {:noreply, update(socket, :count, &(&1 + 1))}
end
```

Same WebSocket, same diff protocol, same LiveView client. No wrapper divs, no `phx-update="ignore"`.

## Three tiers

| Tier | What | How |
|------|------|-----|
| `~VUE` sigil | Vue templates in any LiveView | `~VUE"""

{{ count }}

"""` |
| `.vue` SFC | Complete LiveView from a `.vue` file | `use PhoenixVapor.Reactive, file: "Counter.vue"` |
| Vapor DOM | Bypass morphdom — direct DOM writes | `patchLiveSocket(liveSocket)` |

## Installation

```elixir
def deps do
[
{:phoenix_vapor, "~> 0.1.0"},
{:quickbeam, "~> 0.3.0", optional: true} # for complex JS expressions
]
end
```

## Supported syntax

`{{ expr }}` · `:attr="expr"` · `@click="handler"` · `v-if` / `v-else-if` / `v-else` · `v-for` · `v-show` · `v-model` · `v-html` · ternaries · arithmetic · `.length` · `.toUpperCase()` · dot access · components

Simple expressions evaluate in pure Elixir via OXC AST. Complex expressions (arrow functions, `.filter()`, `.map()`) fall back to [QuickBEAM](https://hex.pm/packages/quickbeam).

## `.vue` SFC mode

```vue

import { ref, computed } from "vue"
const count = ref(0)
const doubled = computed(() => count * 2)
function increment() { count++ }

{{ count }} × 2 = {{ doubled }}


+

```

```elixir
defmodule MyAppWeb.CounterLive do
use MyAppWeb, :live_view
use PhoenixVapor.Reactive, file: "Counter.vue"
end
```

`ref()` → assigns, `computed()` → derived state, functions → event handlers. Three lines of Elixir.

## Vapor DOM

Opt-in morphdom bypass. The client parses statics once, builds a registry mapping each dynamic slot to its DOM node, then applies diffs as direct property writes.

```js
import { patchLiveSocket } from "phoenix_vapor"
patchLiveSocket(liveSocket)
```

See [ARCHITECTURE.md](ARCHITECTURE.md) for protocol-level details.

## Docs

- **[ARCHITECTURE.md](ARCHITECTURE.md)** — how it works at the protocol level, with wire format examples
- **[examples/demo](https://github.com/elixir-volt/phoenix_vapor/tree/master/examples/demo)** — runnable Phoenix app with all features

## License

MIT