UNPKG

react-webpack-node

Version:

A simple Node.js app using Express 4 with Webpack, React, alt, ImmutableJS

103 lines (97 loc) 3.71 kB
import axios from 'axios'; import React from 'react'; import { renderToString } from 'react-dom/server'; import { createMemoryHistory, match, RouterContext } from 'react-router'; import { Provider } from 'react-redux'; import createRoutes from 'routes'; import configureStore from 'store/configureStore'; import preRenderMiddleware from 'middlewares/preRenderMiddleware'; import header from 'components/Meta'; const clientConfig = { host: process.env.HOSTNAME || 'localhost', port: process.env.PORT || '3000' }; // configure baseURL for axios requests (for serverside API calls) axios.defaults.baseURL = `http://${clientConfig.host}:${clientConfig.port}`; /* * Export render function to be used in server/config/routes.js * We grab the state passed in from the server and the req object from Express/Koa * and pass it into the Router.run function. */ export default function render(req, res) { const authenticated = req.isAuthenticated(); const history = createMemoryHistory(); const store = configureStore({ user: { authenticated, isWaiting: false, message: '', isLogin: true } }, history); const routes = createRoutes(store); /* * From the react-router docs: * * This function is to be used for server-side rendering. It matches a set of routes to * a location, without rendering, and calls a callback(err, redirect, props) * when it's done. * * The function will create a `history` for you, passing additional `options` to create it. * These options can include `basename` to control the base name for URLs, as well as the pair * of `parseQueryString` and `stringifyQuery` to control query string parsing and serializing. * You can also pass in an already instantiated `history` object, which can be constructured * however you like. * * The three arguments to the callback function you pass to `match` are: * - err: A javascript Error object if an error occured, `undefined` otherwise. * - redirect: A `Location` object if the route is a redirect, `undefined` otherwise * - props: The props you should pass to the routing context if the route matched, * `undefined` otherwise. * If all three parameters are `undefined`, this means that there was no route found matching the * given location. */ match({routes, location: req.url}, (err, redirect, props) => { if (err) { res.status(500).json(err); } else if (redirect) { res.redirect(302, redirect.pathname + redirect.search); } else if (props) { // This method waits for all render component // promises to resolve before returning to browser preRenderMiddleware( store.dispatch, props.components, props.params ) .then(() => { const initialState = store.getState(); const componentHTML = renderToString( <Provider store={store}> <RouterContext {...props} /> </Provider> ); res.status(200).send(` <!doctype html> <html ${header.htmlAttributes.toString()}> <head> ${header.title.toString()} ${header.meta.toString()} ${header.link.toString()} </head> <body> <div id="app">${componentHTML}</div> <script>window.__INITIAL_STATE__ = ${JSON.stringify(initialState)};</script> <script type="text/javascript" charset="utf-8" src="/assets/app.js"></script> </body> </html> `); }) .catch((err) => { res.status(500).json(err); }); } else { res.sendStatus(404); } }); }