# Lissome
Lissome is a library to integrate the [Gleam](https://gleam.run/) frontend framework [Lustre](https://hexdocs.pm/lustre/lustre.html) with Phoenix Live View.
> [!WARNING]
> This project is on early stage of development and breaking changes are expected.
## Setup
First, make sure you have the Gleam compiler installed. Instructions can be found [here](https://gleam.run/getting-started/installing/)
1. We will use a tool called `mix_gleam` to manage a Gleam project with Mix. Follow the [instructions](https://github.com/gleam-lang/mix_gleam?tab=readme-ov-file#installation) to setup it.
2. Add `lissome` to your `mix.exs` file:
```elixir
def deps do
[
...,
{:lissome, "~> 0.2.0"},
]
end
```
3. Create a `gleam.toml` file with your Gleam dependencies:
```toml
name = "your_app_name"
[dependencies]
gleam_stdlib = ">= 0.44.0 and < 2.0.0"
lustre = ">= 4.6.3 and < 5.0.0"
[dev-dependencies]
gleeunit = ">= 1.0.0 and < 2.0.0"
```
4. Run:
```bash
mix deps.get
gleam deps download
```
> [!NOTE]
> Although `mix_gleam` is able to install Gleam dependencies, it doesn't manages dependencies well outside Erlang target. For that reason, we usea `gleam.toml` file and the Gleam tooling to manage Gleam dependencies.
## Usage
To render a Lustre app, we need to define a Gleam module that contains a public `main` function. This function must start a Lustre app created with the `lustre.simple` function.
```gleam
//// src/hello.gleam
pub fn init() {
...
}
pub fn update(msg, model) {
...
}
pub fn view(model) {
...
}
pub fn main() {
let app = lustre.simple(init, update, view)
let assert Ok(_) = lustre.start(app, "#app", Nil)
Nil
}
```
Now, inside `HEEX` we can render it using the `lustre` component:
```elixir
defmodule MyApp.MyLiveView do
use MyApp, :live_view
import Lissome.Component
def mount(_params, _session, socket) do
{:ok, socket}
end
def render(assigns) do
~H"""
<div>
<div>Content rendered with Phoenix Live View</div>
<div>
<.lustre id="app" name="hello" />
</div>
</div>
"""
end
end
```
Check out the project in the `example` directory for a complete code example.
## SSR
Thanks to the ability of Gleam to compile to both Erlang and JavaScript, we can do server-side rendering of Lustre without having to install Node.js. This is why `Lissome` has SSR enabled by default, but you can disable it by passing `ssr={false}` to the `lustre` component.
Keep in mind that `Lissome` will call the `init` and the `view` functions of your Gleam module in order to render the initial HTML. By default `Lissome` will look for functions with that name in your module. If you happen to named them differently, you can pass to the `lustre` component `init_fn` with the name of your function responsible for initializing the model and `view_fn` with the name of your function responsible for rendering the view. Also, both functions must be public.
```elixir
<.lustre
id="app"
name="hello"
init_fn="my_init_function"
view_fn="my_view_function"
/>
```
## Use cases
In my experience, many part of the UI in Phoenix apps could be done with `Phoenix LiveView`; even for parts that are heavily interactive we have ways to build components like modals using JS commands and [perform optimistic updates](https://hexdocs.pm/phoenix_live_view/syncing-changes.html) by combining JS commands and Tailwind CSS classes.
However, there are still parts of the UI that are very complex to implement in `Phoenix LiveView`, often because they have a non-trivial client-side state.
In that situations, we could use Gleam and its fronted framework, Lustre, as they are well suited to handle that kind of state in a simple way. Also, Gleam has interopability with Elixir and both shares many concepts, such as immutability, functional paradigms and pattern matching.
`Lissome` is designed to address *only* the gaps of `Phoenix LiveView` when it comes to client-side state.
## Roadmap
- [ ] Improvements to the SSR.
- [ ] Gleam's helpers for communicating with Phoenix LiveView and supporting Lustre's effects.
- [ ] Hot module replacement for Gleam.
- [ ] Support for [`LiveJson`](https://github.com/Miserlou/live_json).
- [ ] Support for Lustre's `server components`.