Skip to content

Commit

Permalink
Write out route components as ES6 classes for hot reloading
Browse files Browse the repository at this point in the history
React-Router route components can't be functional components for hot
reloading to work consistently with react-hot-loader-beta6... weird.
  • Loading branch information
KyleAMathews committed Nov 1, 2016
1 parent eefeb48 commit 6069610
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 18 deletions.
1 change: 1 addition & 0 deletions lib/intermediate-representation-dir/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import ReactDOM from 'react-dom'
import { AppContainer as HotContainer } from 'react-hot-loader'

const rootElement = document.getElementById(`react-mount`)

let Root = require('./root')
if (Root.default) { Root = Root.default }

Expand Down
66 changes: 48 additions & 18 deletions lib/utils/query-runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import glob from 'glob'
import { pagesDB, siteDB, programDB } from './globals'
import { layoutComponentChunkName, pathChunkName } from './js-chunk-names'

const pascalCase = _.flow(_.camelCase, _.upperFirst)

const hashStr = function (str) {
let hash = 5381,
i = str.length
Expand Down Expand Up @@ -41,16 +43,7 @@ const writeChildRoutes = () => {
return (`
{
${pathStr}
component: (props) => {
let Component = require('${page.component}')
if (Component.default) {
Component = Component.default
}
const data = require('./json/${page.resultHash}.json')
return (
<Component {...props} {...data} />
)
},
component: ${page.internalComponentName},
},
`)
}
Expand All @@ -77,7 +70,7 @@ const writeChildRoutes = () => {
Component = Component.default
}
require.ensure([], (require) => {
const data = require('./json/${page.resultHash}.json')
const data = require('./json/${page.jsonName}')
cb(null, () => <Component {...nextState} {...data} />)
}, '${pathName}')
}, '${layoutName}')
Expand Down Expand Up @@ -167,9 +160,44 @@ const writeChildRoutes = () => {
// Close out object.
rootRoute += `]}`
splitRootRoute += `]}`
const componentsStr = [...pagesDB().values()].map((page) => {
return (
`class ${page.internalComponentName} extends React.Component {
render () {
let Component = require('${page.component}')
if (Component.default) {
Component = Component.default
}
const data = require('./json/${page.jsonName}')
return <Component {...this.props} {...data} />
}
}`)
}).join("\n")

childRoutes = `
import React from 'react'
/**
* Warning from React Router, caused by react-hot-loader.
* The warning can be safely ignored, so filter it from the console.
* Otherwise you'll see it every time something changes.
* See https://github.com/gaearon/react-hot-loader/issues/298
*/
if (module.hot) {
const isString = require('lodash/isString')
const orgError = console.error;
console.error = (...args) => {
if (args && args.length === 1 && isString(args[0]) && args[0].indexOf('You cannot change <Router routes>;') > -1) {
// React route changed
} else {
// Log the error as normally
orgError.apply(console, args);
}
};
}
${componentsStr}
const rootRoute = ${rootRoute}
module.exports = rootRoute`
splitChildRoutes = `
Expand Down Expand Up @@ -283,20 +311,22 @@ const q = queue(({ file, graphql, directory }, callback) => {
// Combine the result with the pathInfo.
const clonedResult = { ...result }
result.pathContext = pathInfo
const resultHash = hashStr(JSON.stringify(clonedResult))

// Add result to page object.
const page = pagesDB().get(pathInfo.path)
page.resultHash = resultHash
let jsonName = `${_.kebabCase(pathInfo.path)}.json`
let internalComponentName = `Component${pascalCase(pathInfo.path)}`
if (jsonName === `.json`) {
jsonName = `index.json`
internalComponentName = 'ComponentIndex'
}
page.jsonName = jsonName
page.internalComponentName = internalComponentName
pagesDB(pagesDB().set(page.path, page))

// Save result to file.
const resultJSON = JSON.stringify(clonedResult, null, 4)
let fileName = `${_.kebabCase(pathInfo.path)}.js`
if (fileName === `.js`) {
fileName = `index.js`
}
fs.writeFileSync(`${directory}/.intermediate-representation/json/${resultHash}.json`, resultJSON)
fs.writeFileSync(`${directory}/.intermediate-representation/json/${jsonName}`, resultJSON)

return null
})
Expand Down

0 comments on commit 6069610

Please sign in to comment.