Skip to content

Commit

Permalink
Add configurable SSR support
Browse files Browse the repository at this point in the history
Fixes #15
  • Loading branch information
larixer committed Dec 28, 2016
1 parent e5b0052 commit b60c7e6
Show file tree
Hide file tree
Showing 7 changed files with 31 additions and 18 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ frontend and backend at the same time, so React should not complain about differ
On the initial web page request backend fully renders UI and hands off Apollo Redux Store state to frontend. Frontend
then starts off from there and updates itself on user interactions.

If you don't need Server Side Rendering, set package.json `ssr` field to `false`

- Optimistic UI updates

This example application uses Apollo optimistic UI updates, that result in immediate UI update on user interaction and then,
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"backendBuildDir": "build/server",
"frontendBuildDir": "build/client",
"webpackDevPort": 3000,
"apiPort": 8080
"apiPort": 8080,
"ssr": true
},
"engines": {
"node": "6.6.0",
Expand Down
20 changes: 11 additions & 9 deletions src/apollo_client.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,18 @@ const createApolloClient = networkInterface => {
},
networkInterface,
};
if (__CLIENT__) {
if (window.__APOLLO_STATE__) {
params.initialState = window.__APOLLO_STATE__;
// Temporary workaround for bug in AC@0.5.0: https://github.com/apollostack/apollo-client/issues/845
delete params.initialState.apollo.queries;
delete params.initialState.apollo.mutations;
if (__SSR__) {
if (__CLIENT__) {
if (window.__APOLLO_STATE__) {
params.initialState = window.__APOLLO_STATE__;
// Temporary workaround for bug in AC@0.5.0: https://github.com/apollostack/apollo-client/issues/845
delete params.initialState.apollo.queries;
delete params.initialState.apollo.mutations;
}
params.ssrForceFetchDelay = 100;
} else {
params.ssrMode = true;
}
params.ssrForceFetchDelay = 100;
} else {
params.ssrMode = true;
}
return new ApolloClient(params);
};
Expand Down
11 changes: 9 additions & 2 deletions src/server/middleware/website.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export default (req, res) => {
} else if (error) {
log.error('ROUTER ERROR:', error);
res.status(500);
} else if (renderProps) {
} else if (__SSR__ && renderProps) {
const client = createApolloClient(createBatchingNetworkInterface({
uri: apiUrl,
opts: {
Expand Down Expand Up @@ -60,10 +60,17 @@ export default (req, res) => {
assetMap = JSON.parse(fs.readFileSync(path.join(settings.frontendBuildDir, 'assets.json')));
}

const page = <Html content={html} state={context.store.getState()} assetMap={assetMap} aphroditeCss={css}/>;
const page = <Html content={html} state={context.store.getState()} assetMap={assetMap} aphroditeCss={css.content}/>;
res.send(`<!doctype html>\n${ReactDOM.renderToStaticMarkup(page)}`);
res.end();
}).catch(e => log.error('RENDERING ERROR:', e));
} else if (!__SSR__ && renderProps) {
if (__DEV__ || !assetMap) {
assetMap = JSON.parse(fs.readFileSync(path.join(settings.frontendBuildDir, 'assets.json')));
}
const page = <Html content="" state={({})} assetMap={assetMap} aphroditeCss="" />;
res.send(`<!doctype html>\n${ReactDOM.renderToStaticMarkup(page)}`);
res.end();
} else {
res.status(404).send('Not found');
}
Expand Down
4 changes: 2 additions & 2 deletions src/ui/components/html.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const Html = ({ content, state, assetMap, aphroditeCss }) => {
}}/>
}
<link rel="shortcut icon" href="/favicon.ico"/>
<style data-aphrodite>{aphroditeCss.content}</style>
<style data-aphrodite>{aphroditeCss}</style>
</head>
<body>
<div id="content" dangerouslySetInnerHTML={{ __html: content }} />
Expand All @@ -34,7 +34,7 @@ Html.propTypes = {
content: PropTypes.string.isRequired,
state: PropTypes.object.isRequired,
assetMap: PropTypes.object.isRequired,
aphroditeCss: PropTypes.object.isRequired,
aphroditeCss: PropTypes.string.isRequired,
};

export default Html;
4 changes: 2 additions & 2 deletions src/ui/containers/counter.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ const SUBSCRIPTION_QUERY = gql`

class Counter extends React.Component {

componentDidMount() {
if (this.props.loading === false) {
componentWillReceiveProps(nextProps) {
if (nextProps.loading === false) {
this.subscribe();
}
}
Expand Down
5 changes: 3 additions & 2 deletions tools/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const ExtractTextPlugin = require('extract-text-webpack-plugin');
const merge = require('webpack-merge');
const nodeExternals = require('webpack-node-externals');
const path = require('path');
const settings = require('../package.json').app;

global.__DEV__ = process.argv.length >= 3 && process.argv[2] === 'watch';
const buildNodeEnv = __DEV__ ? 'development' : 'production';
Expand Down Expand Up @@ -48,7 +49,7 @@ const baseConfig = {
let serverPlugins = [
new webpack.BannerPlugin('require("source-map-support").install();',
{ raw: true, entryOnly: false }),
new webpack.DefinePlugin(Object.assign({__CLIENT__: false, __SERVER__: true,
new webpack.DefinePlugin(Object.assign({__CLIENT__: false, __SERVER__: true, __SSR__: settings.ssr,
__DEV__: __DEV__, 'process.env.NODE_ENV': `"${buildNodeEnv}"`}))
];

Expand Down Expand Up @@ -91,7 +92,7 @@ let clientPlugins = [
new ManifestPlugin({
fileName: 'assets.json'
}),
new webpack.DefinePlugin(Object.assign({__CLIENT__: true, __SERVER__: false,
new webpack.DefinePlugin(Object.assign({__CLIENT__: true, __SERVER__: false, __SSR__: settings.ssr,
__DEV__: __DEV__, 'process.env.NODE_ENV': `"${buildNodeEnv}"`})),
new webpack.optimize.CommonsChunkPlugin(
"vendor",
Expand Down

0 comments on commit b60c7e6

Please sign in to comment.