Meteor 2.0 Beta with Hot Module Replacement (HMR)

The first Meteor 2.0 betas are now available with hot module replacement (HMR).

Hot module replacement updates the app while it is running, resulting in a better developer experience. It can apply updates to the client without reloading the page, most of the time completing before the rebuild has finished.

To try it, run these commands:

meteor update --release METEOR@2.0-beta.2
meteor add hot-module-replacement

HMR is only used in development, and doesn’t affect production builds.

HMR is currently enabled for app code in the modern client. Support for other client architectures and for packages will be implemented later. If a change can not be applied with HMR, it falls back to hot code push.

How it works

When an app depends on the hot-module-replacement package, a HMR server is started in the meteor-tool. This provides a websocket server the app connects to to receive updates.

During a build, Meteor compares the current build with the previous build to identify any modified modules. It then immediately sends those to the app, even though the build is still in progress.

In the app, you can use the hot api to configure which modules are replaceable:

if (module.hot) {
  module.hot.accept();
}

If a module accepts updates, it applies to updates to itself and any modules it imports.

When a module is modified, we run dispose functions so it can remove any timers, dom elements, or do anything else necessary for the module to no longer affect the app.

const interval = setInterval(doWork, 2000);
if (module.hot) {
  module.hot.dispose(() => {
    clearInterval(interval);
  });
}

When a module is modified, we first check if it accepts the updates. If not, we look at the modules that import it, and so on until all paths lead to a module that accepts the updates. If it is accepted, we call the dispose functions on the modified module, the modules that accept the update, and the modules between those.

Then, we re-run the modules that accept the update, their dependencies that were disposed, and the updated modules if they are still imported by the app.

After the build is finished, hot code push is used if a change was not accepted or there were any changes that are not possible to update with HMR.

Integrations

Most of the time you don’t need to decide which modules accept updates or write your own dispose handlers. These integrations can handle it for your app.

React - Changes to react components are automatically handled by React Fast Refresh. Learn more in the React Native docs.

Svelte - replace svelte:compiler with zodern:melte.

PureAdmin - When a module is disposed, PureAdmin automatically removes any pages and menu items the module had added. You will still need to add module.hot.accept() to the file or to a file that imports it for it to be updated with HMR.

We’ve been using HMR for a few apps, and it has been working well, though there are still many small details that need to be handled. We would appreciate any feedback on how reliable it works, and any issues with updating files that use Meteor’s core packages.

Learn more in the PR.

Also, I would like to thank e-Potek and @florianbienefelt for funding the initial implementation.

34 Likes

Great work @zodern. Thank you!

Meteor 2.0 is coming with many cool features and updates! HMR is one of them :slight_smile:

We are waiting your feedback!

9 Likes

Dammit just send out the newsletter few hours before this! :rofl:

Looking forward to give it a try after Meteor Impact.

6 Likes

I have been testing the beta version and I must say I love the HMR, it works pretty well. can’t wait for the final release.

5 Likes

Check out Zodern’s talk at Meteor Impact for more on HMR:

4 Likes

Does this/will this support the Vue integration? It had its own HMR solution that never worked with me

1 Like

Love this! I tested in my app, it worked perfectly when using it in a smaller Typescript component. When changing its parent (JSX) component I got this console message:

Some changes cannot be applied with HMR. Using hot code push.

And it triggered a full refresh (even though I saw the update on the screen already before the refresh). Is there a way to debug this behaviour, or documentation of conditions that block HMR?

I’m looking into this. Hope to release this with Vue 3 integration

3 Likes

So for HMR to work, do we need to have

if (module.hot) {
  module.hot.accept();
}

or does it work by default.

For files with React components, or svelte files, it will decide for you which modules accept updates. Since updates bubble up, this also applies to any files only imported by components.

For other files you will have to add that code to accept an update. You should preferably accept updates in modules that do not have exports, or that have exports you don’t want to update since we only rerun modules between the ones that were modified and the ones that accept updates. Let me know if this doesn’t make sense. I am trying to find a simple way to explain it.

1 Like

Sounds great. Is it accurate to think of this essentially as an alternative to snowpack?

For Svelte, does zodern:melte also essentially replace svelte-meteor-data with it’s $m tracker function? I guess it doesn’t have cursor support so you’d need to have a .fetch() on all cursors. Anything else I’m missing? @rdb, curious to hear your take.

Modifying Svelte to accept an $m syntax looks like a convenient alternative approach that obviates the need for rdb:svelte-meteor-data. I have thought about an approach like this but have in my library so far decided to avoid requiring modifications to Svelte.

Thank you @zodern just got HMR into Level Up Tutorials and it totally rules.

8 Likes

I’ve made the update on a fairly big project with react, and it’s just amazing !
Thanks @zodern, you’ll save us ton of time.

3 Likes

So far my experience has been a mix. Some time it works as intended, other time I have seen the HMR happen only to be followed by Hot Code Push. But I’m sure that is going go improve as things go forward.

Really worked fine at first. The only problem was React Dev Tools not working while hot-module-replacement package was active. Yesterday I noticed it was doing Hot Code Push instead of HMR and now it even breaks the Hot Code Push.

This is seriously awesome!!!

Is Vue HMR also going to be supported?

I don’t understand this feature, however I’m worried for the future of Meteor if it incorporates a non-standard api with module. Based on the article you provided it is for development only, however I don’t think I would like to write source code that is only for development builds – in this case I would presumably delete the source code that was HMR-related in order to produce a production build?

Could you belay my fears, or else point me towards a tool that I should work with?

Ok, as you don’t bundle your code editor into your production code bundle, so you don’t bundle anything related to HMR into your production code. This is a development tool, nothing related to your production code content.
Your source (development) code is not the same as your production code. Example: if you add an NPM library with 1GB of readme files, that will not go into your production. I don’t think there is anything to be worried about.

1 Like

Yep, I’m loving it too. I was trying it on a branch for a few days, and when I went back to a branch without it, I couldn’t believe how slow it was waiting for the full cycle. I’m sold and sitting on 2.0 Beta now, for better or worse :slight_smile:

6 Likes