sergio

sergio

Are you all in on LiveView? How are you using it?

LiveView has me quite excited. The possibility of building a simpler architecture that ultimately leads to better user experience and better developer experience is compelling.

Fly.io + CockroachDB + Elixir + Phoenix LiveView

Anyone out here using LiveView in production today? What’s your experience like?

Most Liked

tj0

tj0

Been using Liveview in production since 0.1.0. The cognitive overhead is much lower and I can’t say enough good things about it. Simply put, it made a herculean task of building desktop-like software, merely difficult. That is truly innovation. Fire And Motion – Joel on Software covers my thoughts pretty well on this. While everyone else is busy keeping up with the tech and wasting their time, liveview just works.

Here are some notes:

  • I designed the frontend so that the user rarely has to hit the server unless they actually new data, so I am not running into any of the downsides of the approach at the cost of sending 10k-20k extra uncompressed data upfront. The compressed page is still 30k though.
  • Each livesocket uses some amount of memory on connection and holds it in the state. Early on, I had to manually hibernate the threads. This was added by default in 0.5.0. This is super-important to be able to scale the number of concurrent users. I made sure that most of the user actions do not go back to the server by using hooks and css, so this memory saving is real. More on that later.
  • Security - it took a while to figure out the difference between the different mount options in liveview. For instance, to have the user_id available with both liveview and non-liveview, I had to use conn.assign and Plug.Conn.put_session and read the session from the liveview.
  • Speaking of sessions, I have been using cookies to store the session and include user preferences. I was shortening the cookie fields from “pref” → “p” in the cookie to save space, but what I didn’t realize is that everything would end up in the session cookie. I’m not sure how I missed it, but I was awfully close to running out of cookie space. Eventually, I had to make a guid in the cookie, store everything in ETS, sync the ETS prefs to DB, and make a distributed cache update on ETS for multiple machines if a pref was changed. Quite frankly, the distributed cache update was the easy part.
  • Optimistic UI - if every menu update had to go back to the server, that would be really irritating. I’ve been using CSS instead of alpine with No Javascript Clientside Phoenix Live View Modals
  • Alpine - on that note, I’m not sure what the point of using Alpine is. It just seems to add another layer to have to debug. I tried it and then re-wrote what I needed in maybe 50 lines of hooks.
  • Form recovery is important to get right. If a user changes to a different tab, what will happen is eventually the browser will remove it from memory on mobile. Form recovery gets called quite a bit for me.
  • I’ve been strictly using stateful components. The rendering time is in a single process and I haven’t tried improving it. My main page has about 15 components which take 40ms to render. I’m not sure if changing these to liveview would make life more or less complex. I’m still on 0.15.4. Unfortunately, I’m not looking forward to 0.16.0 since I have to change all my stateful components to heex.
  • Testing - I haven’t written a single liveview test. There have been occasional small breakages on upgrade, but those would not have been picked up anyway by tests.
  • Rendering size - websocket is passing about 40k-70k of data on an update. Adding compress: true to the socket options saved me about 50ms on update for far away users.
  • Hooks - Overall, I have 350 lines of js. The user doesn’t need to contact the server unless they are actually executing an update or need a re-render. ’
  • Typeahead - there are so many tutorials that use datalist including the default from the liveview examples. DO NOT DO THIS UNLESS YOU HAVE EXACT MATCHES. Each browser implements datalist slightly differently, but more importantly, it will further filter your results based on a String.contains. So if your result doesn’t have a comma, but the input does, the result won’t show. Instead, use relative_div → absolute_div → ul / span / etc and use phx-click and careful with safari.
  • Safari is annoying in general. Not to do with LiveView, but sometimes items where not clickable with phx-click. This is a Safari’ism, where you can’t put phx-click on a div, etc.
  • Breaking changes - it’s 0.x software which is remarkably stable. But there will be breaking changes on upgrades. I suspect the churn is still less than the js ecosystem though.
  • Sending events on the backend is great for GUI design/updates.
  • Regarding fly.io, I’m planning to use it once I migrate a lot of my read only data to sqlite. At that point, the update latency will be ridiculously low.

Yah, what can I say really. Liveview is fantastic.

34
Post #2
josevalim

josevalim

Creator of Elixir

Thank you @tj0 and @shd42 for the detailed and precise feedback coming from your dev and prod experiences. I have taken notes on what works and what could improve. If all feedback was written like this, my life would be much easier. :slight_smile:

27
Post #7
shd42

shd42

I’ve started using LiveView since the 0.13.3.

I’m a one-man shop, having grown quite a bit tired of NodeJS / VueJS endless changes in direction / way to many packages required to make a web app (half of which, only used for development) and a number of other things like testing (i’ve used Mocha and Jest, both of which remain a pain to use IMHO) which all had a part in my decision to go for Elixir/Phoenix/LiveView. Considering the app i’ve moved over is about 75% of my incomes, and a sizeable amount of clients which i all know personally and we’re relying on me to not mess that up, i didn’t take the change lightly (obviously). But it really was all about seriously alleviating the load required to update and maintain my app (and by extension, my happiness in getting up and doing my job which was far from stellar prior to the change) while making sure for my clients that the change would be mostly invisible and/or at least only for the better.

About a year ago (June 2020), i started the rewrite, choosing to learn along the way everything i needed (including LiveView). After all, an actual app where i knew what i had to do, but not really how to do it in my new stack was a good way to learn (and i’ve always done it this way in the past, without much issues so…). I won’t bother everyone discussing everything since it’s about LiveView. 3 months ago, i finally put in production the rewritten version (i use Scalingo) and since then, and i have barely got any issue at all:

  • I didn’t hit any latency issue, and i’m relying quite heavily on client/server trips (data driven, and realtime saving). To be noted that all my clients are situated in the same country (and they’re all within 1000km from the servers), so i’ve never had to deal with anything related to really long distance usage. I already had to do roundtrip to the server on my previous stack, and the move to LiveView only made it simpler while keeping the performance and optimistic UI.
  • I’ve only started using AlpineJS towards the end prior to deploying, mostly to reduce the amount of javascript code (i’ve had enough of that for a lifetime) i would have to maintain. It’s been quite seamless, not much debug required overall. I still retain a number of hooks on complex UI related part of the app.
  • I’m only testing my LiveViews for things like authentication/permissions, and a number of critical things. Overall, i didn’t feel the need to go far on that front.
  • One of the thing that ended up being an absolute breeze compared to my previous stack was how to handle the role/permissions system. Well, most things ended up being easier to handle, but that was strongly the case for that part. To put it simply, entirely handling the state server side while keeping the SPA type of app for the user has been an absolute breeze of fresh air. I no longer have to think twice about my data.
  • I’m not currently a big fan of Live Components, i have quite a lot of them (both stateful and stateless), but they are clearly not (yet) on part with what i had in VueJS. Lack of a proper slots system, inability to use handle_info in stateful components, which makes separating LiveView in multiple parts less easy, or sometimes, not even making much sense. In addition, using non-routable LiveViews has often limitation that come in direct contradiction with the needs, ending up also not being the solution. They’re still good overall, but there’s some things that could be better.
  • The latency compensation regarding automatically adding classes isn’t of much help currently. Far too often, the element the class is being added to isn’t the one that should receive it (and the concept of the global handling with phx-page-loading isn’t great). I ended up using mutation observer to handle user feedback on what’s going on (adding classes manually where they should be, through AlpineJS init()). It’s not like a big issue, but there’s room for improvements.

I’ll resonate with what @tj0 said, LiveView is fantastic :face_savoring_food:. I know often the discussion is about big companies using the stack you like, but i’ll say that at the very least, for small teams or like in my case, single developer, LiveView seriously ease the amount of work required to make and maintain an app that requires SPA-like stuff. Over a year down the line, i can only say that i’m fully satisfied with my choice and i’m starting to look towards contributing back to the community (still have to get past the damn impostor syndrome, but i’ll get there :smirking_face:).

23
Post #3

Where Next?

Popular in Questions Top

chokchit
** (DBConnection.ConnectionError) connection not available and request was dropped from queue after 2733ms. You can configure how long re...
New
nobody
How to bind a phoenix app to a specific ip address? could not find anything about that, nowhere, unfortunately, but for me this is quite...
New
greenz1
I have a phoenix application from which a user can download multiple(5-6) files of size 1MB. I couldn’t find anything related to sending ...
New
shahryarjb
Hello, I get Persian date from my client and convert it to normal calendar like this: def jalali_string_to_miladi_english_number(persi...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
Emily
I have VueJS GUIs with the project generated using Webpack. I have Elixir modules that will need to be used by the VueJS GUIs. I forese...
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" => #BSON.ObjectId<58eb1a7a9ad169198c3dXXXX>, "email" => ...
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New

Other popular topics Top

sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
mcarvalho
What is the difference between System.get_env and Application.get_env? For example, what are best practices to use one versus another.
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New
JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New
boundedvariable
I am going through the kafka architecture. All the features what the kafka is providing are already in Erlang. I would like hear your opi...
New
rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list. ...
New

We're in Beta

About us Mission Statement