klazuka / elm-hot Goto Github PK
View Code? Open in Web Editor NEWHot module reloading for Elm
License: Other
Hot module reloading for Elm
License: Other
As in the title.
Currently if I change init
or my initial model, those changes will not get hot-loaded because hmr.js
remembers the last model state.
I made a proof of concept back in 0.18 of doing hot loading by storing init
and the list of messages instead of model
: https://gist.github.com/rtfeldman/f259128af7fea653876c34cca033ae68
When you change your code, including init
or the initial model
, it would replay the messages on top of the new code. This would also continue to work for any of the existing use cases, because the current model state can be derived by replaying messages on top of the initial model
.
Thoughts?
Based on the discussion we add on Slack yesterday about the feasibility of such an improvement, I'm taking the liberty of opening this issue to easily track progress as well as coordinate efforts should some benevolent soul try and take a shot at this.
Some relevant information from @klazuka :
It can definitely be fixed (PRs welcome). At the time, I just wanted to get something out the door, and I hadn’t yet seen changes to rtfeldman’s SPA example. So it seemed like a reasonable compromise. But now that that example is out there, it’s less tenable of a solution.
The core problem is that Browser.Navigation.Key is not plain-old data: it’s actually a function that closes over the Elm runtime’ssendToApp
function. So unlike all of the other data in your model, the navigation key cannot be reused in the new app. So we need to be able to find it in the old model and swap it out with the new app’s key.
My implementation just looks one level deep in your model. We could certainly crawl the model recursively to try to find all instances of the nav key and update them in the new app’s model.
Unless I'm mistaken, the relevant code should be around here : https://github.com/klazuka/elm-hot/blob/master/resources/hmr.js#L303-L325
Browser.document
and Browser.element
take over the <body>
element. But if the user provides a node
when calling init()
on their Elm module entry point from JS, we will register that DOM node as belonging to the instance. But we actually should ignore it (which is apparently what the Elm runtime does).
I've been experimenting with elm-optimize-level-2
in our Parcel build (a large part of what I do is testing performance impact of code changes, so it's useful to be able to combine hot reloading with an optimized-but-not-minified build so I can make a change and get a quick sense of whether things are faster or slower). Unfortunately there's a small conflict between elm-optimize-level-2
and elm-hot
; elm-hot
expects the exact string
var key = function() { key.a(onUrlChange(_Browser_getUrl())); };
in the output, but the output from elm-optimize-level-2
has
var key = function () { key.a(onUrlChange(_Browser_getUrl())); };
(with a space between function
and ()
). For now I have a little post-processing script that makes the necessary replacement, but would it make sense to use a whitespace-tolerant regex instead of an exact string match on this line?
Hello!
I'm using create-elm-app on a project, which is using elm-hot under the hood. Here are the versions involved:
➜ npm ls elm-hot
[email protected] /Users/projects/my-project
└─┬ [email protected]
└─┬ [email protected]
└── [email protected]
When changing some code in my IDE, the hot reload is not working and I can see this error in the console:
[elm-hot] Hot-swapping Main not possible: keypath state,a,b is invalid. Please report a bug.
with the stacktrace being:
__stack_frame_overlay_proxy_console__ | @ | index.js:2178
-- | -- | --
| hookedInit | @ | Main.elm:21480
| _Platform_initialize | @ | Main.elm:1877
| _Platform_initialize | @ | Main.elm:21534
| (anonymous) | @ | Main.elm:3991
| (anonymous) | @ | Main.elm:20
| swap | @ | Main.elm:21293
| webpackHotUpdate../src/Main.elm.scope._elm_hot_loader_init | @ | Main.elm:21560
| (anonymous) | @ | Main.elm:21578
| ./src/Main.elm | @ | Main.elm:21583
| __webpack_require__ | @ | bootstrap:785
| hotApply | @ | bootstrap:709
| (anonymous) | @ | bootstrap:363
| Promise.then (async) | |
| hotUpdateDownloaded | @ | bootstrap:362
| hotAddUpdateChunk | @ | bootstrap:338
| webpackHotUpdateCallback | @ | bootstrap:57
| (anonymous) | @ | main.f81156501911093…c61.hot-update.js:1
Do you have any idea where this could come from? Would a SSCCE help?
While trying to use elm-hot-webpack-loader I'm seeing this error
[elm-hot] Browser.Navigation.Key def not found. Version mismatch
The code seems to be looking for
var key = function() ...
https://github.com/klazuka/elm-hot/blob/master/src/inject.js#L22
If I compile my Elm module using elm make
I cannot find that in my generated code. https://paste.ee/p/hDuYB
Thanks
When the library gets used on top of a SharedWorker implemented as a worker program, the wrapping init function fails because document
does not exist in the context of the worker.
The failing line in my case is hmr.js#L174 but L170 is going to have the same problem.
Adding a simple guard if (typeof document !== 'undefined')
seems to solve the problem at least for me.
Hello!
I'm using create-elm-app on a project, which is using elm-hot under the hood. Here are the versions involved:
➜ npm ls elm-hot
[email protected] /Users/projects/my-project
└─┬ [email protected]
└─┬ [email protected]
└── [email protected]
When changing some code in my IDE, the hot reload is not working and I can see this error in the console:
[elm-hot] Hot-swapping Main not possible: keypath state,a,b is invalid. Please report a bug.
with the stacktrace being:
__stack_frame_overlay_proxy_console__ | @ | index.js:2178
-- | -- | --
| hookedInit | @ | Main.elm:21480
| _Platform_initialize | @ | Main.elm:1877
| _Platform_initialize | @ | Main.elm:21534
| (anonymous) | @ | Main.elm:3991
| (anonymous) | @ | Main.elm:20
| swap | @ | Main.elm:21293
| webpackHotUpdate../src/Main.elm.scope._elm_hot_loader_init | @ | Main.elm:21560
| (anonymous) | @ | Main.elm:21578
| ./src/Main.elm | @ | Main.elm:21583
| __webpack_require__ | @ | bootstrap:785
| hotApply | @ | bootstrap:709
| (anonymous) | @ | bootstrap:363
| Promise.then (async) | |
| hotUpdateDownloaded | @ | bootstrap:362
| hotAddUpdateChunk | @ | bootstrap:338
| webpackHotUpdateCallback | @ | bootstrap:57
| (anonymous) | @ | main.f81156501911093…c61.hot-update.js:1
Do you have any idea where this could come from? Would a SSCCE help?
I don't understand what this error means:
[elm-hot] Hot-swapping Main not possible: the location of the Browser.Navigation.Key in the model has changed.
would you mind helping me understand how to fix?
While using the Elm plugin for Parcel I've noticed that whenever the page I'm working on hot reloads, any scroll offset on the body gets reset. This is a problem as the time I spend scrolling back to where I was on a long page can add up.
I'm posting this issue here because, as I understand it, the Elm plugin for Parcel relies on elm-hot for hot reloading.
I am getting this error if I activate the hot reload using elm-live. It is unclear to me if the error is related to elm-live
implementation or to elm-hot
.
I commented to a related issue in elm-live here: wking-io/elm-live#211
This is the error:
elm.js:37126 Uncaught TypeError: Cannot read property 'hasOwnProperty' of undefined
at findNavKey (elm.js:37126)
at hookedInit (elm.js:37218)
at _Platform_initialize (elm.js:1978)
at _Platform_initialize (elm.js:37256)
at elm.js:4093
at elm.js:20
at Object.module.init (elm.js:36980)
at index-hot.html:29
Hi!
I'm using elm-hot with Webpack, using v1.0.2. Unfortunately, I added Browser.Navigation in my Main file, but now I can't start the webpack-dev-server anymore because of this:
Error: [elm-hot] Browser.Navigation.Key def not found. Version mismatch?
Do you have an idea of what to do? I'm correctly storing the Browser.Navigation.Key in the Model (but nested).
elm-hot
log the error message:
[elm-hot] Hot-swapping disabled for Main: could not find Browser.Navigation.Key in your model.
with Browser.application
and after a reloading:
...
[WDS] 100% - Compilation completed.
[WDS] App hot update...
[HMR] Checking for updates on the server...
Uncaught RangeError: Maximum call stack size exceeded
at hotAddUpdateChunk (main.js:979)
at webpackHotUpdateCallback (main.js:8)
at webpackHotUpdateCallback (main.js:9)
...
Compiled in DEBUG mode. Follow the advice at https://elm-lang.org/0.19.0/optimize for better performance and smaller assets.
[elm-hot] Hot-swapping module: Main
[elm-hot] Hot-swapping disabled for Main: could not find Browser.Navigation.Key in your model.
...
This is a minor request about adding a "verbose" flag to enable/disable the logging to the console by HMR.
I was testing the implementation of hot reload in elm-live (wking-io/elm-live#146 (comment)) and I have such "verbose" flag that I would also like to propagate to HMR so that the console can remain clean.
node -v
: v8.11.4
npm -v
: 6.3.0
npm ls create-elm-app -g
: [email protected]
Operating system: Ubuntu
Browser and version (if relevant): Version 69.0.3497.92 (Official Build) (64-bit)
Provide warning message about missing setup that create-elm-app requires and don't break application. According to elm documentation:
A navigation Key is needed to create navigation commands that change the URL. That includes pushUrl, replaceUrl, back, and forward.
It's confusing that application compiles successfully but then breaks in runtime as soon as you apply Browser.application to run it.
Application hangs in infinite loop, from quick debugging I find out it's in findNavKey function.
Modified Main.elm from create-elm-app
module Main exposing (..)
import Browser
import Browser.Navigation
import Html exposing (Html, text, div, h1, img)
import Html.Attributes exposing (src)
import Url
---- MODEL ----
type alias Model =
{}
init : () -> Url.Url -> Browser.Navigation.Key -> ( Model, Cmd Msg )
init flags url navKey =
( {}, Cmd.none )
---- UPDATE ----
type Msg
= NoOp
| LinkClicked Browser.UrlRequest
| UrlChnged Url.Url
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
( model, Cmd.none )
---- VIEW ----
view : Model -> Browser.Document Msg
view model =
{
title = ""
, body = [
div []
[ img [ src "/logo.svg" ] []
, h1 [] [ text "Your Elm App is working!" ]
]
]
}
---- PROGRAM ----
main : Program () Model Msg
main =
Browser.application
{ view = view
, init = init
, update = update
, subscriptions = always Sub.none
, onUrlChange = UrlChnged
, onUrlRequest = LinkClicked
}
This is causing trouble with elm-ui
when trying to fill the screen.
Hi there, I've been starting to use elm-hot to work on the 0.19 upgrade of my project by referencing your repo in my package.json.
Are there any major issue left prior to the release on npm that I should be aware of ? I am well aware that elm-hot is in its early stages still.
Anyway, thank you for the amazing work. The (very-limited) tests I did so far did work well enough !
Can this work with this model?
I have an application where I call init with no arguments. If I leave it like that, then the hmr script throws.
If I add {}
as the argument, it works.
// This throws
const app = Elm.Main.init();
// This works
const app = Elm.Main.init({});
I traced that back to
Line 172 in 3372608
if (originalInit) {
module.init = function (args) {
var elm;
var portSubscribes = {};
var portSends = {};
var domNode = args['node'] ? wrapDomNode(args['node']) : document.body;
The code there assumes that args already exists, and then checks whether there's a node or not.
I thought to open an issue instead of sending a drive-by PR.
One solution could be just more ternaries, or splitting it out to something named and nicer to debug.
var domNode = !args ? document.body : args['node'] ? wrapDomNode(args['node']) : document.body;
But the root question I suppose is whether "init without arguments means document.body".
I looked through the docs, and that seems to be the case, at least for the current Browser programs.
It seems that package.elm-lang.org also uses init
without args, and possibly more user code.
view-source:https://package.elm-lang.org/packages/elm/browser/latest/Browser#application
Now, running parcel
in watch mode (that starts elm-hot
) results in the following error being thrown "Could not determine Elm version".
1.1.0
works fine.
This parcel example can be used to see the error:
https://github.com/benthepoet/elm-parcel-example
littlestudent on Slack wrote that HMR is broken for him with Browser.element
HMR fails to show the new changes with this DOM:
<body>
<div id="root" class="fullHeight"></div>
</body>
but works with:
<body>
<div>
<div id="root" class="fullHeight"></div>
</div>
</body>
We have several pages in our application, the key is passed between the pages when you transition between them. Some pages store the key in e.g
{
page = FooPage { navigation: { key: <KEY>, ... } }
}
while another page stores it in:
{
page = BarPage { navKey: <KEY>, ... }
}
Elm-Hot fails to find the key when it wants to hot-reload. Our assumtion is that this is because the path cached in hmr.js
is no longer correct (instance.navKeyPath) and when it tries to look it up it fails giving the error:
keypath " + instance.navKeyPath + " is invalid. Please report a bug.
Could you look up the key again in the oldModel when it needs to reload?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.