Skip to content

Instantly share code, notes, and snippets.

@KevinDanikowski
Created July 27, 2020 18:59
Show Gist options
  • Save KevinDanikowski/ca2b0b10eb6f1f871bd8538a1c93e1c0 to your computer and use it in GitHub Desktop.
Save KevinDanikowski/ca2b0b10eb6f1f871bd8538a1c93e1c0 to your computer and use it in GitHub Desktop.

Revisions

  1. KevinDanikowski created this gist Jul 27, 2020.
    124 changes: 124 additions & 0 deletions apollo.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,124 @@
    // I'VE COPIED WHOLE FILE FOR REFERENCE, ONLY THE HEADERS PART HAS CHANGED
    // THIS FILE: https://github.com/amclin/react-project-boilerplate/blob/master/templates/default/src/utils/apollo.jsx
    /* eslint-disable react/jsx-props-no-spreading, no-console */
    /* FOR SERVER SIDE RENDERING APOLLO FETCHES: Use unmodifed link below.
    * https://github.com/zeit/next.js/blob/canary/examples/with-apollo/lib/apollo.js
    * this file is modified from link above. Had some issues getting it to work with hooks.
    */
    import React from 'react'
    import { ApolloProvider } from '@apollo/react-hooks'
    import { ApolloClient, createHttpLink, InMemoryCache } from '@apollo/client'
    import fetch from 'isomorphic-unfetch'
    import getConfig from 'next/config'
    import { setContext } from '@apollo/client/link/context'
    import { AWS_ACCESS_TOKEN } from 'Utils/constants'

    const {
    publicRuntimeConfig: {
    urls: { proxyServer: apiGatewayUrl },
    },
    } = getConfig()
    export let apolloClient = null

    const httpLink = createHttpLink({
    uri: apiGatewayUrl,
    fetch,
    })

    const authLink = setContext((_, { headers }) => {
    // get the authentication token from local storage if it exists
    const token = localStorage.getItem(AWS_ACCESS_TOKEN)
    // return the headers to the context so httpLink can read them
    return {
    headers: {
    ...headers,
    authorization: token ? `Bearer ${token}` : '',
    },
    }
    })

    /**
    * Creates and configures the ApolloClient
    * @param {Object} [initialState={}]
    */
    function createApolloClient(initialState = {}) {
    return new ApolloClient({
    ssrMode: false, // !process.browser - turn this on if you need to make calls before sending html page
    link: authLink.concat(httpLink),
    cache: new InMemoryCache().restore(initialState),
    })
    }

    /**
    * Always creates a new apollo client on the server
    * Creates or reuses apollo client in the browser.
    * @param {Object} initialState
    */
    function initApolloClient(initialState) {
    // 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 createApolloClient(initialState)
    }

    // Reuse client on the client-side
    if (!apolloClient) {
    apolloClient = createApolloClient(initialState)
    }

    return apolloClient
    }

    /**
    * Creates and provides the apolloContext
    * to a next.js PageTree. Use it by wrapping
    * your PageComponent via HOC pattern.
    * @param {Function|Class} PageComponent
    * @param {Object} [config]
    */
    export function withApollo(PageComponent) {
    // eslint-disable-next-line
    const WithApollo = ({ apolloClient, apolloState, ...pageProps }) => {
    const client = apolloClient || initApolloClient(apolloState)
    return (
    <ApolloProvider client={client}>
    <PageComponent {...pageProps} />
    </ApolloProvider>
    )
    }

    // unused, we do server rendered optimized, so no getInitialProps
    if (PageComponent.getInitialProps) {
    WithApollo.getInitialProps = async ctx => {
    // Initialize ApolloClient, add it to the ctx object so
    // we can use it in `PageComponent.getInitialProp`.
    // eslint-disable-next-line
    const apolloClient = (ctx.apolloClient = initApolloClient())

    // Run wrapped getInitialProps methods
    const pageProps = await PageComponent.getInitialProps(ctx)

    // Only on the server:
    if (!process.browser) {
    // When redirecting, the response is finished.
    // No point in continuing to render
    if (ctx.res && ctx.res.finished) {
    return pageProps
    }
    }

    // Extract query data from the Apollo store
    const apolloState = apolloClient.cache.extract()

    return {
    ...pageProps,
    apolloState,
    }
    }
    }

    return WithApollo
    }

    export default withApollo