-
-
Save jmahc/cbe281d8e0dde863f57af49d262dcb28 to your computer and use it in GitHub Desktop.
Moderately-successful hot reloading for react-router v3
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Stripped down because you probably have your own setup for this sort of stuff already… | |
export default function configureStore() { | |
// Setup the Redux store, perhaps also using react-router-redux, | |
// or maybe not even using Redux at all… | |
// history is either browserHistory from react-router | |
// or some other history generation… | |
return { store, history }; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export default function hotReloadRoutes(routes, nextRoutes, keyDebug = []) { | |
/* eslint-disable no-console */ | |
if (!routes || typeof routes !== 'object') { | |
console.warn('No matching routes available to hot reload into…'); | |
return; | |
} | |
if (!nextRoutes || typeof nextRoutes !== 'object') { | |
console.warn('No matching new routes available to hot reload into…'); | |
return; | |
} | |
if (Array.isArray(routes)) { | |
if (!Array.isArray(nextRoutes)) { | |
console.warn( | |
'Old routes is an array but the next routes are not:', | |
keyDebug.join('.') | |
); | |
return; | |
} | |
const length = routes.length; | |
const nextRoutesLength = nextRoutes.length; | |
if (nextRoutesLength !== length) { | |
console.warn( | |
'Old routes is an array of', length, | |
'but the next routes are an array of ', nextRoutesLength, ':', | |
keyDebug.join('.') | |
); | |
return; | |
} | |
for (let index = 0; index < length; index++) { | |
const childRoute = routes[index]; | |
const nextChildRoute = routes[index]; | |
const newKeyDebug = keyDebug.slice(0); | |
const lastKeyDebugIndex = newKeyDebug.length - 1; | |
newKeyDebug[lastKeyDebugIndex] = `${newKeyDebug[lastKeyDebugIndex]}[${index}]`; | |
// Ignore array items without paths | |
if (!childRoute.path) { continue; } | |
// Warn if paths don't match up between arrays | |
if (childRoute.path !== nextChildRoute.path) { | |
console.warn( | |
'Old child route has path', childRoute.path, | |
'but the next child route has path ', nextChildRoute.path, ':', | |
newKeyDebug.join('.') | |
); | |
break; | |
} | |
hotReloadRoutes(childRoute, nextChildRoute, newKeyDebug); | |
} | |
return; | |
} | |
const keys = Object.keys(routes); | |
for (const key of keys) { | |
const nextSubRoutes = nextRoutes[key]; | |
const newKeyDebug = keyDebug.concat([key]); | |
if (key === 'component' && nextSubRoutes) { | |
// eslint-disable-next-line no-param-reassign | |
routes.component = nextSubRoutes; | |
} else { | |
const subRoutes = routes[key]; | |
// Ignore plain data… | |
if (typeof subRoutes !== 'object') { return; } | |
// Check for missing data… | |
if (!nextSubRoutes || typeof nextSubRoutes !== 'object') { | |
console.warn( | |
'No matching new routes available for subkey:', | |
newKeyDebug.join('.') | |
); | |
return; | |
} | |
// Recursion… | |
hotReloadRoutes(subRoutes, nextSubRoutes, newKeyDebug); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react'; | |
import { render } from 'react-dom'; | |
import configureStore from './configureStore'; | |
import routes from './routes'; | |
import Root from './Root'; | |
// Development only | |
import hotReloadRoutes from './hotReloadRoutes'; | |
const props = configureStore(); // { store, history } | |
render( | |
<AppContainer> | |
<Root {...props} routes={routes} /> | |
</AppContainer>, | |
document.getElementById('root') | |
); | |
if (module.hot) { | |
module.hot.accept([ | |
'./Root', | |
'./routes', | |
], () => { | |
/* eslint-disable global-require */ | |
const NextRoot = require('./Root').default; | |
const nextRoutes = require('./routes').default; | |
/* eslint-enable global-require */ | |
// Patch the existing routes object with hot-reloaded components | |
hotReloadRoutes(routes, nextRoutes); | |
// Re-render the Root component via the react-hot-loader container | |
render( | |
<AppContainer> | |
<NextRoot {...props} routes={routes} /> | |
</AppContainer>, | |
document.getElementById('root') | |
); | |
}); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* eslint-disable global-require */ | |
if (process.env.NODE_ENV === 'production') { | |
module.exports = require('./index.prod'); | |
} else { | |
module.exports = require('./index.dev'); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react'; | |
import { render } from 'react-dom'; | |
import configureStore from './configureStore'; | |
import routes from './routes'; | |
import Root from './Root'; | |
const props = configureStore(); // { store, history } | |
render( | |
<Root {...props} routes={routes} />, | |
document.getElementById('root') | |
); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { PropTypes } from 'react'; | |
import { Provider } from 'react-redux'; // Or something else, if you're not using Redux | |
import Router from 'react-router/lib/Router'; | |
const Root = ({ store, history, routes }) => ( | |
<Provider store={store} key="provider"> | |
<Router history={history} routes={routes} /> | |
</Provider> | |
); | |
Root.propTypes = { | |
store: PropTypes.object.isRequired, | |
history: PropTypes.object.isRequired, | |
routes: PropTypes.object.isRequired, | |
}; | |
export default Root; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export default { | |
// Insert routes config here… | |
// Anything imported/required here will trigger the custom hot reloading when they attempt to reload | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment