Skip to content

Instantly share code, notes, and snippets.

@scazzy
Last active July 30, 2017 08:20
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 scazzy/0160c03d94602fa7684df55e7c82d040 to your computer and use it in GitHub Desktop.
Save scazzy/0160c03d94602fa7684df55e7c82d040 to your computer and use it in GitHub Desktop.
SSR using React-transmit
/*
* src/client.js
*/
import React from 'react';
import { render } from 'react-dom';
import Transmit from 'react-transmit';
import Root from './containers/Root'
window.onload = () => {
Transmit.render(
Root,
{
locale: navigator.language,
browser: true
},
document.getElementById('root')
)
}
/**
* Detect whether the server-side render has been discarded due to an invalid checksum.
*/
if (process.env.NODE_ENV !== "production" || 1) {
const reactRoot = window.document.getElementById("root");
if (!reactRoot || !reactRoot.firstChild || !reactRoot.firstChild.attributes ||
!reactRoot.firstChild.attributes["data-react-checksum"]) {
console.error("Server-side React render was discarded. Make sure that your initial render does not contain any client-side code.");
}
}
/**
* src/containers/Root.js
* App's root container
*/
import React, { Component } from 'react';
import { BrowserRouter, StaticRouter } from 'react-router-dom';
import Redux from 'redux';
import { Provider } from 'react-redux';
import AppRoutes from '../routes/AppRoutes';
import { IntlProvider, addLocaleData, defineMessages } from 'react-intl';
import store from '../store';
import * as intl from '../lang/intl';
import * as browserHelper from '../helpers/browser';
import Transmit from 'react-transmit';
import axios from 'axios';
import PropTypes from 'prop-types';
/**
* Initialize i18n
* common for server and client
*/
intl.init();
const bootApiUrl = "http://dev-api.domain.com/api/v1/sg/boot";
/**
* src/containers/Root.js
* App root view container
*/
class Root extends Component {
constructor () {
super();
this.defaultProps = {
bootdata: {}
}
}
componentDidMount () {
// Load Facebook SDK
// browserHelper.loadFBSDK();
}
getChildContext() {
return { bootdata: this.props.bootdata }
}
render () {
const Router = this.props.browser === true ? BrowserRouter : StaticRouter;
const locale = this.props.locale.substring(0,2) || 'en';
return (
<Provider store={store}>
<IntlProvider locale={locale} messages={intl.getTranslations(locale)}>
<Router {...this.props}>
<AppRoutes />
</Router>
</IntlProvider>
</Provider>
)
}
}
Root.childContextTypes = {
bootdata: PropTypes.object
};
export default Transmit.createContainer(Root, {
initialVariables: {},
fragments: {
bootdata () {
return axios.get(bootApiUrl).then(response => response.data.data);
}
}
});
/*
* src/server.js
*/
import path from 'path';
import express from 'express';
import React from 'react';
import Transmit from 'react-transmit';
import { renderToString } from 'react-dom/server';
import { StaticRouter } from 'react-router-dom';
import cookieParser from 'cookie-parser';
import boot from './boot';
import Config from './config';
import Root from './containers/Root';
import * as intl from './lang/intl';
import { readFile } from 'fs'
const app = new express();
app.use(cookieParser());
app.use('/assets', express.static('public/assets', { fallthrough: false }));
app.get('*.js', function (req, res, next) {
req.url = req.url + '.gz';
res.set('Content-Encoding', 'gzip');
next();
});
app.get('/*', (req, res) => {
const domain = req.get('host');
const locale = req.cookies['locale'] || req.header('Accept-Language') || 'en';
const context = {};
if(!req.cookies['locale'])
res.cookie('locale', locale);
// TODO:
// Cache this part of rendering content of that page for every request
//
if (context.url) {
// Somewhere a `<Redirect>` was rendered
redirect(302, context.url);
} else {
// (<Root locale={locale} location={req.url} context={context} />)
// We're good, send the response
const indexFile = path.join(__dirname, '..', 'public','index.html')
const renderedHtml = Transmit.renderToString(
Root,
{
locale,
location: req.url,
context
}
).then(({reactString, reactData}) => {
readFile(indexFile, 'utf8', (err, data) => {
if (err) throw err;
const document = data.replace('<!-- server -->', reactString);
res.send(document);
})
});
}
});
app.listen(Config.port, (err) => {
if(err) {
return console.error(err);
} else {
console.log('Listening at :' + Config.port);
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment