2021-05-02 20:04:54 +08:00
|
|
|
import { useMemo } from "react";
|
2021-07-01 14:01:12 +08:00
|
|
|
import {
|
|
|
|
ApolloClient,
|
2021-07-03 22:36:38 +08:00
|
|
|
ApolloLink,
|
2021-07-01 14:01:12 +08:00
|
|
|
from,
|
|
|
|
HttpLink,
|
|
|
|
InMemoryCache,
|
|
|
|
NormalizedCacheObject,
|
|
|
|
} from "@apollo/client";
|
2021-05-02 20:04:54 +08:00
|
|
|
import { concatPagination } from "@apollo/client/utilities";
|
2021-07-03 22:36:38 +08:00
|
|
|
import { clone, equals, mergeDeepWith } from "ramda";
|
2021-05-02 20:04:54 +08:00
|
|
|
import { onError } from "@apollo/client/link/error";
|
2021-07-03 22:36:38 +08:00
|
|
|
import { buildClientSchema, IntrospectionQuery } from "graphql";
|
|
|
|
import { DateTimeResolver } from "graphql-scalars";
|
|
|
|
import introspectionResult from "./graphql.schema.json"; // schema 文件
|
|
|
|
import { withScalars } from "apollo-link-scalars";
|
|
|
|
import superjson from "superjson";
|
2021-05-01 18:34:45 +08:00
|
|
|
|
2021-07-03 22:36:38 +08:00
|
|
|
const schema = buildClientSchema(
|
|
|
|
introspectionResult as unknown as IntrospectionQuery
|
|
|
|
);
|
|
|
|
|
|
|
|
const typesMap = {
|
|
|
|
DateTime: DateTimeResolver,
|
|
|
|
};
|
2021-05-02 20:04:54 +08:00
|
|
|
|
|
|
|
export const APOLLO_STATE_PROP_NAME = "__APOLLO_STATE__";
|
|
|
|
|
2021-07-01 14:01:12 +08:00
|
|
|
let apolloClient: ApolloClient<NormalizedCacheObject>;
|
2021-05-02 20:04:54 +08:00
|
|
|
|
|
|
|
function createApolloClient() {
|
|
|
|
const httpLink = new HttpLink({
|
2021-07-03 22:36:38 +08:00
|
|
|
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`
|
|
|
|
});
|
2021-05-02 20:04:54 +08:00
|
|
|
|
|
|
|
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",
|
2021-07-03 22:36:38 +08:00
|
|
|
link: from([
|
|
|
|
errorLink,
|
|
|
|
withScalars({ schema, typesMap }) as ApolloLink,
|
|
|
|
httpLink,
|
|
|
|
]),
|
2021-05-02 20:04:54 +08:00
|
|
|
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)) {
|
2021-07-03 22:36:38 +08:00
|
|
|
return [...a, ...b.filter((bi) => a.every((ai) => !equals(ai, bi)))];
|
2021-05-02 20:04:54 +08:00
|
|
|
} 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) {
|
2021-07-03 22:36:38 +08:00
|
|
|
pageProps.props[APOLLO_STATE_PROP_NAME] = clone(client.cache.extract());
|
2021-05-02 20:04:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return pageProps;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function useApollo(pageProps) {
|
|
|
|
const state = pageProps[APOLLO_STATE_PROP_NAME];
|
|
|
|
const store = useMemo(() => initializeApollo(state), [state]);
|
|
|
|
return store;
|
|
|
|
}
|