-
Notifications
You must be signed in to change notification settings - Fork 435
Investigate the ability to work with Redux hot reload #1097
Comments
The scope is actually broader than just Redux — it can apply at anything made with React (maybe even Exim, although not sure about this one). Here's a few approaches: 1. NaiveWhen a JS file changes, reload the javascript files instead of refreshing the page. With this, we'll also want to flush the local module cache. The app modules themselves (probably only In case of React, that would mean wrapping every component with The following changes will be required:
And here's an example of what import ReactDOM from 'react-dom';
import React from 'react';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import counterApp from './reducers';
import App from 'components/App';
import createProxy from 'react-proxy';
import deepForceUpdate from 'react-deep-force-update';
if (!window.store) {
window.store = createStore(counterApp, 0);
} else {
window.store.replaceReducer(counterApp);
}
var Root = React.createClass({
render() {
return <Provider store={window.store}>
<App />
</Provider>
}
});
var first;
if (!window.proxy) {
window.proxy = createProxy(Root);
first = true;
} else {
window.proxy.update(Root);
}
var Proxy = window.proxy.get();
setTimeout(function() {
if (first) {
window.rd = ReactDOM.render(
<Proxy />,
document.querySelector('#app')
);
} else {
deepForceUpdate(rd);
}
}, 250); 2. A better NaiveTargeting React specifically, it can be seen that wrapping into LiveReactload, a live React reload for Browserfy is using a custom react transform plugin to do that, for example — https://github.com/milankinen/livereactload/blob/master/src/babel-transform/main.js The following changes will be required:
And here's an example of what import ReactDOM from 'react-dom';
import React from 'react';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import counterApp from './reducers';
import App from 'components/App';
if (!window.store) {
window.store = createStore(counterApp, 0);
} else {
window.store.replaceReducer(counterApp);
}
var Root = React.createClass({
render() {
return <Provider store={window.store}>
<App />
</Provider>
}
});
setTimeout(function() {
if (window.rd) return;
window.rd = ReactDOM.render(
<Root />,
document.querySelector('#app')
);
}, 250); 3. Hot Module Replacement (HMR) APIA more advanced solution could be to implement Webpack's Hot Module Replacement API It could allow to, for example, pass that state between old and new version of a module without using The following changes will be required:
On the pro's side, it allows for more flexibility in regards to replacements. The API, however, has 11 entry points and could very well complicate deppack and And here's an example of what import ReactDOM from 'react-dom';
import React from 'react';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import counterApp from './reducers';
import App from 'components/App';
var store = createStore(counterApp, 0);
// this, instead of window.store + checks
if (module.hot) {
module.hot.accept('./reducers', function() {
counterApp = require('./reducers');
store.replaceReducer(counterApp);
});
}
var Root = React.createClass({
render() {
return <Provider store={store}>
<App />
</Provider>
}
});
setTimeout(function() {
ReactDOM.render(
<Root />,
document.querySelector('#app')
);
}, 250); ConclusionThese can be seen as gradual "levels" of live JS reloading, not as totally different approaches. No.1 and no.2 are more or less easy to implement right here, right now and provide an easier time developing React apps without reloads (there could be some limitations as to what React Proxy can't handle as well as there could be sporadic, app-dependent issue related to state, in which case a reload will be required). Then, with that baseline already established, at some later point, we could evaluate exactly how easy/hard will it be to bring HMR to Brunch, to allow for more fine-grained control of module replacements and to avoid storing state globally. cc @paulmillr |
@goshakkk You wrote a really good summary of our options going forward. I was wondering though, should the discussion be here in the core brunch repo or should it be in one of the React-based skeletons? |
@adrianmc core seems like a better fit, if only because the changes are required to core itself/other plugins, and also because there are at least 3 official react-based skeletons (react, exim, redux) |
those steps are needed in any case. let's start, I guess |
Created a sample React app with Brunch to showcase the adopted react-transform babel plugin that automatically wraps React components into proxies — https://github.com/goshakkk/brunch-livejs-reload-stage2 built on top of https://github.com/brunch/react-livejs initialize.js looks like this now: import ReactDOM from 'react-dom';
import React from 'react';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import counterApp from './reducers';
import App from 'components/App';
// detect if we're loading for the first time or reloading
if (!window.store) {
window.store = createStore(counterApp, 0);
} else {
window.store.replaceReducer(counterApp);
}
document.addEventListener('DOMContentLoaded', () => {
ReactDOM.render(
<Provider store={window.store}>
<App />
</Provider>,
document.querySelector('#app')
);
}); which is definitely an improvement compared to something like this: import ReactDOM from 'react-dom';
import React from 'react';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import counterApp from './reducers';
import App from 'components/App';
import {createProxy} from 'react-proxy';
import deepForceUpdate from 'react-deep-force-update';
if (!window.store) {
window.store = createStore(counterApp, 0);
} else {
window.store.replaceReducer(counterApp);
}
var Root = React.createClass({
render() {
return <Provider store={window.store}>
<App />
</Provider>
}
});
var first;
if (!window.proxy) {
window.proxy = createProxy(Root);
first = true;
} else {
window.proxy.update(Root);
}
var Proxy = window.proxy.get();
setTimeout(function() {
if (first) {
window.rd = ReactDOM.render(
<Proxy />,
document.querySelector('#app')
);
} else {
deepForceUpdate(rd);
}
}, 250); The next thing to research/implement is probably Hot Module Replacement API. |
Now that we have https://github.com/brunch/hmr-brunch, can you close this? @paulmillr |
No description provided.
The text was updated successfully, but these errors were encountered: