gaearon / gaearon/react-hot-loader
Enable every async "loader" to work with RHL
- Dominant language
- JavaScript
- Stars
- 12.2k
- Forks
- 775
- PR merge metrics
- No merged PRs in 30d
Description
RHL and HRM comes together, and HRM fails to reload data - RHL also could not work.
All modern loaders has some assumptions about how to detect HMR:
- imported-component - based on PureComponentUpdate (ie someone (RHL) force updated it)
- universal-component - based on componentWillRecieveProps (lots of false positive)
- loadable-component - just always loads component in dev mode ("deferred" loading is not a thing)
- react-loadable - no assumptions
Meanwhile - we could execute the same trick `loadable-component` uses - just import new file, it will `register` itself, and next RHL will perform an actual "update".
The idea behind is based on how "module system" works - when you are importing something, you are becoming a parent, for a module you did import. As a parent - you will get HRM events, you may react on.
I could see 2 ways
1. Add `module.accept` using babel plugin
```js
const Component = Loadable({
loader: () => import('./module')
});
^^^^^^^^^^^^^^^^^^^^^
// then be ready to reload all modules, with ReactComponents registered and used.
// not _all_ modules and _all_ imports, only those ones, who could work using RHL.register to update instance.
module.hot.accept(
''./module',
() => reactHotLoader.hasComponentsFrom('./module') && import('./module')
);
```
1.1 - we might use `statusHandler` instead of `accept` to observe, not to change the code. The same trick we are using in `hot` HOC.
2. Create a separated imported file, as `react-imported-component` does, then track all loaded files, and reload them on HRM.
The major benefit of this way - it creates __another__ module, and `accept` in that file will work in __parallel__, not affecting the "real code", ie the cases when you might have "accept" in another place. Probably this is not the case keeping in mind 1.1
```js
const Component = Loadable({
loader: () => hotRelodable('./module', import('./module'))
});
/////
# hot-relodable.js
// all the "imports" of project, extracted by plugin
const hotRelodables = {
'./module': () => import('./module')
};
const hotRelodable = (moduleName, promise) => {
hotRelodables[moduleName]();
return promise;
}
module.hot.accept(reloadAllLoadedRelodablesWhichAreComponents)
```
- Second way is a bit more hard to maintain, probably we should go with .1
- The only thing we need to impliment - internal tracking of factual usage of some component from some file.
- RHL version 1 did something similar, reloading everything by it's own, but _everything_. I hope that not accepting all possible changes, but only "component-reloading" ones could do things better.
CC #953
Contributor guide
Research direction
Start by reading the existing `hot` HOC HMR handling and the async-loader approaches named in the issue, including `loadable-component` and `react-imported-component`. Compare the proposed Babel `module.hot.accept` approach with the separate tracking module, then define which approach can track component usage and reload only affected components; the issue does not name tests or implementation files.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, react
- Domain
- frontend, tooling
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100