In this article, we will go over why we choose to go with this approach instead of using LiveView.
LiveView works by holding a stateful websocket connection. This means anytime you do a deployment, you will need a strategy to persist and restore that state. This can be done via encoding that information in the URL params or hash params, or saving the state in Redis or Postgres.
Failing to do so will result in a jarring user experience during deployment, as the LiveView will “reset” as through the user has visited the page for the first time once more. For our quiz component, we saved the quiz session state in Postgres and it worked well enough.
However, we still ran into some rough edges as we needed to evolve the state table schema and data within it during migrations.
In comparison, rolling deployments are trivial for traditional stateless applications. Simply have the reverse proxy route all new requests to the newer version of the app. Since there are no stateful websocket connections, there is no need to worry about draining old connections.
In short, one pays for LiveView in the form of deployment complexity.
LiveView has not reached 1.0 yet, so it is subject to frequent changes. For example, in the past year the recommended templating language changed from LEEX to HEEX. The HEEX is great and a huge improvement, but it was a bit of effort to make the changes to our existing templates. We could have kept the LEEX templates and still be supported, but most tutorials used HEEX, even before Phoenix 1.7 came out.
Related to the previous point, we also ran into an issue where a status code sent by the Caddy reverse proxy when doing rolling deploys would result in the Phoenix LiveView application completely breaking.
All of this is to be expected, and I think for many they are willing to accept paper cuts to stay close to the cutting edge.
Most changes in Phoenix LiveView requires a server-round trip to process. Therefore, it is suggested that LiveView should only be used for interactions that would need a server round-trip anyway, like fetching extra data or updating a form.
The main interactive widget on our site is our quiz page. There users are quizzed on items they previously learned, and they type in the answer to be graded.
We initially thought using LiveView would be fine for this, since we wanted to do a round-trip anyway to update the user data when they answer a question.
Unfortunately, the visible delay from hitting ENTER and the input turning red or green resulted in a degraded experience.
However, we think most websites don’t have latency requirements like this. For standard form updates and lazy loading data, LiveView is not going to be any slower than any SPA - in fact it may be faster.
Phoenix LiveView is pretty magical in what it can do. It does state change tracking to send down incremental updates over a websocket to update the client DOM.
Unfortunately, we personally think it is harder to understand and tinker with than the traditional MVC model. I don’t think this is anything inherit in the Phoenix LiveView model per se, but depends on the person. I’m sure there are others that think the opposite!
For example, if we hit an issue with HTMX AJAX-powered SPA-like navigation, looking through the HTMX code is usually pretty simple. After all, it is a single file with no transpiler. And I can easily reason about how things are working because it is just a thin layer on top of traditional stateless HTTP requests, which can be easily inspected and understood.
However, for LiveView, one needs to have a deep understanding of the LiveView lifecycle instead. In exchange, you have less code you need to write and maintain.
Picking LiveView or any other frontend approach really comes down to one’s own tastes and the requirements of the application.
We think LiveView is cool technology, and have nothing but respect for the entirety of the Phoenix team. I can see it growing in popularity, especially after it hits 1.0. However, I do think there will be many, like us, who will stick with more traditional Phoenix applications.