Created
August 17, 2019 06:22
-
-
Save luandevpro/39ebbf1de3fdbd1445b421c812b80cc6 to your computer and use it in GitHub Desktop.
This file contains 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 fetch from 'isomorphic-fetch'; | |
import { ApolloClient } from 'apollo-client'; | |
import { createHttpLink } from 'apollo-link-http'; | |
import { InMemoryCache } from 'apollo-cache-inmemory'; | |
import { split } from 'apollo-link'; | |
import { getMainDefinition } from 'apollo-utilities'; | |
import { setContext } from 'apollo-link-context'; | |
import { WebSocketLink } from 'apollo-link-ws'; | |
let apolloClient = null; | |
// Polyfill fetch() on the server (used by apollo-client) | |
if (!process.browser) { | |
global.fetch = fetch; | |
} | |
const HASURA_GRAPHQL_ENGINE_HOSTNAME = 'next-node-hasura-graphql.herokuapp.com'; | |
const GRAPHQL_ENDPOINT = `https://${HASURA_GRAPHQL_ENGINE_HOSTNAME}/v1/graphql`; | |
const WEBSOCKET_ENDPOINT = `wss://${HASURA_GRAPHQL_ENGINE_HOSTNAME}/v1/graphql`; | |
function create(initialState, { getToken }) { | |
const authLink = setContext((_, { headers }) => { | |
const token = getToken(); | |
return { | |
headers: { | |
...headers, | |
authorization: token ? `Bearer ${token}` : '', | |
}, | |
}; | |
}); | |
const wsLink = process.browser | |
? new WebSocketLink({ | |
uri: WEBSOCKET_ENDPOINT, | |
options: { | |
lazy: true, | |
reconnect: true, | |
}, | |
}) | |
: null; | |
const httpLink = createHttpLink({ | |
uri: GRAPHQL_ENDPOINT, | |
credentials: 'same-origin', | |
}); | |
const link = process.browser | |
? split( | |
({ query }) => { | |
const { kind, operation } = getMainDefinition(query); | |
return kind === 'OperationDefinition' && operation === 'subscription'; | |
}, | |
wsLink, | |
httpLink, | |
) | |
: httpLink; | |
return new ApolloClient({ | |
connectToDevTools: process.browser, | |
ssrMode: !process.browser, | |
link: authLink.concat(link), | |
cache: new InMemoryCache().restore(initialState || {}), | |
}); | |
} | |
function initApollo(initialState, options) { | |
if (!process.browser) { | |
return create(initialState, options); | |
} | |
if (!apolloClient) { | |
apolloClient = create(initialState, options); | |
} | |
return apolloClient; | |
} | |
export default initApollo; |
This file contains 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 Head from 'next/head'; | |
import PropTypes from 'prop-types'; | |
import { getMarkupFromTree } from '@apollo/react-ssr'; | |
import { ApolloProvider } from '@apollo/react-hooks'; | |
import { renderToString } from 'react-dom/server'; | |
import initApollo from './initApollo'; | |
import { userByPk } from '../graphql/users/query'; | |
let globalUser = null; | |
let globalToken = null; | |
function getCookie(context = {}) { | |
return context.req && context.req.signedCookies.token | |
? context.req.signedCookies.token | |
: globalToken; | |
} | |
export default (App) => { | |
class Apollo extends React.Component { | |
static displayName = 'withApollo(App)'; | |
static propTypes = { | |
user: PropTypes.shape({ | |
id: PropTypes.string, | |
isAdmin: PropTypes.bool, | |
}), | |
isFromServer: PropTypes.bool.isRequired, | |
token: PropTypes.string.isRequired, | |
}; | |
static defaultProps = { | |
user: null, | |
}; | |
constructor(props) { | |
super(props); | |
this.apolloClient = initApollo(props.apolloState, { | |
getToken: () => getCookie(), | |
}); | |
} | |
componentDidMount() { | |
const { user, isFromServer, token } = this.props; | |
if (isFromServer) { | |
globalUser = user; | |
globalToken = token; | |
} | |
} | |
static async getInitialProps(ctx) { | |
const { Component, router } = ctx; | |
// Run all GraphQL queries in the component tree | |
// and extract the resulting data | |
const apollo = initApollo( | |
{}, | |
{ | |
getToken: () => getCookie(ctx), | |
}, | |
); | |
const isFromServer = !!ctx.req; | |
let user = null; | |
// get currentUser if login for client vs server | |
if (ctx.req && ctx.req.signedCookies.token) { | |
try { | |
const { data } = await apollo.query({ | |
query: userByPk, | |
}); | |
user = ctx.req && ctx.req.signedCookies.token ? data.users[0] : globalUser; | |
} catch (e) { | |
console.log(e); | |
} | |
} else { | |
user = globalUser; | |
} | |
// get token from server vs client | |
const token = | |
ctx.req && ctx.req.signedCookies.token ? ctx.req.signedCookies.token : globalToken; | |
const appProps = { isFromServer, user, token }; | |
if (App.getInitialProps) { | |
Object.assign(appProps, (await App.getInitialProps(ctx, apollo)) || {}); | |
} | |
const url = { | |
ctx: ctx.asPath, | |
pathname: ctx.pathname, | |
query: ctx.query, | |
}; | |
if (ctx.res && ctx.res.finished) { | |
return {}; | |
} | |
if (ctx.req && ctx.req.signedCookies.token) { | |
try { | |
await getMarkupFromTree({ | |
renderFunction: renderToString, | |
tree: ( | |
<ApolloProvider ctx={ctx} {...appProps} client={apollo}> | |
<App | |
ctx={ctx} | |
{...appProps} | |
url={url} | |
Component={Component} | |
router={router} | |
apolloClient={apollo} | |
name="oc cho" | |
/> | |
</ApolloProvider> | |
), | |
}); | |
} catch (error) { | |
console.error('Error while running `getMarkupFromTree`', error); | |
} | |
} | |
if (!process.browser) { | |
// getDataFromTree does not call componentWillUnmount | |
// head side effect therefore need to be cleared manually | |
Head.rewind(); | |
} | |
const apolloState = apollo.cache.extract(); | |
return { | |
...appProps, | |
apolloState, | |
url, | |
}; | |
} | |
render() { | |
return ( | |
<ApolloProvider client={this.apolloClient}> | |
<App {...this.props} apolloClient={this.apolloClient} /> | |
</ApolloProvider> | |
); | |
} | |
} | |
Apollo.propTypes = { | |
apolloState: PropTypes.object , //eslint-disable-line | |
}; | |
return Apollo; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment