HanziHero is a Chinese character learning web application that leverages the powers of mnemonics and spaced repetition to help you learn thousands of Chinese characters!
It is written in Elixir using the Phoenix Framework. Earlier versions of the application used Phoenix LiveView before switching over to using a combination of small composable JavaScript libraries:
- Mithril – for complex interactions
- StimulusJS – for simple interactions
- HTMX – for SPA-like navigation, lazy loading, form enhancements
In this article, we will go over why we choose to go with this approach instead of using LiveView.
Stateful vs stateless
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.
Stability
LiveView has not reached 1.0 yet, so it is subject to frequent changes. For ex