2016-01-27 11:34:44 -08:00
|
|
|
import debug from 'debug';
|
2017-11-09 17:10:30 -08:00
|
|
|
import { renderToString } from 'react-dom/server';
|
|
|
|
import createMemoryHistory from 'history/createMemoryHistory';
|
|
|
|
import { NOT_FOUND } from 'redux-first-router';
|
|
|
|
import devtoolsEnhancer from 'remote-redux-devtools';
|
2016-10-29 00:46:45 +01:00
|
|
|
|
2017-11-09 17:10:30 -08:00
|
|
|
import {
|
|
|
|
errorThrowerMiddleware
|
|
|
|
} from '../utils/react.js';
|
|
|
|
import { createApp, provideStore, App } from '../../common/app';
|
|
|
|
import waitForEpics from '../../common/utils/wait-for-epics.js';
|
|
|
|
import { titleSelector } from '../../common/app/redux';
|
2015-06-29 09:50:25 -07:00
|
|
|
|
2016-01-27 11:34:44 -08:00
|
|
|
const log = debug('fcc:react-server');
|
2017-11-09 17:10:30 -08:00
|
|
|
const isDev = process.env.NODE_ENV !== 'production';
|
2015-07-01 15:14:10 -07:00
|
|
|
|
|
|
|
// add routes here as they slowly get reactified
|
|
|
|
// remove their individual controllers
|
2015-06-29 12:01:56 -07:00
|
|
|
const routes = [
|
2016-03-14 17:22:56 -07:00
|
|
|
'/challenges',
|
2016-04-18 18:58:29 -07:00
|
|
|
'/challenges/*',
|
2016-07-15 14:32:42 -07:00
|
|
|
'/map',
|
2016-07-19 16:36:34 -07:00
|
|
|
'/settings',
|
|
|
|
'/settings/*'
|
2015-10-19 23:16:56 -07:00
|
|
|
];
|
|
|
|
|
2015-12-22 19:28:07 -08:00
|
|
|
const devRoutes = [];
|
|
|
|
|
2017-12-07 16:13:19 -08:00
|
|
|
const middlewares = isDev ? [errorThrowerMiddleware] : [];
|
2015-06-29 12:01:56 -07:00
|
|
|
export default function reactSubRouter(app) {
|
2015-07-02 23:44:34 -07:00
|
|
|
var router = app.loopback.Router();
|
2015-06-29 09:50:25 -07:00
|
|
|
|
2016-06-17 12:35:10 -07:00
|
|
|
router.get('/videos', (req, res) => res.redirect('/map'));
|
|
|
|
router.get(
|
|
|
|
'/videos/:dashedName',
|
|
|
|
(req, res) => res.redirect(`/challenges/${req.params.dashedName}`)
|
|
|
|
);
|
|
|
|
|
2015-10-29 17:55:42 -07:00
|
|
|
// These routes are in production
|
|
|
|
routes.forEach((route) => {
|
|
|
|
router.get(route, serveReactApp);
|
|
|
|
});
|
2015-10-19 23:16:56 -07:00
|
|
|
|
2015-08-13 11:09:34 -07:00
|
|
|
if (process.env.NODE_ENV === 'development') {
|
2015-10-19 23:16:56 -07:00
|
|
|
devRoutes.forEach(function(route) {
|
2015-08-13 11:09:34 -07:00
|
|
|
router.get(route, serveReactApp);
|
|
|
|
});
|
|
|
|
}
|
2015-06-29 09:50:25 -07:00
|
|
|
|
2016-06-17 12:35:10 -07:00
|
|
|
app.use('/:lang', router);
|
2015-06-29 09:50:25 -07:00
|
|
|
|
|
|
|
function serveReactApp(req, res, next) {
|
2016-06-17 12:35:10 -07:00
|
|
|
const { lang } = req;
|
2016-01-27 11:34:44 -08:00
|
|
|
const serviceOptions = { req };
|
2016-03-14 17:22:56 -07:00
|
|
|
createApp({
|
|
|
|
serviceOptions,
|
2017-11-09 17:10:30 -08:00
|
|
|
middlewares,
|
|
|
|
enhancers: [
|
|
|
|
devtoolsEnhancer({ name: 'server' })
|
|
|
|
],
|
|
|
|
history: createMemoryHistory({ initialEntries: [ req.originalUrl ] }),
|
|
|
|
defaultStaet: { app: { lang } }
|
2016-01-27 11:34:44 -08:00
|
|
|
})
|
2017-11-09 17:10:30 -08:00
|
|
|
.filter(({
|
|
|
|
location: {
|
|
|
|
type,
|
|
|
|
kind,
|
|
|
|
pathname
|
|
|
|
} = {}
|
|
|
|
}) => {
|
|
|
|
if (kind === 'redirect') {
|
|
|
|
log('react found a redirect');
|
|
|
|
res.redirect(pathname);
|
|
|
|
return false;
|
2015-06-29 09:50:25 -07:00
|
|
|
}
|
2016-01-03 19:40:49 -08:00
|
|
|
|
2017-11-09 17:10:30 -08:00
|
|
|
if (type === NOT_FOUND) {
|
|
|
|
log(`react tried to find ${req.path} but got 404`);
|
|
|
|
next();
|
2016-06-09 16:02:51 -07:00
|
|
|
return false;
|
|
|
|
}
|
2017-11-09 17:10:30 -08:00
|
|
|
|
2016-06-09 16:02:51 -07:00
|
|
|
return true;
|
|
|
|
})
|
2017-11-09 17:10:30 -08:00
|
|
|
.flatMap(({ store, epic }) => {
|
|
|
|
return waitForEpics(epic)
|
|
|
|
.map(() => renderToString(
|
|
|
|
provideStore(App, store)
|
|
|
|
))
|
|
|
|
.map((markup) => ({ markup, store, epic }));
|
|
|
|
})
|
|
|
|
.do(({ markup, store, epic }) => {
|
2016-01-27 11:34:44 -08:00
|
|
|
log('react markup rendered, data fetched');
|
|
|
|
const state = store.getState();
|
2017-11-09 17:10:30 -08:00
|
|
|
const title = titleSelector(state);
|
2016-04-24 21:54:48 -07:00
|
|
|
epic.dispose();
|
2017-11-09 17:10:30 -08:00
|
|
|
res.expose(state, 'data', { isJSON: true });
|
2018-01-09 17:12:58 -08:00
|
|
|
// note(berks): we render without express-flash dumping our messages
|
|
|
|
// the app will query for these on load
|
|
|
|
res.renderWithoutFlash('layout-react', { markup, title });
|
2015-06-29 09:50:25 -07:00
|
|
|
})
|
2017-11-09 17:10:30 -08:00
|
|
|
.subscribe(() => log('html rendered and sent'), next);
|
2015-06-29 09:50:25 -07:00
|
|
|
}
|
2015-06-29 12:01:56 -07:00
|
|
|
}
|