-
-
Notifications
You must be signed in to change notification settings - Fork 139
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Proper hot code reloading #749
Comments
Of course, many solutions to this problem are pretty hacky and unsound. I don't think any of the JS frameworks or bundlers implementing hot reloading (often referred to as "HMR" - hot module reloading, presumably since modules are the smallest unit replaced) have a great story around what happens when interfaces change in incompatible ways. But Miso is potentially in a great position to handle this in a principled way, since everything is immutable and the state is a first class entity. It even has a type, so we can detect when changes are incompatible. All we need to do is serialise the state on each update (or on exit, if we can reliably intercept that) and attempt to de-serialise upon reloading*. Come to think of it, this still isn't really true hot reloading, since the code is fully replaced, but it's much simpler and the end result is largely the same. A hacky working prototype, probably with race conditions, is as simple as: startAppWithSavedState :: (Eq model, Read model, Show model) => Miso.App model action -> JSM ()
startAppWithSavedState app = do
loadedInitialState <- liftIO $ doesFileExist filePath >>= \case
False -> pure Nothing
True -> readMaybe <$> readFile filePath
startApp
app
{ model = fromMaybe app.model loadedInitialState
, update = \case
Nothing -> pure -- no-op
Just a -> \m -> do
m' <- first Just $ app.update a m
m' <# do
liftIO $ writeFile filePath $ show m'
pure Nothing
, subs = mapSub Just <$> app.subs
, view = fmap Just . app.view
, initialAction = Just app.initialAction
}
where
filePath = "miso-state" Various potential improvements:
* I'm hardly the first person to notice this. This Elm article talking about how much easier the whole problem is in a functional setting is over a decade old. Unfortunately, it's also presumably out-of-date since it mentions FRP. I don't know what support for hot reloading Elm has today. |
Hi, The nomenclature used around "hot reloading" vs. "live reloading" in the docs might need improvement. According to your description miso has live reloading via jsaddle yes. The code is altered, browser refreshed, and the state gets reset every time. I like your idea of persisting the state to disk on all changes for jsaddle users. I typically don't use jsaddle, so I haven't experimented too much with this approach. With the JS-backend you can save the state of the miso application to local storage on every event. Since jsaddle for development keeps the state on the server your example above would be the equivalent. Something like you're describing should exist, like a "Phoenix Live view", etc. would be nice. I'd prefer to dump the state as JSON for it to be readable, but in theory people can do whatever they want. You could try using That's how I'd try to go about doing it. |
That's a great point. Would you accept a PR which added a cleaned-up version of
Something based around genuine hot-swapping would be amazing to have. But I suspect it has its own caveats (e.g. I don't know how it handles data of a type whose definition has changed), and I suspect it's a lot more work anyway (the library repo is archived, for a start, which isn't a great sign). Given that I already have a feedback cycle well under a second with the example code above, I wouldn't personally be motivated to work on integrating |
Sure, there should be some prior art on local storage for reference as well |
I've realised I'm not actually sure what you mean by this. AFAICT using local storage via JSaddle does the same thing in both environments. |
My understanding is that w/ jsaddle the update function gets executed on the server, the client has an interpreter that modifies the DOM via a websocket protocol. Yes localStorage API stays the same. You could serialize the model to disk on the server, or to localStorage w/ jsaddle. It'd probably be better to do it on the server to avoid round trips. I thought you were going to mimic the localStorage API on the server and save the serialized model to disk on each call to update |
The sample app README mentions "hot reload". Perhaps these terms aren't all that standardised but my experience from the JavaScript ecosystem is that what we have in the examples, via
jsaddle-warp
'sdebug
function, where the browser auto-refreshes but state is reset, is called "live" reloading. Whereas "hot" reloading tends to mean actually swapping out code without restarting the program, as associated with languages like Lisp, Erlang and Smalltalk.As far as I can tell, Miso doesn't support this?
The text was updated successfully, but these errors were encountered: