Phoenix LiveView is now... live!

Awesome great work @chrismccord, @josevalim and everybody else who is contributing! Thanks!

3 Likes

Can you elaborate more on what you did?

1 Like

Congratulations on the launch. Iā€™ll hold my hands up as one of the people filling your inbox :sweat_smile:.

Iā€™ve actually been working on an interactive form all week, and have been trying a few client side approaches (Svelte V3, React, Vue) and some server side ones (Drab, Channels hooked up to Stimulus). When I saw LiveView this morning I immediately downed tools and had a play to see what a LV implementation would look like.

The form that was live until earlier was powered by Drab, and along with rebuilding the form half a dozen different ways I felt pretty confident putting together the LiveView version. I have to say that it excels at ease of use and logical API. Quite similar to Drab.Live in this regard and also Phoenix Channels.

That said, I ultimately put LiveView aside and finished my Stimulus/Channels enhanced form. I couldnā€™t quite get my head around using it with forms and changesets. LV only operating on the form, and not the inputs confused me. For example, I couldnā€™t work out how to dynamically add a new record to an association without having a phx-click on a button inside the form. That didnā€™t play nicely with the phx-validate, and it became a case of either or, and I simply couldnā€™t replicate what Iā€™ve built with Channels and JS.

I suspect that Iā€™m missing something, and will take a proper look at LiveView next week, as your commentā€¦

ā€¦makes me believe what Iā€™m doing should be possible.

Anyway, congratulations on the launch! Even as someone whoā€™s very comfortable with JS, I can see myself reaching for LiveView often!

4 Likes

You can use Phoenix.PubSub (which Phoenix will use by default), if you donā€™t want to depend on Postgres. Regarding large collections, right now adding a new entry will always reload the whole page but we plan to include mechanisms were you only append/prepend items.

8 Likes

Oh fantastic, thank you!

Iā€™ll definitely take a look at this and it really is time for me to roll my sleeves up and get into Phoenix properly.

1 Like

Just thought Iā€™d try out the rainbow torture test and Iā€™m really impressed. I managed 9 windows, all cranked up to 100FPS before I hit 100% CPU usage on a $5 Digital Ocean droplet. My (high spec) MacBook Pro was having more problems with it than the remote server was.

I think youā€™d have to have quite a lot of users (when using LiveView as intended) before youā€™d put some hurt on even a modest dedicated server. Thorughly impressed!

7 Likes

I knew this was going to be a great weekend :partying_face:

2 Likes

I want you to know that I had plans this weekend before this was posted. Know that.

8 Likes

For anyone trying out LiveView, WebSocket felt really slow to connect when I used localhost:4000. It seems that there is some sort of delay at least on Windows. According to this https://stackoverflow.com/questions/15135506/websocket-connection-setup-takes-a-relatively-long-time-is-this-normal itā€™s caused by IPv6. So if someone is experiencing this as well, use 127.0.0.1:4000 instead.

3 Likes

I asked a question about Optimistic UI 22 days ago, and had a great discussion about the possibilities of achieving it through the use of vanilla JavaScript with Phoenix and/or LiveView, but now when LiveView is released, would you guys please revisit my question and give me some insights about what do you guys think about the possibilities of achieving Optimistic UI with vanilla JavaScript and/or LiveView.

@chrismccord @josevalim @ericmj @Gazler @jeregrine @lance @scrogson @fishcakez @lexmag @whatyouhide @peerreynders @OvermindDL1 @dgmcguire

thank you!

Thank you very much for your response and explaining the current state and direction of LiveView. Thereā€™s so much to explore!

It was not my intention to downplay realtime crud forms (or any other goal LiveView is pursuing). On the contrary, I donā€™t like building and maintaining a JS SPA, LiveView looks like it could be a game-changer.

Perhaps itā€™s that I see so many possibilities and get so many ideas about this that my thoughts are getting a bit unrestrained and indistinct. As you said: start small and see where things go. :slight_smile:

2 Likes

I think this pattern will be important for LiveView backed forms. From a user point-of-view, losing a bunch of stuff you typed in is a negative experience. However, Iā€™m excited to see what kind of patterns emerge for this.

But while I thinking about this stuff, Iā€™m also not thinking about all the Javascript I would have to write.

I compiled a simple vue component with the webcomponent build target and deployed that within the Demo app web artifacts. In a new LiveView module, I added the custom element markup and socket bindings. Binding the server state into the element works great, i piped in the clock, weather, etc. It works like any other data property and doesnt rerender the entire component.

Unfortunately I spoke a bit too soon. The downside seems to be getting data out of the component. I hacked around the click/submit/change handlers but could not get it to populate the value field of the event passed up the socket. If the wrapper supported CustomEvents (something like. phx-custom-eventname that grabs event.details) then webcomponents could probably work.

Fear not, this is easily doable today :slight_smile:
I have pushed a branch with an example:

Code wise, you can add the dynamic fields with inputs_for like a regular static form:

  <%= label f, :hobbies %>
  <%= inputs_for f, :hobbies, fn hf -> %>
    <%= text_input hf, :title, placeholder: "hobby" %>
    <%= error_tag hf, :title %>
  <% end %>
  <button phx-click="add_hobby">+ Add Hobby</button>

Then in your LV:

  # UserLive.Edit
  def handle_event("add_hobby", _, socket) do
    changeset = Accounts.build_hobby(socket.assigns.changeset, %{title: ""})
    {:noreply, assign(socket, changeset: changeset)}
  end

Thatā€™s it! As long as you update your changeset assign, which is what the validate callback does, then thereā€™s no ā€œeither/orā€ dance as the server has the changeset state. My build_hobby code in this case is just a simple ecto embed, but you can get the idea:

  # Accounts
  def change_user(user, attrs \\ %{}) do
    user
    |> populate_hobbies()
    |> User.changeset(attrs)
  end

  defp populate_hobbies(%User{hobbies: []} = user) do
    %User{user | hobbies: [%Hobby{title: ""}]}
  end
  defp populate_hobbies(%User{} = user), do: user

  def build_hobby(changeset, hobby) do
    hobbies = Ecto.Changeset.get_field(changeset, :hobbies)
    Ecto.Changeset.change(changeset, hobbies: hobbies ++ [hobby])
  end

Hope that helps! Here is the branch:

22 Likes

Thatā€™s brilliant Chris, thank you! I was thinking about it last night (no computer in front of me) and was going to try something similar. Thanks for the example!

1 Like

Congrats for LiveView great devs! ā€¦ this seems to be so exciting that if I had the time I was going to start changing lots of JS stuff to it.

However, I am mostly thinking about how to implement the following patterns in LiveView:

  1. Infinite scrolling
  2. Modals/Dialogs
  3. Some material design artifacts such snackbar

I see there is a phoenix_live_view Javascript module with lots of logic in it. Perhaps, if Iā€™m not wrong, the JS architecture can be improved to make it more extensible, by breaking the file into smaller ones so people can reuse parts and add features without having to touch the core ā€¦

Anyways, going a little bit deeper, I was reading the morphdom README and found the following sentence:

UPDATE: As of v2.1.0 , morphdom supports both diffing a real DOM tree with another real DOM tree and diffing a real DOM tree with a virtual DOM tree. See: docs/virtual-dom.md for more details.

This makes me think that in the near future, it might be possible to update a React app with content from LiveView.

Finally, Iā€™d like to know if using GraphQL more specifically Absinthe will make sense instead of accessing the backend directly without the extra layer, in case of using plain LiveView without extra Javascript of course.

3 Likes

This looks fantastic. Iā€™ve been waiting to use this in a project of mine. Huge congratulation to the team.

One question - I modified the autocomplete example to return 200 words and on my box the search ground to a bit of a halt - it did eventually return but was taking seconds to display the results. I appreciate returning 200 words isnā€™t perhaps a real world use case but wondered why the performance loss?

This is amazing, I remember hearing about LiveViews and then watching one of Chrisā€™ video about it a few months ago and thatā€™s one of the reason I started to look more into Phoenix (as a Rails replacement) as Iā€™m looking more into how to reduce the ā€œSPA for everythingā€ trend.

Iā€™ll look into migrating a simple form I have that uses Ajax to LiveView and see how it goes!

Iā€™ve been thinking about contributing to Elixir/Phoenix - are contribution opened yet? How can we jump on the bandwagon and help?

2 Likes

ā€œ200 wordsā€ is nothing as far as LV is concerned. Consider the rainbow where we are generating 80 divs every 16ms :slight_smile: My hunch is the browser is choking on the <datalist> updates containing 200 options, so my wild guess is itā€™s a browser issue and nothing in what weā€™re doing on our side. The datalist thing is somewhat new, so likely not optimized. UX wise, it also doesnā€™t make sense to render that many options below an input, so the browserā€™s UI rendering of it is probably not optimized for that case.

2 Likes

Awesome. Let us know how it goes! We tag issues on the phoenix repos as level:starter when they are good opportunities for new folks to get involved without trying to take on the world. We just had our 1.4.2 release so a lot of issues were closed out, but keep an eye on the issue tracker, as this is the best way to get involved. Welcome aboard!

3 Likes