0

I have a simple Parcel.js 2.0 set up with a main.js file as the starting point:

import('./components/faqs/faqs.js').then(function(Faqs){

  Faqs.init()  

})

When running parcel watch - I have found that changes to the main.js file HMR as expected, but changes to the linked faqs.js within the init function do not, and require a page refresh.

If I take a synchronous approach such as:

import init from'./components/faqs/faqs.js'

init()  

Then HMR works as intended, refreshing with any changes to the faqs.js. Is this an expected behaviour of Parcel's HMR?

Michael Watson
  • 224
  • 3
  • 11

1 Answers1

1

I debugged this, and here's a quick description of what currently happens in Parcel HMR with this example:

  1. You load main.js the first time, and it dynamically imports and loads faqs.js.
  2. You make a change to faqs.js, parcel sends a websocket message to the browser, informing it that the bundle beginning with faqs.js needs to be re-loaded. The updated bundle code is downloaded and executed, including a new definition for the init() function. Any global side-effects in faqs.js will also be re-run. So far, so good.
  3. However, probably what you're expecting is that the .then callback from main.js that actually runs the init function also re-runs. This doesn't happen because parcel treats the different dynamic bundles independently.

IMO, this seems like a bit of a rough edge of the current implementation of HMR in Parcel2 - I'll file a bug with what I've found so that we can think about possibly improving this.

In the meantime, however, you can work around the problem yourself by providing a callback to module.hot.accept, which will be injected by parcel in development mode (see documentation). For example, you could add this to faqs.js:

// "module.hot" is injected by parcel in development mode.
// This check will ensure that this code _only_ runs in this context
// (e.g. it won't affect production)
if (module.hot) {
   // The callback provided to "module.hot.accept" will be run whenever
   // parcel sends a new version of `faqs.js` to the browser in development.
   module.hot.accept(() => {
      // Actually run the new version of your init function.
      init()
   })
}
Andrew Stegmaier
  • 3,429
  • 2
  • 14
  • 26
  • Thanks for the detailed response and the bug report, would you mind sharing a link to the bug report with me? I appreciate your snippet suggestion, however, async loading of the module through a promise still doesn't deliver changes of the updated faqs.js file. The same outcome arises as above. It works sync, just not through a promise. – Michael Watson Nov 03 '21 at 17:39
  • Ignore my previous statement, of course your snippet does indeed resolve this, I misunderstood what you meant for a moment. It's not an ideal solution but does certainly work for now! Thanks – Michael Watson Nov 03 '21 at 18:20
  • 1
    Glad it works! I haven't gotten around to filing the bug yet - I want to chew a bit on the desired behavior, taking into account your scenario (and others) before opening it. Here's a repo with a simple project that illustrates the solution: https://github.com/astegmaier/stackoverflow-parcel-hmr-dynamic-imports – Andrew Stegmaier Nov 03 '21 at 18:24