@@ -26,15 +26,6 @@
> of a dev dependency as it automatically ensures it is not executed in
> production and the footprint is minimal.
-## 🔥 HOT-LABS 🔥
-
-Latest (4.5.0+) version of React-Hot-Loader could be quite 🔥!
-
-> RHL will patch React, replace React-DOM by React-🔥-DOM and work with fiber directly
-
-* (required) [use webpack plugin](https://github.com/gaearon/react-hot-loader#webpack-plugin) to let RHL patch React-DOM for you.
-* (alternative) [use react-🔥-dom](https://github.com/gaearon/react-hot-loader#react--dom) to use already patched React-DOM.
-
## Getting started
1. Add `react-hot-loader/babel` to your `.babelrc`:
@@ -50,19 +41,46 @@
```js
// App.js
-import { hot } from 'react-hot-loader/root'
-const App = () => <div>Hello World!</div>
-export default hot(App)
+import { hot } from 'react-hot-loader/root';
+const App = () => <div>Hello World!</div>;
+export default hot(App);
```
-3. Make sure `react-hot-loader` is required before `react`.
+3. Make sure `react-hot-loader` is required before `react` and `react-dom`:
* or `import 'react-hot-loader'` in your main file (before React)
-* or have at least one variable in the same file (babel/webpack plugin would import react-hot-loader then)
-* or prepend your webpack entry point with `react-hot-loader/patch`, which will `import 'react-hot-loader'`, and nothing more.
+* or prepend your webpack entry point with `react-hot-loader/patch`
+
+4. If you need hooks support, use React-🔥-Dom
+
+## React-🔥-Dom
+
+React-🔥-Dom ([hot-loader/react-dom](https://github.com/hot-loader/react-dom)) replaces the "react-dom" package of the same version, but with additional patches to support hot reloading.
+
+There are 2 ways to install it:
+
+* Use **yarn** name resolution, so `@hot-loader/react-dom` would be installed instead of `react-dom`
-Keep in mind - the same rule is applied to `react-dom`, as long as it would (since 16.8.6) import `react` internally.
-React-hot-loader, to prevent dependency cycles(#1209), caused by the code it injects, **should be imported first**.
+```
+yarn add react-dom@npm:@hot-loader/react-dom
+```
+
+* Use webpack **aliases**
+
+```
+yarn add @hot-loader/react-dom
+```
+
+```js
+// webpack.conf
+...
+resolve: {
+ alias: {
+ 'react-dom': '@hot-loader/react-dom'
+ }
+}
+...
+```
### Old API
@@ -75,9 +93,9 @@
It is almost the same, but you have to pass `module` inside `hot`.
```js
-import { hot } from 'react-hot-loader'
-const App = () => <div>Hello World!</div>
-export default hot(module)(App)
+import { hot } from 'react-hot-loader';
+const App = () => <div>Hello World!</div>;
+export default hot(module)(App);
```
3. [Run webpack with Hot Module Replacement](https://webpack.js.org/guides/hot-module-replacement/#enabling-hmr):
@@ -124,12 +142,12 @@
```js
// ./containers/App.js
-import React from 'react'
-import { hot } from 'react-hot-loader'
+import React from 'react';
+import { hot } from 'react-hot-loader';
-const App = () => <div>Hello World!</div>
+const App = () => <div>Hello World!</div>;
-export default hot(module)(App)
+export default hot(module)(App);
```
### Migrating from [create-react-app](https://github.com/facebookincubator/create-react-app) without ejecting
@@ -212,6 +230,41 @@
Hot reloading code is just one line in the beginning and one line at the end of
each module so you might not need source maps at all.
+### Linking
+
+If you are using `npm link` or `yarn link` for development purposes, there is a chance you will get error `Module not found: Error: Cannot resolve module 'react-hot-loader'` or the linked package is not hot reloaded.
+
+There are 2 ways to fix `Module not found`:
+
+* Use [`include` in loader configuration](https://github.com/gaearon/react-hot-boilerplate/blob/master/webpack.config.js#L22) to only opt-in your app's files to processing.
+* Alternatively if you are using webpack, override the module resolution in your config:
+
+```js
+{
+ resolve: {
+ alias: {
+ 'react-hot-loader': path.resolve(path.join(__dirname, './node_modules/react-hot-loader')),
+ }
+ }
+}
+```
+
+And to make your linked package to be hot reloaded, it will need to use the patched version of `react` and `react-dom`, if you're using webpack, add this options to the alias config
+
+```js
+{
+ resolve: {
+ alias: {
+ 'react-hot-loader': path.resolve(path.join(__dirname, './node_modules/react-hot-loader')),
+ // add these 2 lines below so linked package will reference the patched version of `react` and `react-dom`
+ 'react': path.resolve(path.join(__dirname, './node_modules/react')),
+ 'react-dom': path.resolve(path.join(__dirname, './node_modules/react-dom')),
+ // or point react-dom above to './node_modules/@hot-loader/react-dom' if you are using React-🔥-Dom
+ }
+ }
+}
+```
+
## Preact
React-hot-loader should work out of the box with `preact-compat`, but, in case of pure preact, you will need
@@ -220,10 +273,10 @@
* create configuration file (setupHotLoader.js)
```js
-import reactHotLoader from 'react-hot-loader'
-import preact from 'preact'
+import reactHotLoader from 'react-hot-loader';
+import preact from 'preact';
-reactHotLoader.preact(preact)
+reactHotLoader.preact(preact);
```
* dont forget to import it
@@ -249,8 +302,8 @@
```js
class MyComponent extends React.Component {
- onClick = () => this.setState() // COULD NOT UPDATE
- variable = 1 // this is ok
+ onClick = () => this.setState(); // COULD NOT UPDATE
+ variable = 1; // this is ok
render() {} // this is ok
}
```
@@ -271,38 +324,11 @@
},
],
},
-}
+};
```
Webpack plugin will also land a "hot" patch to react-dom, making React-Hot-Loader more compliant to [the principles](https://github.com/gaearon/react-hot-loader/issues/1118).
-## React-🔥-Dom
-
-Another way to make RHL more compliant is to use _our_ version of React-Dom - [hot-loader/react-dom](https://github.com/hot-loader/react-dom)
-
-It is the same React-Dom, with the same version, just with our patches already landed inside.
-
-There is 2 ways to install it:
-
-* Use **yarn** name resolution, so `@hot-loader/react-dom` would be installed instead of `react-dom`
-
-```
-yarn add react-dom@npm:@hot-loader/react-dom
-```
-
-* Use webpack **aliases**
-
-```js
-// webpack.conf
-...
-resolve: {
- alias: {
- 'react-dom': '@hot-loader/react-dom'
- }
-}
-...
-```
-
### Code Splitting
If you want to use Code Splitting + React Hot Loader, the simplest solution is to pick one of our compatible library:
@@ -316,23 +342,23 @@
```js
// AsyncHello.js
-import { asyncComponent } from 'react-async-component'
+import { asyncComponent } from 'react-async-component';
// asyncComponent could not `hot-reload` itself.
const AsyncHello = asyncComponent({
resolve: () => import('./Hello'),
-})
+});
-export default AsyncHello
+export default AsyncHello;
```
```js
// Hello.js
-import { hot } from 'react-hot-loader'
+import { hot } from 'react-hot-loader';
-const Hello = () => 'Hello'
+const Hello = () => 'Hello';
-export default hot(module)(Hello) // <-- module will reload itself
+export default hot(module)(Hello); // <-- module will reload itself
```
### Checking Element `type`s
@@ -341,28 +367,28 @@
reference types of elements won't work:
```js
-const element = <Component />
-console.log(element.type === Component) // false
+const element = <Component />;
+console.log(element.type === Component); // false
```
React Hot Loader exposes a function `areComponentsEqual` to make it possible:
```js
-import { areComponentsEqual } from 'react-hot-loader'
-const element = <Component />
-areComponentsEqual(element.type, Component) // true
+import { areComponentsEqual } from 'react-hot-loader';
+const element = <Component />;
+areComponentsEqual(element.type, Component); // true
```
Another way - compare "rendered" element type
```js
-const element = <Component />
-console.log(element.type === <Component />.type) // true
+const element = <Component />;
+console.log(element.type === <Component />.type); // true
// better - precache rendered type
-const element = <Component />
-const ComponentType = <Component />.type
-console.log(element.type === ComponentType) // true
+const element = <Component />;
+const ComponentType = <Component />.type;
+console.log(element.type === ComponentType); // true
```
But you might have to provide all required props. See [original issue](https://github.com/gaearon/react-hot-loader/issues/304).
@@ -373,8 +399,8 @@
> Not all components has a name. **In production displayName could not exists.**
```js
-const element = <Component />
-console.log(element.displayName === 'Component') // true
+const element = <Component />;
+console.log(element.displayName === 'Component'); // true
```
This is something we did not solve yet. Cold API could help keep original types.
@@ -387,7 +413,7 @@
new ExtractTextPlugin({
filename: 'styles/[name].[contenthash].css',
disable: NODE_ENV !== 'production',
-})
+});
```
#### Disabling a type change (❄️)
@@ -414,15 +440,14 @@
are not welcomed, and modules are not expected to change.
```js
-import { setConfig, cold } from 'react-hot-loader'
+import { setConfig, cold } from 'react-hot-loader';
setConfig({
- onComponentRegister: (type, name, file) =>
- file.indexOf('node_modules') > 0 && cold(type),
+ onComponentRegister: (type, name, file) => file.indexOf('node_modules') > 0 && cold(type),
// some components are not visible as top level variables,
// thus its not known where they were created
onComponentCreate: (type, name) => name.indexOf('styled') > 0 && cold(type),
-})
+});
```
! To be able to "cold" components from 'node_modules' you have to apply babel to node_modules, while this
@@ -448,13 +473,11 @@
* _cold_ components using hooks.
```js
-import { setConfig, cold } from 'react-hot-loader'
+import { setConfig, cold } from 'react-hot-loader';
setConfig({
onComponentCreate: (type, name) =>
- (String(type).indexOf('useState') > 0 ||
- String(type).indexOf('useEffect') > 0) &&
- cold(type),
-})
+ (String(type).indexOf('useState') > 0 || String(type).indexOf('useEffect') > 0) && cold(type),
+});
```
## API
@@ -490,11 +513,11 @@
**!!** Use `hot` only for module `exports`, not for module `imports`. **!!**
```js
-import { hot } from 'react-hot-loader/root'
+import { hot } from 'react-hot-loader/root';
-const App = () => 'Hello World!'
+const App = () => 'Hello World!';
-export default hot(App)
+export default hot(App);
```
Keep in mind - by importing `react-hot-loader/root` you are setting up a boundary for update event propagation.
@@ -518,11 +541,11 @@
only the second `(App)`. The "new" hot is using old API.
```js
-import { hot } from 'react-hot-loader'
+import { hot } from 'react-hot-loader';
-const App = () => 'Hello World!'
+const App = () => 'Hello World!';
-export default hot(module)(App)
+export default hot(module)(App);
```
### `AppContainer`
@@ -532,10 +555,10 @@
This low-level approach lets you make **hot **imports\_\_, not exports.
```js
-import React from 'react'
-import ReactDOM from 'react-dom'
-import { AppContainer } from 'react-hot-loader'
-import App from './containers/App'
+import React from 'react';
+import ReactDOM from 'react-dom';
+import { AppContainer } from 'react-hot-loader';
+import App from './containers/App';
const render = Component => {
ReactDOM.render(
@@ -543,10 +566,10 @@
<Component />
</AppContainer>,
document.getElementById('root'),
- )
-}
+ );
+};
-render(App)
+render(App);
// webpack Hot Module Replacement API
if (module.hot) {
@@ -554,10 +577,10 @@
// while `hot` would configure HMR for the CURRENT module
module.hot.accept('./containers/App', () => {
// if you are using harmony modules ({modules:false})
- render(App)
+ render(App);
// in all other cases - re-require App manually
- render(require('./containers/App'))
- })
+ render(require('./containers/App'));
+ });
}
```
@@ -566,11 +589,11 @@
Test if two components have the same type.
```js
-import { areComponentsEqual } from 'react-hot-loader'
-import Component1 from './Component1'
-import Component2 from './Component2'
+import { areComponentsEqual } from 'react-hot-loader';
+import Component1 from './Component1';
+import Component2 from './Component2';
-areComponentsEqual(Component1, Component2) // true or false
+areComponentsEqual(Component1, Component2); // true or false
```
### setConfig(config)
@@ -588,9 +611,9 @@
```js
// rhlConfig.js
-import { setConfig } from 'react-hot-loader'
+import { setConfig } from 'react-hot-loader';
-setConfig({ logLevel: 'debug' })
+setConfig({ logLevel: 'debug' });
```
**It is important** to set configuration before any other action will take a place
@@ -614,19 +637,19 @@
```js
// App.js
-import React from 'react'
+import React from 'react';
-const App = () => <div>Hello world!</div>
+const App = () => <div>Hello world!</div>;
-export default App
+export default App;
```
```js
// main.js
-import React from 'react'
-import ReactDOM from 'react-dom'
-import { AppContainer } from 'react-hot-loader'
-import App from './containers/App'
+import React from 'react';
+import ReactDOM from 'react-dom';
+import { AppContainer } from 'react-hot-loader';
+import App from './containers/App';
const render = Component => {
ReactDOM.render(
@@ -634,19 +657,19 @@
<Component />
</AppContainer>,
document.getElementById('root'),
- )
-}
+ );
+};
-render(App)
+render(App);
// webpack Hot Module Replacement API
if (module.hot) {
module.hot.accept('./containers/App', () => {
// if you are using harmony modules ({modules:false})
- render(App)
+ render(App);
// in all other cases - re-require App manually
- render(require('./containers/App'))
- })
+ render(require('./containers/App'));
+ });
}
```
@@ -654,21 +677,21 @@
```js
// App.js
-import React from 'react'
-import { hot } from 'react-hot-loader'
+import React from 'react';
+import { hot } from 'react-hot-loader';
-const App = () => <div>Hello world!</div>
+const App = () => <div>Hello world!</div>;
-export default hot(module)(App)
+export default hot(module)(App);
```
```js
// main.js
-import React from 'react'
-import ReactDOM from 'react-dom'
-import App from './containers/App'
+import React from 'react';
+import ReactDOM from 'react-dom';
+import App from './containers/App';
-ReactDOM.render(<App />, document.getElementById('root'))
+ReactDOM.render(<App />, document.getElementById('root'));
```
### Patch is optional
@@ -692,11 +715,11 @@
However - this option affects only SFC behavior, and any ClassComponent would boundary itself.
```js
-import { setConfig } from 'react-hot-loader'
-import ErrorBoundary from './ErrorBoundary'
+import { setConfig } from 'react-hot-loader';
+import ErrorBoundary from './ErrorBoundary';
// ErrorBoundary will be given error and errorInfo prop.
-setConfig({ errorReporter: ErrorBoundary })
+setConfig({ errorReporter: ErrorBoundary });
```
If `errorReporter` is not set - full screen error overlay would be shown.
@@ -711,10 +734,10 @@
```js
// to disable
-setConfig({ ErrorOverlay: () => null })
+setConfig({ ErrorOverlay: () => null });
// to change
-setConfig({ ErrorOverlay: MyErrorOverlay })
+setConfig({ ErrorOverlay: MyErrorOverlay });
```
The UX of existing overlay is a subject to change, and we are open to any proposals.
@@ -759,8 +782,8 @@
not working properly in your application.
```js
-import { setConfig } from 'react-hot-loader'
-setConfig({ logLevel: 'debug' })
+import { setConfig } from 'react-hot-loader';
+setConfig({ logLevel: 'debug' });
```
## Contributors