Skip to content

Instantly share code, notes, and snippets.

@ndelitski
Created September 8, 2018 08:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ndelitski/0a526c14c28ba067f5668e000c19bfa6 to your computer and use it in GitHub Desktop.
Save ndelitski/0a526c14c28ba067f5668e000c19bfa6 to your computer and use it in GitHub Desktop.
import { matchRoutes } from 'react-router-config'
import { flatMap, values } from 'lodash'
import { createMemoryHistory } from 'history'
import { wrapRootEpic } from 'react-redux-epic'
import createStore from 'app/createStore'
import { featureTypes } from 'client/checkFeature'
import renderHtmlPage from './renderHtml'
import { normalizeAssets, orderAssets, normalizeStore } from './utils'
import renderRoute from './renderRoute'
export default ({ routes, frankTheme, muiTheme, reducer, epic }) => {
const ssrOnlyRoutes = routes.filter(route => route.ssr)
const isSSREnabled = process.env.SSR === 'true'
const isProduction = process.env.NODE_ENV === 'production'
const defaultFeatures = isProduction
? ''
: [featureTypes.layoutGrids].join(',')
const enabledClientFeatures = (
process.env.CLIENT_FEATURES || defaultFeatures
).split(/[,\s]/g)
const fontsUrls = frankTheme.fontFaces.map(({ resources }) => resources.woff)
function getWebpackData(stats) {
const assets = stats.assetsByChunkName
const publicPath = stats.publicPath
const manifest = {}
// if (process.NODE_ENV === 'production') {
// // eslint-disable-next-line import/no-dynamic-require,global-require
// manifest = require(path.join(
// __dirname,
// '..',
// 'src',
// 'server',
// 'manifest.json'
// ))
// } else {
// manifest = JSON.parse(
// fs.readFileSync(
// path.join(__dirname, '..', 'src', 'server', 'manifest.json')
// )
// )
// }
const jsAssets = orderAssets(
flatMap(values(assets).map(normalizeAssets))
.filter(file => file.match(/\.js$/))
.map(filePath => publicPath + filePath)
)
const prefetchScripts = [...jsAssets]
return {
jsAssets,
webpackManifest: manifest,
prefetchScripts,
}
}
function getWebpackProdData(stats) {
// const publicPath = __PUBLIC_PATH || '/assets/' // TODO
// eslint-disable-next-line global-require
// eslint-disable-next-line global-require
// const webpackManifest = require('./manifest.json')
const jsAssets = orderAssets(values(stats).map(({ js }) => js))
const prefetchScripts = [
...jsAssets,
// ...values(webpackManifest).map(filePath => publicPath + filePath),
]
return {
jsAssets,
webpackManifest: {},
prefetchScripts,
}
}
return ({ clientStats }) => (req, res, next) => {
const { url, httpClient, graphqlClient, user } = req
const isSSRUrl = !!matchRoutes(ssrOnlyRoutes, req.path).length
const memoryHistory = createMemoryHistory({ initialEntries: [url] })
const wrappedEpic = wrapRootEpic(epic)
const initialState = { auth: { user } }
const csrfToken = req.csrfToken()
const nonce = res.locals.nonce
if (isSSREnabled && isSSRUrl) {
const store = createStore({
reducer,
initialState,
history: memoryHistory,
epic: wrappedEpic,
dependencies: {
http: httpClient,
graphql: graphqlClient,
},
isServer: true,
})
renderRoute({
url,
frankTheme,
muiTheme,
store,
httpClient,
graphqlClient,
wrappedEpic,
})
.then(({ markup, helmet, criticalPathCSS, context: routerContext }) => {
if (routerContext.url) {
res.redirect(routerContext.url)
return
}
if (routerContext.status) {
res.status(routerContext.status)
}
const html = renderHtmlPage({
markup,
csrfToken,
inlineScriptNonce: nonce,
helmet,
criticalPathCSS,
fontsUrls,
store: normalizeStore(store),
features: enabledClientFeatures,
// TODO normalize clientStats to one format and make single function
...(isProduction
? getWebpackProdData(clientStats)
: getWebpackData(clientStats)),
})
res.send(html)
})
.catch(next)
} else {
const html = renderHtmlPage({
csrfToken,
inlineScriptNonce: nonce,
store: initialState,
fontsUrls,
features: enabledClientFeatures,
...(isProduction
? getWebpackProdData(clientStats)
: getWebpackData(clientStats)),
})
res.send(html)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment