import { useMemo } from "react"; import { ApolloClient, from, HttpLink, InMemoryCache, NormalizedCacheObject, } from "@apollo/client"; import { concatPagination } from "@apollo/client/utilities"; import { equals, mergeDeepWith } from "ramda"; import { onError } from "@apollo/client/link/error"; export const client = new ApolloClient({ uri: "/api/graphql", cache: new InMemoryCache(), }); export const APOLLO_STATE_PROP_NAME = "__APOLLO_STATE__"; let apolloClient: ApolloClient; function createApolloClient() { const httpLink = new HttpLink({ uri: typeof window === "undefined" ? process.env.BACKEND_URI : "/api/graphql", // Server URL (must be absolute) credentials: "same-origin", // Additional fetch() options like `credentials` or `headers` }); const errorLink = onError(({ graphQLErrors, networkError }) => { if (graphQLErrors) graphQLErrors.forEach(({ message, locations, path }) => console.log( `[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}` ) ); if (networkError) console.log(`[Network error]: ${networkError}`); }); return new ApolloClient({ ssrMode: typeof window === "undefined", link: from([errorLink, httpLink]), cache: new InMemoryCache({ typePolicies: { Query: { fields: { allPosts: concatPagination(), }, }, }, }), }); } export function initializeApollo(initialState = null) { const _apolloClient = apolloClient ?? createApolloClient(); // If your page has Next.js data fetching methods that use Apollo Client, the initial state // gets hydrated here if (initialState) { // Get existing cache, loaded during client side data fetching const existingCache = _apolloClient.extract(); // Merge the existing cache into data passed from getStaticProps/getServerSideProps const data = mergeDeepWith( (a, b) => { if (Array.isArray(a) && Array.isArray(b)) { return [ ...a, ...b.filter((bi) => a.every((ai) => !equals(ai, bi))), ]; } else { return b; } }, initialState, existingCache ); // Restore the cache with the merged data _apolloClient.cache.restore(data); } // For SSG and SSR always create a new Apollo Client if (typeof window === "undefined") return _apolloClient; // Create the Apollo Client once in the client if (!apolloClient) apolloClient = _apolloClient; return _apolloClient; } export function addApolloState(client, pageProps) { if (pageProps?.props) { pageProps.props[APOLLO_STATE_PROP_NAME] = client.cache.extract(); } return pageProps; } export function useApollo(pageProps) { const state = pageProps[APOLLO_STATE_PROP_NAME]; const store = useMemo(() => initializeApollo(state), [state]); return store; }