Add webpack cold reloading

On changes to the react bundle
webpack will store the current redux state
in localStorage, waits (to allow the server to restart)
then refreshes the page. On page load, it checks if it
has state stored and loads it into the app.
This commit is contained in:
Berkeley Martinez
2016-03-14 17:22:56 -07:00
parent 6898d961bf
commit 4e12c45057
10 changed files with 114 additions and 83 deletions

View File

@@ -6,7 +6,7 @@ import { Router } from 'react-router';
import { routeReducer as routing, syncHistory } from 'react-router-redux';
import { createHistory } from 'history';
import app$ from '../common/app';
import createApp from '../common/app';
import provideStore from '../common/app/provide-store';
// client specific sagas
@@ -14,20 +14,26 @@ import sagas from './sagas';
// render to observable
import render from '../common/app/utils/render';
import {
isColdStored,
getColdStorage,
saveToColdStorage
} from './cold-reload';
Rx.config.longStackSupport = !!debug.enabled;
const log = debug('fcc:client');
const DOMContainer = document.getElementById('fcc');
const initialState = window.__fcc__.data;
const hotReloadTimeout = 5000;
const csrfToken = window.__fcc__.csrf.token;
const initialState = isColdStored() ?
getColdStorage() :
window.__fcc__.data;
initialState.app.csrfToken = csrfToken;
const serviceOptions = { xhrPath: '/services', context: { _csrf: csrfToken } };
Rx.config.longStackSupport = !!debug.enabled;
const history = createHistory();
const appLocation = history.createLocation(
location.pathname + location.search
);
const routingMiddleware = syncHistory(history);
const devTools = window.devToolsExtension ? window.devToolsExtension() : f => f;
@@ -35,37 +41,35 @@ const shouldRouterListenForReplays = !!window.devToolsExtension;
const clientSagaOptions = { doc: document };
// returns an observable
app$({
location: appLocation,
history,
serviceOptions,
initialState,
middlewares: [
routingMiddleware,
...sagas.map(saga => saga(clientSagaOptions))
],
reducers: { routing },
enhancers: [ devTools ]
})
.flatMap(({ props, store }) => {
// because of weirdness in react-routers match function
// we replace the wrapped returned in props with the first one
// we passed in. This might be fixed in react-router 2.0
props.history = history;
createApp({
history,
serviceOptions,
initialState,
middlewares: [
routingMiddleware,
...sagas.map(saga => saga(clientSagaOptions))
],
reducers: { routing },
enhancers: [ devTools ]
})
.doOnNext(({ store }) => {
if (shouldRouterListenForReplays && store) {
log('routing middleware listening for replays');
routingMiddleware.listenForReplays(store);
}
log('rendering');
return render(
provideStore(React.createElement(Router, props), store),
DOMContainer
);
if (module.hot && typeof module.hot.accept === 'function') {
module.hot.accept('../common/app', function() {
saveToColdStorage(store.getState());
setTimeout(() => window.location.reload(), hotReloadTimeout);
});
}
})
.doOnNext(() => log('rendering'))
.flatMap(({ props, store }) => render(
provideStore(React.createElement(Router, props), store),
DOMContainer
))
.subscribe(
() => debug('react rendered'),
err => { throw err; },