spee.ch/server/render/src/handleShowRender.jsx

129 lines
3.7 KiB
React
Raw Normal View History

import React from 'react';
import { renderToString } from 'react-dom/server';
import { createStore, applyMiddleware } from 'redux';
import { Provider } from 'react-redux';
import { StaticRouter } from 'react-router-dom';
2018-04-18 21:11:25 +02:00
import renderFullPage from '../renderFullPage';
import createSagaMiddleware from 'redux-saga';
import { call } from 'redux-saga/effects';
2018-06-07 00:12:07 +02:00
import Helmet from 'react-helmet';
import * as httpContext from 'express-http-context';
2018-06-07 00:12:07 +02:00
2018-05-23 20:16:47 +02:00
import Reducers from '@reducers';
import GAListener from '@components/GAListener';
import App from '@app';
import Sagas from '@sagas';
import Actions from '@actions';
2018-11-01 15:58:12 +01:00
const createCanonicalLink = require('../../../utils/createCanonicalLink');
const getCanonicalUrlFromShow = show => {
const requestId = show.requestList[show.request.id];
const requestType = show.request.type;
if (!requestId || !requestType) {
return null;
}
2018-11-01 15:58:12 +01:00
switch (requestType) {
case 'ASSET_DETAILS':
const asset = show.assetList[requestId.key];
return createCanonicalLink({ asset: { ...asset.claimData, shortId: asset.shortId }});
2018-11-01 15:58:12 +01:00
case 'CHANNEL':
return createCanonicalLink({ channel: show.channelList[requestId.key] });
default:
return null;
}
};
const returnSagaWithParams = (saga, params) => {
return function * () {
yield call(saga, params);
};
};
2018-11-12 17:19:31 +01:00
module.exports = (req, res) => {
let context = {};
const {
action = false,
saga = false,
} = httpContext.get('routeData');
const runSaga = (action !== false && saga !== false);
const renderPage = (store) => {
// Workaround, remove when a solution for async httpContext exists
const showState = store.getState().show;
const assetKeys = Object.keys(showState.assetList);
if(assetKeys.length !== 0) {
res.claimId = showState.assetList[assetKeys[0]].claimId;
} else {
const channelKeys = Object.keys(showState.channelList);
if(channelKeys.length !== 0) {
res.claimId = showState.channelList[channelKeys[0]].longId;
res.isChannel = true;
}
}
// render component to a string
const html = renderToString(
<Provider store={store}>
<StaticRouter location={req.url} context={context}>
<GAListener>
<App />
</GAListener>
</StaticRouter>
</Provider>
);
// get head tags from helmet
const helmet = Helmet.renderStatic();
// check for a redirect
if (context.url) {
return res.redirect(301, context.url);
}
// get the initial state from our Redux store
const preloadedState = store.getState();
// send the rendered page back to the client
res.send(renderFullPage(helmet, html, preloadedState));
};
if (runSaga) {
// create and apply middleware
const sagaMiddleware = createSagaMiddleware();
const middleware = applyMiddleware(sagaMiddleware);
// create a new Redux store instance
const store = createStore(Reducers, middleware);
// create an action to handle the given url,
// and create a the saga needed to handle that action
const boundAction = action(req.params, req.url);
const boundSaga = returnSagaWithParams(saga, boundAction);
// run the saga middleware with the saga call
sagaMiddleware
.run(boundSaga)
.done
2018-11-01 15:58:12 +01:00
.then(() => {
// redirect if request does not use canonical url
const canonicalUrl = getCanonicalUrlFromShow(store.getState().show);
if (canonicalUrl && canonicalUrl !== req.originalUrl) {
console.log(`redirecting ${req.originalUrl} to ${canonicalUrl}`);
res.redirect(canonicalUrl);
}
return renderPage(store)
});
} else {
const store = createStore(Reducers);
renderPage(store);
}
};