ssr-fatigue-react
v2.0.0-alpha.0
Published
Express middleware for server side rendering of React based apps
Downloads
6
Readme
ssr-fatigue-react
An Express middleware for server side rendering of React based web apps. It wraps:
- react-intl for optional translation management
- react-router for UI route declarations
- react-helmet for dynamic HTML meta data generation
- @loadable/components for easy code splitting and lazy loading
When the ssr-fatigue-intl middleware is used, it will automatically add the messages, locale and, react-intl locale data to the output html.
For keeping things simple, the ssr-fatigue-config project contains some helper methods to build Webpack and Babel configurations in order to get things started without loosing too much sanity (no guarantees though).
Installation
$ npm i ssr-fatigue-react
Usage
src/server/index.js
import express from 'express'
import reactSSR from 'ssr-fatigue-react'
const app = express()
const assetDir = resolve(__dirname, 'path/to/webpack/output/dir')
app.use('/inc', express.static(assetDir))
app.get(
'*',
reactSSR({
buildDir: assetDir,
basePath: '', // (req, res) => res.get('X-Proxy-Base')
publicPath: '/inc/web/', // path to assets (without basePath)
})
)
src/client/entry-web.js
import { hot } from 'react-hot-loader/root'
import initClient from 'ssr-fatigue-react/client'
import App from '../shared/app'
import routeConfig from '../shared/routes'
// check out dynamic webpack public path
console.log('public path', __webpack_public_path__)
initClient(hot(App), routeConfig).then(() => console.log('App hydrated!'))
src/client/entry-node.js
export { default } from '../shared/app'
export routeConfig from '../shared/routes'
src/shared/routes.js
import React from 'react'
import loadable from '@loadable/component'
export default [
{
path: '/',
exact: true,
component: loadable(
() => import(/* webpackPrefetch: true */ './pages/home'),
{
fallback: <div>Loading...</div>,
}
),
},
]
src/shared/app.js
import React from 'react'
import { Helmet } from 'react-helmet'
export default class App extends React.Component {
static async getInitialProps({ getRouteProps, context }) {
context.what = 'something to pass down to routes'
return {
routeProps: await getRouteProps(context),
}
}
render() {
return (
<div className="container">
<Helmet titleTemplate="My App - %s">
<meta name="description" content="An example application" />
</Helmet>
{children}
</div>
)
}
}
src/shared/pages/home.js
import React from 'react'
import { Helmet } from 'react-helmet'
export default class HomePage extends React.Component {
static async getInitialProps(ctx) {
const { req, what } = ctx
return { what }
}
render() {
return (
<div className="row">
<Helmet>
<title>Home</title>
</Helmet>
<div className="col-xs-12">
<h1>Home</h1>
<p>{this.props.what}</p>
</div>
</div>
)
}
}
The given webpackConfig file should have two configurations for target web
and node
. Using the ssr-fatigue-config
package:
webpack.config.js
const { resolve } = require('path')
const { buildWebpackConfig } = require('ssr-fatigue-config/webpack')
const entryDir = resolve(__dirname, 'src', 'client')
const buildDir = resolve(__dirname, 'build')
module.exports = [
buildWebpackConfig({ target: 'node', buildDir, entryDir }),
buildWebpackConfig({ target: 'web', buildDir, entryDir }),
]
babel.config.js
const { buildLocalBabelConfig } = require('ssr-fatigue-config/babel')
module.exports = buildLocalBabelConfig()