Skip to content

Instantly share code, notes, and snippets.

@RStankov
Last active January 30, 2020 06:30
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 RStankov/1652eee15a54fe4c365bcb8e3ae5ce82 to your computer and use it in GitHub Desktop.
Save RStankov/1652eee15a54fe4c365bcb8e3ae5ce82 to your computer and use it in GitHub Desktop.
import {
ApolloClient,
InMemoryCache,
HttpLink,
IntrospectionFragmentMatcher,
} from 'apollo-boost';
import { GRAPHQL_URI } from '~/config';
function createClient(initialState: any, { fetch }: { fetch: any }) {
const headers: any = {
'X-Requested-With': 'XMLHttpRequest',
};
return new ApolloClient({
link: new HttpLink({
uri: GRAPHQL_URI,
credentials: 'include',
headers,
fetch: fetch || global.fetch,
}),
),
// more irrelevant stuff
});
}
let apolloClient: ApolloClient<any> | null = null;
export default function initApollo(initialState: any, options: any = {}) {
// Make sure to create a new client for every server-side request so that data
// isn't shared between connections (which would be bad)
if (!process.browser) {
return createClient(initialState, options);
}
// Reuse client on the client-side
if (!apolloClient) {
apolloClient = createClient(initialState, options);
}
return apolloClient;
}
import fetch from 'isomorphic-unfetch';
export default class ServerFetcher {
reqHeaders: any;
resHeaders: any = [];
constructor(req: any) {
this.reqHeaders = {
Cookie: req.get('cookie'),
'User-Agent': req.headers['user-agent'],
};
if (req.headers['cf-ipcountry']) {
this.reqHeaders['CF-IPCountry'] = req.headers['cf-ipcountry'];
}
}
fetch = (url: string, options: any) => {
options = {
...options,
headers: {
...options.headers,
...this.reqHeaders,
},
};
return fetch(url, options).then((res: any) => {
const setCookie = res.headers.raw()['set-cookie'];
if (setCookie) {
if (typeof setCookie === 'string') {
this.resHeaders.push(['Set-Cookie', setCookie]);
} else {
this.resHeaders = this.resHeaders.concat(
setCookie.map((value: string) => ['Set-Cookie', value]),
);
}
}
return res;
});
};
setResponseHeaders(res: any) {
this.resHeaders.forEach(([name, value]: string[]) => {
res.set(name, value);
});
}
}
import * as React from 'react';
import Head from 'next/head';
import ServerFetcher from './serverFetcher';
import captureError from '~/utils/captureError';
import initApollo from './init';
import { ApolloClient } from 'apollo-boost';
import { getDataFromTree } from 'react-apollo';
export default function withApollo(App: any): any {
return class WithApollo extends React.Component<any, any> {
static displayName = `WithApollo(${App.displayName})`;
static getInitialProps = buildInitialProps(App);
apolloClient: ApolloClient<any>;
constructor(props: any) {
super(props);
this.apolloClient = initApollo(props.apolloState);
}
render() {
return <App {...this.props} apolloClient={this.apolloClient} />;
}
};
}
export function buildInitialProps(App: any) {
if (process.browser) {
return async (ctx: any) => {
const apollo = initApollo({});
ctx.ctx.apolloClient = apollo;
let appProps = {};
if (App.getInitialProps) {
appProps = await App.getInitialProps(ctx);
}
return {
...appProps,
apolloState: apollo.cache.extract(),
};
};
}
return async (ctx: any) => {
const {
Component,
router,
ctx: { req, res },
} = ctx;
const fetcher = new ServerFetcher(req);
const apollo = initApollo({}, { fetch: fetcher.fetch });
ctx.ctx.apolloClient = apollo;
let appProps = {};
if (App.getInitialProps) {
appProps = await App.getInitialProps(ctx);
}
if (res && res.finished) {
return {};
}
try {
await getDataFromTree(
<App
{...appProps}
Component={Component}
router={router}
apolloClient={apollo}
/>,
);
} catch (error) {
captureError(error);
}
Head.rewind();
fetcher.setResponseHeaders(res);
return {
...appProps,
apolloState: apollo.cache.extract(),
};
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment