Skip to content

LiveView

Mistweaver integrates Lustre server-side components over a WebSocket connection. The server holds state and pushes HTML diffs; the client applies them with a small JS runtime.

Defining a LiveView

A LiveView is a standard Lustre App. Define init, update, and view:

gleam
import lustre
import lustre/element.{type Element}
import lustre/element/html

pub type Model { Model(count: Int) }
pub type Msg { Increment | Decrement }

pub fn init(_flags) -> #(Model, lustre.Effect(Msg)) {
  #(Model(count: 0), lustre.none())
}

pub fn update(model: Model, msg: Msg) -> #(Model, lustre.Effect(Msg)) {
  case msg {
    Increment -> #(Model(count: model.count + 1), lustre.none())
    Decrement -> #(Model(count: model.count - 1), lustre.none())
  }
}

pub fn view(model: Model) -> Element(Msg) {
  html.div([], [
    html.button([event.on_click(Decrement)], [html.text("-")]),
    html.span([], [html.text(int.to_string(model.count))]),
    html.button([event.on_click(Increment)], [html.text("+")]),
  ])
}

Mounting with auth context

Use live.dynamic_handler_with_shell to inject conn context (including auth) into the component factory:

gleam
router.get(
  "/counter",
  live.dynamic_handler_with_shell(
    fn(c, _params) { counter.make(c.auth) },
    fn(c, component) {
      mw_response.html(200, element.to_document_string(
        layout.page(c, "Counter", None, component),
      ))
    },
  ),
)

make returns a lustre.ServerComponent built from the context:

gleam
pub fn make(auth: Option(AuthUser)) -> lustre.App(...) {
  lustre.component(
    fn(_) { init(option.map(auth, fn(u) { u.id })) },
    update,
    view,
    dict.new(),
  )
}

PubSub integration

LiveView components can subscribe to PubSub topics and push updates to connected clients. Subscribe in init and handle messages with a Lustre effect that sends to process.self().

Released under the Apache 2.0 License.