Skip to content

Instantly share code, notes, and snippets.

@btholt
Last active April 26, 2018 16:24
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save btholt/01adb3cf9c114e5b46a0 to your computer and use it in GitHub Desktop.
Save btholt/01adb3cf9c114e5b46a0 to your computer and use it in GitHub Desktop.
react-router server-side rendering
require("babel-register")
var express = require('express')
var React = require('react')
var ReactDOMServer = require('react-dom/server')
var ReactRouter = require('react-router')
var match = ReactRouter.match
var RouterContext = ReactRouter.RouterContext
var _ = require('lodash')
var fs = require('fs')
var port = 5050
var baseTemplate = fs.readFileSync('./index.html')
var ClientApp = require('./js/ClientApp.jsx')
var routes = ClientApp.Routes
var app = express()
app.use('/public', express.static('./public'))
app.use((req, res) => {
// Note that req.url here should be the full URL path from
// the original request, including the query string.
match({ routes: ReactRouter.createRoutes(routes), location: req.url }, (error, redirectLocation, renderProps) => {
console.log(error, redirectLocation, renderProps)
if (error) {
res.status(500).send(error.message)
} else if (redirectLocation) {
res.redirect(302, redirectLocation.pathname + redirectLocation.search)
} else if (renderProps) {
// You can also check renderProps.components or renderProps.routes for
// your "not found" component or route respectively, and send a 404 as
// below, if you're using a catch-all route.
res.status(200).send(ReactDOMServer.renderToString(React.createElement(RouterContext,renderProps)))
} else {
res.status(404).send('Not found')
}
})
});
console.log('listening on ' + port)
app.listen(port)
const React = require('react')
const Landing = require('./Landing')
const Search = require('./Search')
const Layout = require('./Layout')
const Details = require('./Details')
const ReactRouter = require('react-router')
const data = require('../public/data')
const { Router, Route, hashHistory, IndexRoute } = ReactRouter
const Store = require('./Store')
const { store } = Store
const reactRedux = require('react-redux')
const { Provider } = reactRedux
const shows = data.shows || []
const MyRoutes = (props) => (
<Route path='/' component={Layout}>
<IndexRoute component={Landing} />
<Route path='/search' component={Search} shows={shows} />
<Route path='/details/:id' component={Details} onEnter={props.assignShow} />
</Route>
)
class App extends React.Component {
constructor (props) {
super(props)
this.assignShow = this.assignShow.bind(this)
}
assignShow (nextState, replace) {
const show = data.shows[nextState.params.id]
if (!show) {
return replace('/')
}
Object.assign(nextState.params, show)
return nextState
}
render () {
return (
<Provider store={store}>
<Router history={hashHistory}>
<MyRoutes assignShow={this.assignShow} />
</Router>
</Provider>
)
}
}
App.Routes = MyRoutes
module.exports = App
{
"name": "complete-intro-to-react",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "webpack",
"watch": "webpack --watch",
"test": "mocha --require test/helpers/setup.js",
"lint": "eslint --ignore-path .gitignore --cache ./",
"cover": "nyc --reporter=lcov --reporter=text --reporter=html --require babel-register --extension .jsx npm test"
},
"author": "",
"license": "ISC",
"dependencies": {
"express": "4.13.4",
"lodash": "4.6.1",
"react": "^0.14.7",
"react-dom": "^0.14.7",
"react-redux": "^4.4.0",
"react-router": "^2.0.0",
"redux": "^3.3.1"
},
"devDependencies": {
"babel-core": "^6.5.2",
"babel-loader": "^6.2.2",
"babel-preset-es2015": "^6.5.0",
"babel-preset-react": "^6.5.0",
"babel-register": "^6.5.2",
"chai": "^3.5.0",
"enzyme": "^2.0.0",
"eslint": "^2.2.0",
"eslint-config-standard": "^5.1.0",
"eslint-config-standard-jsx": "^1.1.1",
"eslint-config-standard-react": "^2.3.0",
"eslint-loader": "^1.3.0",
"eslint-plugin-promise": "^1.0.8",
"eslint-plugin-react": "^4.1.0",
"eslint-plugin-standard": "^1.3.2",
"jsdom": "^8.0.4",
"json-loader": "^0.5.4",
"mocha": "^2.4.5",
"nyc": "^6.0.0",
"react-addons-test-utils": "^0.14.7",
"sinon": "^1.17.3",
"webpack": "^1.12.13"
}
}
require("babel-register")
var express = require('express')
var React = require('react')
var ReactDOMServer = require('react-dom/server')
var ReactRouter = require('react-router')
var match = ReactRouter.match
var RouterContext = ReactRouter.RouterContext
var ReactRedux = require('react-redux')
var Provider = ReactRedux.Provider
var Layout = require('./js/Layout.jsx')
var Store = require('./js/Store.jsx')
var store = Store.store
var _ = require('lodash')
var fs = require('fs')
var port = 5050
var baseTemplate = fs.readFileSync('./index.html')
var template = _.template(baseTemplate)
var ClientApp = require('./js/ClientApp.jsx')
var routes = ClientApp.Routes
var app = express()
app.use('/public', express.static('./public'))
app.use((req, res) => {
// Note that req.url here should be the full URL path from
// the original request, including the query string.
match({ routes: routes, location: req.url }, (error, redirectLocation, renderProps) => {
console.log(error, redirectLocation, renderProps)
if (error) {
res.status(500).send(error.message)
} else if (redirectLocation) {
res.redirect(302, redirectLocation.pathname + redirectLocation.search)
} else if (renderProps) {
// You can also check renderProps.components or renderProps.routes for
// your "not found" component or route respectively, and send a 404 as
// below, if you're using a catch-all route.
var body = ReactDOMServer.renderToString(
React.createElement(Provider,{store},
React.createElement(Layout, {},
React.createElement(RouterContext,renderProps)
)
)
)
res.status(200).send(template({body}))
} else {
res.status(404).send('Not found')
}
})
});
console.log('listening on ' + port)
app.listen(port)
const React = require('react')
const Landing = require('./Landing')
const Search = require('./Search')
const Layout = require('./Layout')
const Details = require('./Details')
const ReactRouter = require('react-router')
const data = require('../public/data')
const { Router, Route, browserHistory, IndexRoute } = ReactRouter
const Store = require('./Store')
const { store } = Store
const reactRedux = require('react-redux')
const { Provider } = reactRedux
const shows = data.shows || []
const routes = [
<Route path='/' component={Landing} />,
<Route path='/search' component={Search} shows={shows} />,
<Route path='/details/:id' component={Details} />
]
class App extends React.Component {
constructor (props) {
super(props)
this.assignShow = this.assignShow.bind(this)
}
assignShow (nextState, replace) {
const show = data.shows[nextState.params.id]
if (!show) {
return replace('/')
}
Object.assign(nextState.params, show)
return nextState
}
render () {
return (
<Provider store={store}>
<Router history={browserHistory}>
<Route path='/' component={Layout}>
<IndexRoute component={Landing} />
<Route path='/search' component={Search} shows={shows} />
<Route path='/details/:id' component={Details} onEnter={this.assignShow} />
</Route>
</Router>
</Provider>
)
}
}
App.Routes = routes
module.exports = App
@YacheLee
Copy link

Thanks. You are so smart. I guess that you think ES6 codes in server side is not easy to develop.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment