Hyperapp: Parcel HMR doubles up event handlers.

Created on 22 Mar 2018  路  6Comments  路  Source: jorgebucaran/hyperapp

I tried using the Parcel packager, which does hot-reloading out of the box. And it seems to work great with hyperapp, aside from one thing. On each hot-reload, it seems to re-add event handlers, causing them to eventually be double/triple/quad called from a single click.

My view is basically just the example code:

import { h, View } from 'hyperapp'
import { state, State } from './state'
import { actions, Actions } from './actions'

export const view: View<State, Actions> = (state, actions) => (
  <div>
    <h1>{state.count}</h1>
    <button onclick={() => actions.down(1)}>-</button>
    <button onclick={() => actions.up(1)}>+</button>
  </div>
)

If I change any source code file, I see the changes in my browser immediately, but then one click triggers the action as many times as hot reloads have happened.

Given that addEventListener appears exactly once in the whole framework, I'm guessing there is a bug here wher ethe previous event handers are not being cleared before new ones are installed: https://github.com/hyperapp/hyperapp/blob/master/src/index.js#L170

Bug

Most helpful comment

Thank you, everyone, for your input and @Squeegy for reporting it. This bug is no more. 馃帀

Published as 1.2.3.

All 6 comments

@Squeegy Are you mounting the app to document.body?

I have a feeling that this is causing multiple calls to app, which has been discussed already in another thread: https://github.com/hyperapp/hyperapp/issues/533#issuecomment-355809201.

If I understand correctly.

The app is mounted, the view is renderered and events handlers are added.
After the HMR stuff, the app is mounted again, the hydration do its job by keeping the dom, then the view is rerendered and events handlers added again.

So, hydration should remove events handlers on reused node ?

@jorgebucaran I'm mounting it to #app with this index.html as the starting point for parcel, so I don't think thanks the problem.

<html>
  <head>
    <link rel="stylesheet" href="./styles/index.scss">
  </head>
  <body>
    <div id="app"></div>
    <script src="./src/index.tsx"></script>
  </body>
</html>

This has the potential to cause other issues. The problem isn't limited to event handlers, since you actually have an entire other _app_ still running. If external events were wired to call actions in the previous app and they are both using the same container, then they will both be fighting for control of that part of the DOM.

Your best options for now are probably either to use something like hyperapp-moisturize for real HMR (I have a POC example of this in another repo) or tell Parcel to just reload the page on change instead of using HMR.

Thank you, everyone, for your input and @Squeegy for reporting it. This bug is no more. 馃帀

Published as 1.2.3.

Was this page helpful?
0 / 5 - 0 ratings