Recently, I’ve been working on a project that uses LiveView for most of the UI, but for some parts with very complex client state, it leverages Gleam’s Lustre framework.
If you’re not familiar with it, Lustre is a Gleam frontend framework that implements the Elm architecture and takes advantage of Gleam’s ability to compile to JS for building highly interactive UIs.
I wrote a few simple helpers and components to make integration easier and improve DX. They allow Lustre to be rendered anywhere inside HEEX and communicate with LiveView from Gleam via the WebSocket connection. It’s similar to LiveSvelte or other JS integrations, but with Gleam and Lustre. It also supports server-side rendering.
Would you be interested if I release this as an open source library (lissome)? I Just want to collect feedback before start extracting the code into a library.
Getting to keep going with the well built-out Elixir ecosystem and proven LiveView but being able to use Gleam for shared logic between front and back seems like a neat capability.
Does this all use Plug and that server or how does Lustre get integrated?
Getting to keep going with the well built-out Elixir ecosystem and proven LiveView but being able to use Gleam for shared logic between front and back seems like a neat capability.
That’s exactly the motivation.
Does this all use Plug and that server or how does Lustre get integrated?
It compiles Gleam to Erlang and calls it to produce the initial html. Then compiles Gleam to JS and bundle it using esbuild binary to hydrate.This is different when using Lustre server components.
The integration is via a component, for example:
def render(assigns) do
~H"""
<div>
<div>Some content rendered with LiveView</div>
<.lustre name="my_gleam_module" props={%{initial: 10}} />
</div>
"""
end
The library will rely on mix_gleam, which is a tool to manage Gleam with Mix. I’ll probably change the under-hood details if I figure out a more efficient approach but now the above works well.
I would be really interested on trying this out.
I think a way to have client side state on certain parts of the application is needed for more complex UIs.
Will keep an eye on this thread
I see you’re using Lustre in its typical “SPA” mode:
pub fn main() {
let json = get_element_by_id("ls-model")
let flags = parse_flags(json)
let app = lustre.simple(init, update, view)
let assert Ok(_) = lustre.start(app, "#app", flags)
Nil
}
and decoding flags and state like you would for traditional ssr/prerendering purposes.
You might also want to dig into Lustre’s component system: because these are built on native Web Components and you’d be able to communicate directly with a LiveView app through attributes and events like any other HTML element
Hey, everyone! This release brings new features and a refactor to the approach taken by the library for doing the integration between Lustre and LiveView.
The highlights are:
All the setup and Gleam integration with Mix has been completely changed in favor of a more solid and flexible approach. Details in the README.
Helpers for communicating with LiveView. Now Lissome includes its own Gleam package that you can add to your Gleam project as a path dependency. It contains various helpers, among them are function to interop with Phoenix LiveView using the Lustre’s effects system.
A live reloader that watches for changes in your Gleam files and recompiles them.
Helpers to work with Gleam types and their Erlang representation in Elixir.
Next step will be support for lustre.component component and Lustre’s server components.