Liveview and HMR (hot module replacement)

One of the most important techniques in today’s JS world is HMR - hot module replacement. This is where you make changes to the code base and your browser updates WHILE maintaining state. It’s available in most frameworks now: Angular, React, Flutter, Clojurescript. And it’s an enormous time saver during development.

Are there plans to give Liveview this capability? Say I’m working on a form, and it took me half a dozen steps to reach the point I’m at, and there’s a bug. I fix it in the code, and HMR injects the update while maintaining state. Meaning, I don’t have to walk through all the steps again to get to this point of the app.

I’ve been trying to think of how this could be done in elixir. I’m not nearly an expert, but if most form state is being kept in GenServers, can that state be saved through updates? Perhaps using the same mechanism as Erlang’s hot redeploy? If someone could point me in the right direction on how to research this, I would appreciate it.

Actually - as far as the HTML part stays (mostly) the same, it will be handled automatically OOtB (at least in development). In production it would require a little more work, but should be doable as well (assuming that the generated HTML will be compatible).

1 Like

The BEAM already allows to reload modules and keeps the data :slight_smile:

Since LiveView manages the state on the server, this already works, provided you use Hot Code Reloading in Elixir (which, to be fair, is a bit of a hassle to set up/maintain, because you will have to provide explicit upgrade/downgrade functions for your genservers to ensure they do not crash when changing to the new version).

2 Likes

I’m confused by some of the answers here, here is what i have to say about it:

  1. phoenix LV does NOT do this OOTB. The default setting for LV is to have fs-notify up and running, which when you make a change to your code will tear down the connection and reboot the liveview. At this point, the internal state of the liveview is lost. In order to get hot code updates and keep the liveview state, you have to disable the code reloader.

  2. If you do this, then you can hot-code reload the liveview (eg. using recompile() function from the console). This “just works”. You do not need to provide upgrade or downgrade functions, it’s unnecessary. If the internal state of your liveview is incompatible with the new code, then yeah, the LV will crash, but in dev, you probably don’t care too much about that.

  3. I think code reloading is probably what you want. Almost all of the time you want the liveview itself to be maximally stateless. If you need something truly shared and stateful (like a chat room or a game state) then that will live inside of a separate genserver (or database) that doesn’t get torn down when the liveview is rebooted.

  4. OP’s statement “the form state lives in a genserver” by which I think OP means “the form data lives in the liveview”… You could do that, yes, but don’t, unless you have a damn good reason to. Your form should live client-side and on update or submit it gets sent back down to the liveview which can react to it, but probably it shouldn’t save it internally in 95% of use cases.

3 Likes

Huh, so using recompile() may solve this. Let me test this out and see how it goes, I didn’t think of such a straightforward solution. Thank you for that.

And what I meant by the form is simply this: say I am testing the liveview and I walk through a login and then pull up a form, and then pull up a certain record. If I find a bug at this point, will using recompile() maintain that record that is currently showing in the form? So it will not refresh the entire page, not force me to walk through the whole login process again, and not have me find that record again. And if I make any CSS/SASS changes, the state will still be maintained. I will start looking into this.

I think that will largely depend upon how you have implemented your LV. If the state is stored in the LV itself for some reason then that would likely be lost on recompile, but if all of your application state is stored on the server and the LV reacts to that state, then the server data should be maintained.

1 Like

if you pull up a record, you should try to make it so that getting to that point is stateless (aka there’s some sort of query parameter in the URL that can be used to rehydrate to that point). This is good practice anyways, so in a certain way the inconvenience around not saving state due to fs-notify nudges you to do that.

1 Like