Let's discuss Phoenix LiveView

Some things that pre-date this in one form of another, Nitrogen on erlang and Wt framework on C++. nitrogen let you define a page and then react to it similar to Drab’s low level interfaces, not as ‘live’. Wt for C++ on the other hand has been around for a LONG time, it basically gives you a kind of normal desktop GUI API (QT’ish) for working with the web, been around since 2005, and it is very much like liveview in functionailty (it was SO nice to work in!).

Nitrogen, due to it’s more low-level style, only did explicit updates. Wt was full observer-oriented, super-efficient. Drab.Live is mostly observer style though with some slightly heavy pre-generation (still less than a VDom).

It is in my stuff! ^.^

Unpoly and Drab both make it pretty easy to do though.

I’m curious, how is that new state transformed to the client? Is it a template replacement on the client, a VDOM merge, direct observer interactions (most efficient of these listed but requires compiled-in metadata about the template on the server, which is entirely doable in Elixir), or something else?

What does it gain over Drab.Live as well?

Do note, I’ve not seen the video, I often can’t watch videos. ^.^;

Isn’t the entirety of Drab already? :wink:

Eh, I actually see it as the very old way of doing this. Going back 20 years all web pages were server driven, even with sessions and live polling and COMET and all. It’s just coming back around at this point. Even Wt was birthed as the epitome of that whole server-owned idea (it’s built and managed by a business, it’s only incidentally open-source, and it didn’t even used to be FOSS back when I used it).

3 Likes

It would really help if you watched the video :smiley: as I believe most of your questions will be covered. We use morphdom to apply the DOM patch, without the need for vdom on the client. wrt to drab, there’s some really great work there, and I think we have similar visions, but with different approaches. Note: I’m only familiar with Drab from tangentially following the forum posts, but from what I’ve seen Drab focuses on “remote controlling” the page from the server, where its primitives revolve around poking parts of the page for update, peeking parts of the page for values, and using client-like primitives for setting DOM node props/attrs. With LiveView, we take the react model and place it on the server, where we focus on stateful processes that upon updating their state, transform that state into HTML, which then is used to update the UI. So our approach is more about focusing the UI and stateful views, where the update step pushes the diff down, versus a more direct coupling to server controlling the client DOM/page.

I see this point, but I also find it funny we have folks who both see this as yet another new way to do server apps, and also the way we always did them from the start. Both have valid points, but it’s interesting watching the different hot-takes :slight_smile:

7 Likes

Well, I particularly disagree with this point for some reasons:

  1. I would not call opposite direction, @chrismccord explained very well that his attempt was to solve the same problem, which is the poor UX when you have too many page refreshes. So the direction is the same, it’s just a different path, and it’s totally valid to try out different solutions for the same problem.
  2. Just because big companies are pushing it to a certain way does not mean that’s the best solution.
  3. Just because it’s not “disruptive”, doesn’t mean it’s not good. I see what you mean: the concept is really close to turbolinks, but over websockets. Well, turbolinks was good enough for a long time, but then, some people started to complain about UX with that and try out new solutions, which is good! Very good! But if you try out a new solution, and it’s not better in some senses, the wisest thing to do is going back and maybe try something else closer to how it was.

I see it as the way we always did them from the start, but a little bit simpler, faster and reactive. I already love the way we were doing it from the start, and if you really made it better, I’m really excited to try it out! Thank you!!!

2 Likes

I envision a future where SPA stands for “Server Powered Apps” :slightly_smiling_face:

10 Likes

The funny thing is some industries are actually exploring or heading that way - with dumb(er) clients and intelligent backends. Where? Perhaps where you’d least expect it… gaming

3 Likes

I can’t imagine how this approach would be any more fragmenting than the existing standard for rich clients – where you already have the initial server render, the client side code, and some API. LiveView just looks like a simple embedding a view within a view (which we already do in Phoenix), except the embedded view can by dynamically updated.

Clearly it doesn’t do anything technically that couldn’t be done in 2009, but to have all the tedious and error-prone plumbing taken away seems like a huge win to me. Big props to Chris and the Phoenix team for making this happen.

One big big distinction is we have stateful components on the backend, where turbolinks requests a stateless page/fragment. So for the simplest CounterView example, turbolinks would need to have the client send an Ajax request every second to render the stateless view. For us, the view is up and running and can send updates to the client at any time, on its own accord, such as subscribing to platform events and updating the UI, phoenix presence, etc.

6 Likes

That’s only it’s low level API, good as a fallback to work with anything, even if you have a javascript framework on the front-end, but that is not Drab.Live. Drab.Live renders *.html.drab templates, which is a special eex template processor that builds up a call tree that will return the output like eex but also it compiles the information that Drab needs to know to perform real updates. From that point on when you update, say, an ‘assigns’ that was passed to the template, then it figures out what was chanes of it and then only updates those parts of the page (observer model), without needing to build up a VDom or anything of the sort, it ‘tags’ elements on the page via unique drab-id style id’s so it can directly reference them. In addition you can even do things like do sub-templates that you can put anywhere, like having a Notifications button at the top that renders with the current notifications (progressive enhancement) but will also receive updates to itself, only updating the part of the DOM that actually changed without iterating or recursing or re-rendering anything else. :slight_smile:

With Drab.Live it is also similar to a react/elm model, you have the ‘Commander’ that is the ‘state session’ for that page on the server, you can broadcast to it like any normal Channel, it can use those events to apply updates, can broadcast to all people on that page, a single person, etc… etc… Drab does not transform the state changes in to HTML, rather it transforms it into a set of commands to directly and specifically modify the parts of the HTML that needs changing, without touching anything else, even with little container’ed parts like the Notification it can’t affect anything outside of what it’s view defines (without sending a message elsewhere of course or sending a raw javascript command or something).

This still sounds very much like Drab.Live based on your post (except Drab’s builds it’s template information for fast updating at compile time without needing to take html parts again), so I’m curious what the differences are.

Drab is a multitude of parts, at it’s most basic is Drab.Core, which contains the Channel system and simple javascript command executer. On top of that is Drab.Query (or whatever it’s called, I don’t use this one) that basically exposes JQuery’s API to the Phoenix system to mutate the page that way as you wish, to things like Drab.Live and everything in between.

You can see the demo page Drab: Server Side User Interface Access running a Drab server remotely (to me anyway, off in Europe or something somewhere), so it has a good half second latency to me and yet everything on it works properly. You can give it a try and look it over. It demonstrates many of its API’s, Live and others, but even the top Drab: Server Side User Interface Access example is a simple Drab.Live demonstration, first you make the template:

<form>
  <input name="text_to_uppercase" value="<%= @text %>">
  <button drab="click:uppercase">Upcase</button>
  <button drab="click:downcase">Downcase</button>
</form>

If you set a callback url it could even be progressively enhanced as well, but then you make the commander:

defmodule DrabPoc.LiveCommander do
  use Drab.Commander

  defhandler uppercase(socket, sender) do
    text = sender.params["text_to_uppercase"]
    poke socket, text: String.upcase(text)
  end

  defhandler downcasecase(socket, sender) do
    text = sender.params["text_to_uppercase"]
    poke socket, text: String.downcase(text)
  end
end

The sender contains the data related to the action, in a form’s case it sends the form, you can also specify other data to send with it or whatever as well. Then all it’s doing is updating the assign in the template of the key text with the mutated string. The Phoenix Controller for the page is no different than what you’d expect except for a use Drab thing at the top. It will then send the string to the template drab handler that will see where it is used and setup a minimal command to send to the client to update it, which for <input name="text_to_uppercase" value="<%= @text %>"> will be something like document.querySelectorAll('[drab-ampere="geztqmbwgq2dqnbv"]').value = "UPPERCASED TEXT" (although it has it’s own javascript framework that simplifies these calls even more, but conceptually that is what it does).

The ‘*.html.drab’ templates are parsed using Floki to get all information about the html, passing it straight through as a string otherwise, so it can build that information so it knows how to query the DOM. The drab-ampere attribute is the unique ID of how to access that element that has an assign somewhere in it’s executed code (or higher up references, in the worst case it will re-render large chunks of HTML, but if you don’t do anything crazy in your view it is nicely efficient, but it has had a lot of work done to be able to figure out where and how things are used or to fall back).

But yeah, that above demo page shows off a lot of Drab, not just Drab.Live stuff but a little of all of it, but even just looking at the Drab.Live you can see how similar it is to every description I’ve seen of LiveView here so far? I might be able to watch the video this weekend, but at least based on the descriptions thus far it seems like LiveView is just rewriting Drab.Live (although perhaps more cleanly as rewrites often do, but PR’s can always fix up Drab and Drab has a lot of functionality as it stands built up over a long time).

Thus why I am exceptionally curious what makes LiveView so different from Drab.Live that makes usurping another projects major feature with near identical functionality (I havn’t seen anyone mention how LiveView would determine how to set an attribute or a property for example, among other things, on an element, which Drab can do among other things) in such an announced way.

Lol, I think it depends on how long people have been doing this. I started back writing perl CGI scripts way back in the mid-90’s, and I wrote my own BBS server with 3 dedicated connections before that! It was so fun! ^.^

7 Likes

The Shared Commanders in Drab let you create reuseable components (even many times on a single page if you want), which are especially cool (I use these excessively in some areas). :slight_smile:

4 Likes

Which was your idea (AFAIR), which only shows how Drab evolved in with the help of community!

3 Likes

Honestly I ripped it from both Wt (Web Toolkit in C++ that is very much like Drab.Live/LiveView but even more… old and refined and C++) and Polymer. ^.^;

I used that feature heavily in both of those too. :slight_smile:

3 Likes

I think I lied about drab in my talk at elixirconf - if there’s any way I can rectify my accidental lie let me know - I think I said something to the effect of drab only being targeted updates that didn’t behave like my library texas. I don’t have much of an audience or I’d just tweet a correction or something :sweat:

8 Likes

this_commander looks very jQuery. When I want to update the first span from within the second commander, is it possible to get first commander reference? If so, it’s going back to jQuery problems.

I may not understand Drab much ^_^!

this_commander is just a drab function that returns a string that is the commander’s unique topic, it’s nothing but a helper (though a very nice helper). Not similar to jQuery even remotely.

What do you mean by first commander? You can get any reference on a page by building a name for it if you need, though cross-commander talk should really always be done via broadcast messages and assigns. :slight_smile:

Drab is actually really easy to use, especially if you keep to just Drab.Live (which is what I do 99% of the time until I need to interact with the unpoly.js library). :slight_smile:

1 Like

People are allowed to conceive similar ideas you know - remember Erlang and the Actor model? :lol:

The importance of having something like LiveView as part of Phoenix, to me at least, is incredibly clear.

There’s one thing being acknowledged, endorsed or linked even, but it’s quite another being part of a system that you know and are already invested in. That seamlessness is priceless, it drives adoption, instills confidence and has untold benefits in all manner of areas whether now or in the future. Autonomy is crucial too, being 100% aligned with the parent project is extremely important for something that (may become) so integral to it. Then there’s having very particular requirements or thoughts on how to approach and tackle things, which you generally want to do with little or no friction so that your vision remains undiluted.

There are just too many benefits to mention (think about all the books that are going to cover it, the screencasts, blogs, etc etc etc) and so I genuinely believe LiveView being a part of Phoenix is going to be better for all of us in the long run… just think, if it delivers on its promise it will not only be amazing for us, but could help take Elixir and Phoenix to the next level. I’m pretty sure that’s what we all want, right? :blush:

3 Likes

Not similar to jQuery even remotely.
You can get any reference on a page by building a name for it if you need

Ah, isn’t it selector something something

What do you mean by first commander?

I referred to the Shared Commanders example (your link) but,

though cross-commander talk should really always be done via broadcast messages and assigns.

you already got the point I was concerned. I don’t know what’s usual practice and it seems it embraces unidirectional flow which is better than letting user manually change each other commander context.


I watched the Phoenix.LiveView talk, and it seems its apis are not settled yet. Though def handle_event is cleaner than defhandler (it’s not that important but you know it’s another macro). It also doesn’t require extra template extension (*.html.drab) although a dedicate processing might be more useful for larger use cases. For now it seems ok to put more little stuff in eex project.

I understand your point about reinventing. And I think it’s ok (For example, ActiveStorage vs Carrierwave). Well people keep reinventing old idea maybe just because it’s exciting :slight_smile:

ps; I’m not sure what’s the scope of this thread, hopefully I say something useful. ^^

1 Like

Chris was careful to explicitly state that it would NOT be part of Phoenix.

You do realize that’s self-contradictory???

I’m joining this a bit late but, as far as I can tell nothing about this intrinsically violates any boundaries. It’s our plan for example to hook these live views up to GraphQL queries / subscriptions. For all intents and purposes it’s just a GraphQL client that happens to have a particularly low latency connection.

5 Likes

Whether it is released under the Phoenix organisation or Chris’s own, it’s quite likely going to be seen by most as ‘part of Phoenix’ (and I’m sure many of us will campaign for the r/ship to be as close as possible because of the benefits as described in my previous post). In fact if you look at the comments around the web this is already how people are viewing it - I’m sure I’ve read comments like:

Phoenix has declared war on…

Sorry @reactjs , I think I’m in love with @elixirphoenix LiveView.

Phoenix has a real opportunity to advance the state of the art by making realtime views this easy

Did you see the Phoenix.LiveView demo at @ElixirConf?

etc. :slight_smile:

With regards to your other point, which part is contradictory? Parent project or main goals of the project equate to roughly the same in this context.

100% aligned with parent project is pretty much the polar opposite of autonomous.