What is Phoenix LiveView
Dylan Lederle-Ensign, Former Senior Developer
Article Categories:
Posted on
LiveView is a feature of Phoenix that enables fluid, realtime web interfaces that don't require writing JavaScript. This post explains how it works at a high level, compares some alternatives and thinks through when it might be useful.
LiveView is one of the most exciting features in the Phoenix web framework. It's a new way to produce fluid, realtime web interfaces that doesn’t require writing JavaScript 1. Some of the initial demos really caught my eye, so I’ve spent the last few weeks playing around and learning about how it works. In this post, I’ll try to share some of that excitement, tell you how it works at a high level, compare some alternatives and think through when it might be useful. In future posts, I'll get into a hands-on tutorial.
The Sizzle Reel
Before we get into the details of how it works, let's geek out about some of the official demos!
Here's a snake game, rendering at a playable framerate:
Here’s a thermostat that responds to user input, fetches weather data from an API and displays the new temperature.
Here’s a basic user signup form, with some data validations running on the server:
These may not seem that impressive, but remember that all of these demos were created using just Elixir, without any JavaScript to write or maintain. That’s pretty cool!
For more experimental demos, check out the results of the recently wrapped up Phoenix Phrenzy competition. There are some really impressive apps and they’re all open source!
But how does it work?
The LiveView programming model will feel very familiar to anyone who has worked with React or similar frontend frameworks, but with the rock-solid reliability that Elixir brings to the table. LiveViews are programmed declaratively: the programmer specifies the state of the program and how it can change and then LiveView figures out how to update the rendered page to match the new state. This is a huge improvement from having to imperatively tell the browser each step needed to change what it's displaying, and it’s great that LiveView has adopted this model.
When you write a LiveView template, you include some pieces of dynamic data within your static markup. This is no different than a templating language in any other server-side language; if you’ve written Twig in PHP, ERB in Ruby, or Jinja2 in Python, you understand the basic concept. Where LiveView templates work differently is when that data changes. Let's walk through a toy example to illustrate how this works at a high level.
Say we’ve got a dog photo-sharing site. On the initial page request, your rendered template HTML and the LiveView JavaScript library is sent to the browser 2. The browser responds by opening a WebSocket connection for future updates:
This page has only two pieces of dynamic content: the comment stream and a count of upvotes.
Now, let’s press the upvote button, change some of that data, and see what happens 3. Without going into implementation details, we bind an event to the button and then write a handler function (in Elixir) that responds appropriately. When the button is pressed, the event is sent over the socket connection.
Only the changed content is sent back to the client! Since our comment stream hasn’t changed, we don’t send any new comments. This makes the data sent over the wire very slim. This enables LiveView to provide highly performant experiences by default.
How does this compare to...?
There are three main approaches to building a web app.
- Full Page Reloads
This is the classic old style of web app. Users click a link or other piece of interaction on the screen, and a request is sent to the server which responds with a complete new page representing the new state after the interaction resolves. The server renders the HTML and sends it over to a dumb client that does little more than present it to a user.
This works great for many kinds of applications, particularly content sites that skew closer to the original vision of the web as a document delivery platform. It falls down when we want the user to be able to interact in real-time with the application. - Single Page Apps
In a full Single Page Application (SPA), the entire UI is written in JavaScript and interacts with the server through API calls. For any decently complex application, this adds up to a lot of code to manage. That's why the last several years have seen a dramatic rise in the usage of JavaScript frameworks like React (our favorite!), Vue, Angular or Ember.js 4. The page fully reloads only on the first request to the server; for every subsequent interaction, the server will send only the data requested and the framework figures out how to update the UI to match the new state. This is a very nice approach that has advanced incredibly far, incredibly fast. The tooling has gotten really sophisticated and it's possible to build some fantastic interfaces.
There are some downsides. The simplest is that all this JavaScript requires sending a lot of code down to clients. We’ve developed a number of techniques to get around this (bundling, compression, uglification, code splitting) but at the end of the day, you still need to regularly check bundlephobia to keep your code trim and slim. A more subtle issue is the duplication of domain representation that occurs. Most of your application executes on the client-side, but some bits still need to live on the server-side. In practice, you often end up writing the same business logic in both places. This is both a frustratingly inefficient use of time and a maintainability nightmare. - JS Sprinkles
To avoid the pitfalls of a full SPA, some are advocating for a “sprinkles” approach to your JavaScript interactivity. Most of your application is still server-rendered HTML views, but some pieces get a little “sprinkle” of JavaScript. This sounds a lot like the early days of Web 2.0 where some pages got the jQuery treatment and others remained static. There was a lot to like about that approach, but it’s difficult to scale up to a more complex UI.
When would I use LiveView?
The LiveView approach is an exciting alternative to the three I just listed, which promises some of the fluidity and responsiveness of an SPA, with the maintainability and developer productivity of server-rendered HTML. It very neatly offers a new path forward away from the complexity of webpack and friends. In any Phoenix application where I would be tempted to sprinkle on some JavaScript, I think I’ll be reaching for a LiveView module first.
All that said, LiveView is still early stage software that is not quite ready for prime time. In my week of hacking around, I found that file uploads over a LiveView socket was not yet supported, but there was a talk demonstrating a proof of concept at this year's ElixirConf. Phoenix maintainer Chris McCord said that he is no rush to hit a 1.0 release, preferring to slowly build on the core LiveView that exists now. I am excited to follow along and contribute!
Notes
- The JavaScript is still there, but it's provided by the Phoenix framework. We aren’t writing it ourselves. ⤴️
- This is great for SEO and metrics that measure how quickly content is available (i.e, Time to Interactive, First Meaningful Paint) because the user doesn’t have to wait for JavaScript before they can use the page. ⤴️
- We are not providing a downvote button, you monsters. ⤴️
- While they all have their differences, for the purposes of this discussion they are all solving the same problem. ⤴️