Last active
November 18, 2016 02:11
-
-
Save jasonnathan/ce319b53db4de0b9f3a0fc90379f95a3 to your computer and use it in GitHub Desktop.
SSR with apollo and meteor-router-ssr
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react'; | |
import {Meteor} from 'meteor/meteor'; | |
/* | |
* Had to hack server.jsx in meteor-react-router-ssr to move the `preRender` hook so it runs after | |
* `wrapperHook` and I had to give it {app} as an extra argument. | |
*/ | |
import {ReactRouterSSR} from 'meteor/jasonnathan:react-router-ssr'; | |
import ReactHelmet from 'react-helmet'; | |
import AppRoutes from '/imports/routes.jsx'; | |
import ApolloClient, {createNetworkInterface} from 'apollo-client'; | |
import {ApolloProvider} from 'react-apollo'; | |
import {getDataFromTree} from "react-apollo/server"; | |
let client, initialState, | |
url = "localhost", | |
opts = { | |
ssrMode: Meteor.isServer | |
}; | |
// relevant for apollo when a client-side query is made | |
if(Meteor.isClient && process.env.NODE_ENV === 'production'){ | |
url = "public-url.com"; | |
} | |
// setup apollo's networkInterface | |
opts.networkInterface = createNetworkInterface({ | |
credentials: 'same-origin', uri: `http://${url}:3000/graphql` | |
}); | |
const rehydrateHook = state => initialState = state; | |
const wrapperHook = app => { | |
opts.initialState = initialState; | |
client = new ApolloClient(opts); | |
return <ApolloProvider client={client}>{app}</ApolloProvider> | |
}; | |
// the preRender is simpler. All it needed was the `app` argument | |
const preRender = (req, res, app) => Promise.await(getDataFromTree(app)); | |
// dehydrating in a way that is apollo friendly. Queries & mutations need to be removed | |
const dehydrateHook = () => ({apollo:{data:client.store.getState().apollo.data}}) | |
const htmlHook = html => { | |
const h = ReactHelmet.rewind(); | |
return html.replace('<head>', '<head>' + h.title + h.base + h.meta + h.link + h.script); | |
} | |
// the weirdest thing - wrapperHook in clientOptions - inferring it only runs on the client | |
const clientOptions = {wrapperHook, rehydrateHook}; | |
const serverOptions = {htmlHook, preRender, dehydrateHook}; | |
ReactRouterSSR.Run(AppRoutes(), clientOptions, serverOptions); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// from line 190 | |
// if (serverOptions.preRender) { | |
// serverOptions.preRender(req, res); | |
// } | |
//... | |
global.__STYLE_COLLECTOR_MODULES__ = []; | |
global.__STYLE_COLLECTOR__ = ''; | |
renderProps = { | |
...renderProps, | |
...serverOptions.props | |
}; | |
fetchComponentData(serverOptions, renderProps); | |
let app = <RouterContext {...renderProps} />; | |
if (typeof clientOptions.wrapperHook === 'function') { | |
app = clientOptions.wrapperHook(app); | |
} | |
// preRender moved after wrapperHook | |
if (serverOptions.preRender) { | |
serverOptions.preRender(req, res, app); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment