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
Hot module replacement #11117
Hot module replacement #11117
Conversation
Amazing work @zodern! Thank you! Watch a short demo of this already working in one of my Meteor apps https://youtu.be/riroCNt9I98 I also have tested already in another one that is bigger and almost 3 years old and it is working there as well 😉 If you can please start using it and provide feedback here. I'm working closely with Zodern to get this released as soon as it is ready. |
Awesome. I just started testing it in a large react project and it works perfectly without any config or change. Without hot-reload it takes almost 6s from change to reload. With hot-reload it takes around 3.5s - 3.7s. Ill start using this for our dev env and give some feedback. Thanks @zodern |
HMR newbie here. Question - is this a development-only tool? How would this work in production on Galaxy? You redeploy your app and it doesn't need to refresh if HMR can handle all the changes/updates? |
AFAIK is only a dev tool. It updates the components in place without reloading all the page. Shouldnt do anything on production. |
I've tested it and it seems to be working perfectly! great work @zodern My only wish is that for the HMR to work also within packages. |
@afrokick The next beta will disable react fast refresh if it detects you are using an older version of React, which should fix the issue with the dev tools. If react fast refresh is disabled, it won't automatically update react components with HMR. It requires React 16.9 or newer. Apps that use an older version of React can use this in the file that mounts the root component: if (module.hot) {
module.hot.accept();
} When the file re-runs, |
Meteor 2.0-rc.0 is published. You can use it now updating your app: meteor update --release 2.0-rc.0 Or you can create a new app: meteor create my-app --react --release 2.0-rc.0 Please provide feedback here. |
Im having an issue where hmr is failing to reload a component with this error on the browser console. Its happening on the second update of the component, the first one works ok. hot-module-replacement.js?hash=b99aaee973e26637b168141edcb2337028f027a8:348 Uncaught TypeError: Cannot read property 'forEach' of undefined
at checkModuleAcceptsUpdate (hot-module-replacement.js?hash=b99aaee973e26637b168141edcb2337028f027a8:348)
at hot-module-replacement.js?hash=b99aaee973e26637b168141edcb2337028f027a8:361
at Set.forEach (<anonymous>)
at checkModuleAcceptsUpdate (hot-module-replacement.js?hash=b99aaee973e26637b168141edcb2337028f027a8:348)
at hot-module-replacement.js?hash=b99aaee973e26637b168141edcb2337028f027a8:471
at Array.forEach (<anonymous>)
at applyChangeset (hot-module-replacement.js?hash=b99aaee973e26637b168141edcb2337028f027a8:464)
at hot-module-replacement.js?hash=b99aaee973e26637b168141edcb2337028f027a8:183
at Array.every (<anonymous>)
at handleMessage (hot-module-replacement.js?hash=b99aaee973e26637b168141edcb2337028f027a8:182) This is the component import React from 'react';
import styled from 'styled-components';
import { withQuery } from 'meteor/cultofcoders:grapher-react';
import { assemblyMessagesLiveQuery } from '../../../../api/assemblyMessages/queries';
import Icon from '../Icon';
import ErrorBoundary from '../ErrorBoundary';
function ChatTab(props) {
return (
<ErrorBoundary content={ true }>
{
props.data.map((message) =>
<div key={ message._id }>
<h4>{ message.user.fullName }</h4>
<div>{ message.createdAt }</div>
<p>{ message.text }</p>
</div>
)
}
<MessageInput>
<textarea rows={ 4 }/>
<button>
<Icon
name="send"/>
</button>
</MessageInput>
</ErrorBoundary>
);
}
const MessageInput = styled.div`
position: absolute;
bottom: 0;
left: 0;
width: 100%;
padding: 16px 16px 80px;
min-height: 160px;
background-color: ${({ theme }) => theme.colors.bg};
textarea {
width: 100%;
color: ${({ theme }) => theme.colors.text};
padding: 8px 16px;
border-radius: 8px;
background-color: ${({ theme }) => theme.colors.bgLight};
}
button {
position: absolute;
bottom: 92px;
right: 24px;
color: ${({ theme }) => theme.colors.green};
border: none;
font-size: 24px;
background: none;
}
`;
export default withQuery(({ assemblyId }) => {
return assemblyMessagesLiveQuery.clone({
skip: 0,
limit: 200,
assemblyId
});
})(ChatTab); |
I have the same issue, after updating a hook (not a component). |
😢 |
@nicubarbaros could you please create a reproduction? React fast refresh accesses all of the exports from modules, and it looks like one of the exports is a reference to an iframe or something else that React Fast Refresh needs to be more careful with. |
Don't worry, we are going to continue working on HMR, fixing bugs and improving it as a whole. The merge means that we are ready to have it in a new Meteor final release. |
Further debugging this error:
I found out the |
Sorry, had no idea we were at 3 already 😄 |
Always moving! |
I tracked it down to these fellows that are creating the problem mentioned above. I will try to create a reproduction. |
I can confirm that the issue I reported previously is now fixed in final release. |
@filipenevola Is this still the right place to report issues with HMR? |
Hi @rijk no. It's not. You should open new issues then we can track them individually. Please provide reproductions, it's very hard to reproduce HMR problems when we don't have the code as modules can interact in different ways. Of course, if a reproduction is hard to be provided explain why 😉 Thanks! |
Hot module replacement (HMR) updates modified files in the app without having to reload the page or restart the app. This is usually faster (many times updating the page before the build has finished), and allows state to be preserved, though it is also less reliable. In situations where HMR is not supported, it uses hot code push to update the page.
HMR is only available for apps that use the
modules
package. It will probably not work correctly with apps that use globals (though globals from packages or npm dependencies are fine) since it uses import/require to detect which modules need to be re-evaluated.This pull request only enables it for app code in the modern bundle. After this PR is done I will work on supporting other client architectures and packages.
A partial list of situations it falls back to hot code push:
Current status: It works well with many apps, but there are still many details that need to be handled.
Use:
This PR is included in the Meteor 2 betas: #11206
Integration with View layers
React - Components are automatically configured to update using React Fast Refresh. Learn more about it in the React Native docs. React 16.9 or newer required. I haven't checked what happens with apps using an older version. The react runtime is included in production builds, though it is never evaluated. This should be fixed with tree shacking.
Svelte - Replace
svelte:compiler
withzodern:melte
.Hot API
This API is likely to completely change. It is currently based on the webpack hot api, with only the minimum implemented.
module.hot.accept()
- The module will be rerun whenever it or any of its dependencies are modifiedmodule.hot.decline()
- If the module or any of its dependencies are modified, hot code push will be used instead of HMR.module.hot.dispose((data) => {})
- Adds a callback to run before the module is replaced. Any state that should be preserved can be stored indata
. The data will be available when the module is rerun atmodule.hot.data
.module.hot.data
- If the module was reloaded, will have any data set by dispose handlers. If the file was not reloaded, or there were no dispose handlers, it will benull
.onRequire
is only available whenmodule.hot
is. Use it to run code before and after each module. Bothbefore
andafter
are optional. Anything returned by thebefore
function will be passed as the second argument to theafter
function.These should be wrapped by
Minifiers are able to remove the if statement for production, though none of the common minifiers for Meteor currently do.
How it works
hot-module-replacement
. The HMR server provides a websocket server (on the same port as the proxy) that apps can connect to.file.hmrAvailable()
. Even if it returns true, the file might not be updatable with HMR since all of the information needed isn't available at this step in the build process, but it does guaranteemodule.hot
is set. If a compiler changes its output depending on if HMR is available, it should use it in its cache key.Updates are applied with this process:
Remaining tasks
There are some larger details that should probably be discussed:
Hot API So far I have been copying webpack's api so I can focus on other aspects. Many other bundles have implemented their own api's, and to me some of them seem more intuitive. One of the next steps is to do more research and experiment with this, and I would appreciate any input from the community.
Integration with the meteor tool It currently uses an event emitter, which is a temporary solution. Originally I had considered creating an API for build plugins to handle HMR, but this part of HMR seems straight forward enough I am not sure if there is a reason for there to be more than one implementation. We also need to consider how packages will enable HMR for themselves, and for compilers to know if HMR is available for a unibuild. Allowing build plugins for HMR might help with both.Communication with app Currently it uses a websocket server on a separate port. The Meteor tool already has an http server for the proxy, which could be extended to include a websocket server. A related feature request is at meteor/meteor-feature-requests#354. I think this can wait until later since we should probably review all of the auto reload packages at the same time. With this PR we will have 4, and there are other PR's open adding an additional package.How much should be enabled by default Is there a reason to use
hot-module-reload
without React Fast Refresh?Before beta:
Before stable:
Nuances
topicLater:
install
's root object.install
to add necessary api's for HMRhot-module-replacement
, butmodule.hot
is available for everything.if (module.hot) { ... }
when minifying (requires Dead code elimination #11107)