
On the Utility of Phoenix LiveView - feross
https://jclem.net/posts/on-the-utility-of-phoenix-liveview
======
Ankhers
As someone that writes Elixir at $DAYJOB, I was really looking forward to
replacing some JS with LiveView. However, after having used it for a simple
feature, I'm not entirely sure if I will continue to use it. I realize it is
still pre 1.0 and that there is still a lot of work being done on it.

My biggest complaint is that if your server restarts for any reason (say, a
rolling restart), you currently lose all state that was on the server[0].
There appears to be some kind of workaround for forms currently, but for
anything more complex, I would need to write JS in order to attempt to not
have my page get reset to the default view. So if I need to write JS already,
I may as well just write JS (or something that transpiles or JS/WASM) to have
fewer moving parts.

[0] [https://elixirforum.com/t/liveview-and-rolling-
restarts/2397...](https://elixirforum.com/t/liveview-and-rolling-
restarts/23973)

~~~
chrismccord
In my ElixirConf keynote, I highlighted how automatic form recovery is on the
roadmap, provided we can determine that such a recovery is possible on
reconnect. More advanced dynamic forms will require manual recovery, and as
you said it can be done today, with 20 lines of JS:
[https://gist.github.com/chrismccord/5d2f6e99112c9a67fedb2b85...](https://gist.github.com/chrismccord/5d2f6e99112c9a67fedb2b8501a5bcab)

We are going to formalize the idea of a "stash" to send back up client state
on reconnect, which would remove the need for this JS entirely. It is also
worth noting that if someone packaged up that 20 line gist into a JS package,
your application or anyone else could do `<form ... phx-hook="SavedForm">`, so
"need to write JS anyway so might as well write a JS app" isn't quite accurate
because it's a tiny escape hatch that doesn't require throwing away or
rewriting any feature. Writing 20 lines of JS to keep shipping LV features is
much different than _rewriting_ an entire application in JS. I would actually
argue the fact you have the escape hatch in this scenario is one of the merits
of the library. Anyways, I hope we can keep you around once other features
continue to land :)

~~~
Ankhers
I believe I have only heard about automatic recovery for forms. Would this
"stash" you mentioned be more general for recovering state?

For what it's worth, I very much appreciate the work you and everyone involved
has done for LV (and more generally, Phoenix).

~~~
chrismccord
Yes, in the above gist the connect are params used, so connect params are a
general purpose mechanism for state recovery. In the above example a form is
used, but on mount you can do whatever you'd like with the data. Thanks!

~~~
elcritch
Will the data in the “stash” need to be verified on the server? Currently I
treat connect params as user data and parse and verify it. I’m unclear if a
more general data stash would cause potential security issues.

Secondly, has there been any discussion for supporting server side draining or
moving the process to another node?

~~~
fouc
Phoenix is built around a middleware known as Plug, and most things are Plugs,
you can add a Plug to separately handle the verification I would guess

------
francislavoie
PHP/Laravel have something similar to this now called Livewire
[https://laravel-livewire.com/](https://laravel-livewire.com/)

The author, Caleb Porzio
([https://calebporzio.com/](https://calebporzio.com/)), was inspired by
Phoenix LiveView to build something something like this for his preferred
language/framework.

~~~
mwcampbell
This looks very different from LiveView. In particular, as explained in
Livewire's documentation on state management [1], state is either stored in a
back-end service like Redis, or re-sent to the server with each request,
depending on the type of property. And according to the home page, Ajax
requests are used. With LiveView, a persistent WebSocket connection is used,
and state is stored in memory in an Erlang process.

[1]: [https://laravel-livewire.com/docs/state-management/](https://laravel-
livewire.com/docs/state-management/)

~~~
francislavoie
It was initially implemented with websockets but that meant having to actually
run a websocket server alongside the PHP app to work. Caleb went the simple
route by just sticking to AJAX instead. It's a difference in how PHP is
typically run (mod_php or fastcgi) vs how Erlang runs (standalone server).

On his blog, he posted some videos earlier this year about the process of
coming up with what eventually became Livewire, as well as a bunch of
discussion on his podcast No Plans To Merge.

------
mxstbr
I have been meaning to play around with Elixir, Phoenix and LiveView for a
while, it seems like it could replace client-side JS frameworks (e.g. React)
for many use cases, especially the ones that already fully use server-side
rendering.

Has anybody with lots of React experience made that switch? How is it going?

~~~
elcritch
I switched my work project from Vue (which worked pretty well) to LiveView,
and I’m not looking back. As the article mentions, not having to run a
javascript build chain is fantastic. Writing modern JS isn’t too bad, but the
complexity of writing a data api (whether JSON/rest, websockets, etc) on both
the server and then client, and handling JS async data retrieval methods, is a
huge turn off to me for writing new features. At least for me, being the solo
developer. Big teams might find the data/UI split convenient for other
reasons.

Plus, it’s fast. Rather it feels faster than it should be. Perhaps since
instead of waiting for JS to retrieve data, parse it, and render, and then
update, you just need the JS to update the DOM once the data arrives. Of
course my vue pages were using REST endpoints for data so perhaps a
websocketed vue page would feel more responsive.

LiveView still has a bit of maturing to do, but I’m really enjoying it. I’m
really bullish that writing dashboards, admin pages, internal corporate tools
can all be done an order of magnitude easier with LiveView or similar while
still scaling decently.

~~~
1_player
Same here, we just deployed a React/Next.js app and it's been a veritable
nightmare. Productivity was much worse than a normal server-side framework
with a JS layer on top, especially since we've got experience with Elixir
which has worked great for us.

Soon we're starting another project, and we'll go with Phoenix (which we're
already using as a backend and GraphQL server) with LiveView sprinkled here
and there where we need better interactivity.

------
mcintyre1994
This is an awesome example, thanks for sharing! Are you doing any sort of
optimisation on the server side, or is it parsing the entire page of markdown
on every key press? Have you stress tested this on really long content just
out of interest?

~~~
jclem
Thanks!

It’s parsing the entire Markdown content on each key press right now, which is
definitely suboptimal for a product but fine for my needs.

It should certainly be possible to make this more efficient by either doing
some smarter diffing of the in-progress document or using an operation-based
update mechanism.

LiveView doesn’t yet have event debouncing built in, but it’s in the works, I
believe, and that would help, as well.

That said, it’s currently fast enough writing a post of this length that while
writing, I notice no significant lag in the live updates. By the time I stop
typing and look at the preview, it’s up to date.

~~~
mrdoops
They rolled out debounce and throttle fairly recently. There's also some very
compelling work on a component abstraction (runs in same Liveview process).

------
dmitriid
There’s a big caveat: all state is on server which will bite you (in terms of
RAM) if you’re not careful.

A small thread including my own experience here:
[https://twitter.com/dmitriid/status/1153586545426862080](https://twitter.com/dmitriid/status/1153586545426862080)
It’s fairly obvious, but is worth mentioning.

~~~
chrismccord
Check out our "temporary assign" documentation – you only hold on to the state
you need. That said, you are right that a LV application will necessarily use
more memory than a stateless JSON API, but there is more nuance to the story.
A LiveView application will use less resources under application operation
than a single page app, for example:

\- because LiveViews are stateful, we don't have to refetch/reload the state
we need on every "request". Things like current_user, current organization,
preferences, etc. So what we lose in memory load, we gain in reduced DB and
system load, caching strategies, etc

\- because LiveViews are stateful with change-tracking, we actually can send
_less data than the best hand-written SPA /JSON application you could write_.
So what we lose in memory load, we gain in reduced latency and overall data on
the wire.

Direct link to data-on-the-wire example from my keynote for those curious:
[https://youtu.be/txk4WAlabvI?t=873](https://youtu.be/txk4WAlabvI?t=873)

~~~
verttii
Not only that, but a lot of the state is essentially the same for many/all
users/connections and can be shared.

Let's say in a chat app with a Redux setup I'd maintain channel users,
messages, own profile details etc. in the app's own local state. With LiveView
I'd only need to store the user specific stuff in this user's own state. Some
of which I'd store in the socket.assigns of Phoenix Channels subscriptions
even now with a conventional Redux setup.

------
hartator
Demo looks awesome. Is that against localhost or an actual server? Latency
seems nil.

~~~
jclem
This is against a Heroku hobby server. Latency is very low, as I’m on the East
coast where I believe this server is.

Using LiveView, of course, requires taking round trip latency for your users
into account. It currently won’t work well for some use cases where optimistic
UI updates may help hide some latency. I think I read something about there
being some optimistic updating in the works for LiveView, though, long-term,
but I’m not sure how it’ll be done.

------
owens99
I’m curious why the author used phx-change function for the form, I believe a
better way to do this would be the phx-keyup function attached the text field.

~~~
jclem
There’s more than one field here, it’s just not discussed in the post. The
title is a separate form field that is validated and updates live on every
change event. `phx-change` gives me the whole form state, which is what I
wanted.

