gridiron-example
Version:
Example webpack project for gridiron and related components. Showcases what can be done with gridiron.
158 lines (140 loc) • 7.63 kB
JavaScript
import Promise from 'promise'
import Immutable from 'immutable'
import Router from 'router'
import serveFile from 'serve-file'
import serveStatic from 'serve-static'
import path from 'path'
import React from 'react'
import reactStamp from 'react-stamp'
import { renderToString, renderToStaticMarkup } from 'react-dom/server'
import { createMemoryHistory, match, RouterContext } from 'react-router'
import { Provider } from 'react-redux'
import { syncHistoryWithStore } from 'react-router-redux'
import cookieParser from 'cookie-parser'
import cookie from 'react-cookie'
import { serialize, createInitialState } from 'fire-hydrant'
import { getThemeForUrl } from '../context/theme'
import { defaultTheme, getTheme } from '../context'
import { server, packageName, packageKey, faviconUrl, log, IS_HOT, IS_DEV, noop, resolveRoot, initialState } from '../../config'
import { deauthorized, hydrateIdentity } from '../redux/actions/identity'
import minify from '../services/minify'
import logging from '../services/logging'
import { removeLegacyCookies } from '../services/persistence'
import configureStore from '../redux/store/configureStore'
import routes from '../app/routes'
import util from 'util'
import { reactStyles, serializeStyles, RoutingError } from 'universal-styles'
import ErrorPage from '../components/ErrorPage'
import postcss from 'postcss'
import postcssImport from 'postcss-import'
import postcssUrl from 'postcss-url'
import postcssCssnext from 'postcss-cssnext'
import postcssFontMagician from 'postcss-font-magician'
import cssnano from 'cssnano'
const cssProcessor = postcss( [ postcssImport()
, postcssUrl( { url: 'inline'
, assetsPath: '../images'
} )
, postcssCssnext()
, postcssFontMagician()
, cssnano()
])
function processCSS(css, { meta = {} } = {}) {
return cssProcessor.process(css, { from: meta.resourcePath }).then(x => x.css)
}
const WarnGTM = ({}) => <script dangerouslySetInnerHTML={{ __html: 'if(!window.google_tag_manager) console.info("GTM BLOCKED => consider disabling ad block so we can see how much usage we\'re getting")' }} />
const BodyInit = ({ theme }) => {
const { style } = theme
const { backgroundColor, margin, padding } = style.body
const __html = minify(`
document.body.style.backgroundColor = '${backgroundColor}'
document.body.style.margin = '${margin}'
document.body.style.padding = '${padding}'
`)
return <script dangerouslySetInnerHTML={{ __html }}/>
}
const InitialState = createInitialState({ React, Immutable })
const renderMarkup = html => `<!doctype html>\n${renderToStaticMarkup(html)}`
export default function configureAppRouter({ cors, paths }) {
const { SRC_ROOT, APP_ROOT, LIB_ROOT, STATIC_ROOT, ASSETS_ROOT } = paths
const universalMiddleware = reactStyles(React, { processCSS })
return universalMiddleware(req => new Promise((resolve, reject) => {
const memoryHistory = createMemoryHistory(req.path)
let store = configureStore(memoryHistory)
const history = syncHistoryWithStore(memoryHistory, store)
match({ history
, routes
, location: req.url
}, (error, redirectLocation, renderProps) => {
const renderBody = () => {
if (error) {
return reject(new RoutingError( { status: 500
, statusMessage: 'Body rendering error occurred.'
, error
} ))
} else if (redirectLocation) {
return reject(new RoutingError( { status: 302
, redirect: redirectLocation.pathname + redirectLocation.search
} ))
} else if (renderProps) {
const state = store.getState()
const theme = getThemeForUrl(state.visual.theme, req.url)
const appMarkup = server.flags.render ? renderToString(<Provider store={store}><RouterContext {...renderProps} /></Provider>)
: null
return (
<body>
<BodyInit theme={theme} />
{server.flags.render ? <InitialState globalKey={packageKey} state={state} serialize={serialize} /> : null}
{server.flags.render ? <div id="root" dangerouslySetInnerHTML={{ __html: appMarkup }}/> : <div id="root" />}
<script src="/assets/app.js" />
</body>
)
} else {
reject(false)
}
}
const renderHead = styles => {
const title = `gridiron-example${IS_HOT ? ' is so hot right now...' : (IS_DEV ? ' is so dev right now...' : '')}`
const items = [ <meta charSet="utf-8" />
, <meta name="viewport" content="width=device-width, initial-scale=1.0" />
, <title>{title}</title>
, <link rel="icon" href={faviconUrl} type="image/x-icon" />
, ...(server.flags.render ? styles : [])
, <link rel="stylesheet" href="/assets/app.css" type="text/css" />
, <script dangerouslySetInnerHTML={{ __html: `(function(d) {
var config = { kitId: 'xsj1dhs', scriptTimeout: 3000, async: true },
h=d.documentElement,t=setTimeout(function(){h.className=h.className.replace(/\bwf-loading\b/g,"")+" wf-inactive";},config.scriptTimeout),tk=d.createElement("script"),f=false,s=d.getElementsByTagName("script")[0],a;h.className+=" wf-loading";tk.src='https://use.typekit.net/'+config.kitId+'.js';tk.async=true;tk.onload=tk.onreadystatechange=function(){a=this.readyState;if(f||a&&a!="complete"&&a!="loaded")return;f=true;clearTimeout(t);try{Typekit.load(config)}catch(e){}};s.parentNode.insertBefore(tk,s)
})(document)
` }} />
, <script src="/assets/polyfill.js" />
, <script src="/assets/vendor.js" />
, <script src="/assets/commons.js" />
]
return <head>{items.map((x, key) => React.cloneElement(x, { key }))}</head>
}
const renderPage = ({ head, body }) => renderMarkup(<html>{head}{body}</html>)
return resolve({ renderBody, renderHead, renderPage })
})
}), (promise, res, next) => {
return promise
.then(page => res.send(page))
.catch(err => {
if(err === false) {
return next()
}
console.error(err, 'AN ERROR OCCURRED')
try {
if(err instanceof RoutingError) {
const { status, statusMessage, redirect, innerError } = err
if(status === 302)
return res.redirect(302, redirect)
return res.status(status).send(renderMarkup(<ErrorPage status={status} statusMessage={statusMessage}>{innerError}</ErrorPage>))
} else {
return res.status(500).send(renderMarkup(<ErrorPage statusMessage={err.message || error}>{err}</ErrorPage>))
}
} catch(internalError) {
console.error(internalError, 'REALLY BAD ERROR OCCURRED')
}
})
})
}