diff --git a/src/hoc/withUniversalGraphQLDataLoader.ts b/src/hoc/withUniversalGraphQLDataLoader.ts index 13d9dc3ec..50a016fcc 100644 --- a/src/hoc/withUniversalGraphQLDataLoader.ts +++ b/src/hoc/withUniversalGraphQLDataLoader.ts @@ -1,23 +1,7 @@ import { getDataFromTree } from '@apollo/react-ssr'; -import { InMemoryCache, NormalizedCacheObject } from 'apollo-cache-inmemory'; -import { ApolloClient } from 'apollo-client'; -import { createHttpLink } from 'apollo-link-http'; -import fetch from 'isomorphic-unfetch'; +import { NormalizedCacheObject } from 'apollo-cache-inmemory'; import withApollo, { InitApolloOptions } from 'next-with-apollo'; - -// XXX This config is used on the FRONTEND (from the browser) or on the BACKEND (server), depending on whether it's loaded from SSR or client-side -const link = createHttpLink({ - fetch, // Switches between unfetch & node-fetch for client & server. - uri: process.env.GRAPHQL_API_ENDPOINT, - - // Headers applied here will be applied for all requests - // See the use of the "options" when running a graphQL query to specify options per-request at https://www.apollographql.com/docs/react/api/react-hooks/#options - headers: { - 'gcms-locale-no-default': false, - 'authorization': `Bearer ${process.env.GRAPHQL_API_KEY}`, - }, - credentials: 'same-origin', // XXX See https://www.apollographql.com/docs/react/recipes/authentication#cookie -}); +import { getStandaloneApolloClient } from '../utils/graphql'; /** * Export a HOC from next-with-apollo @@ -29,13 +13,7 @@ const link = createHttpLink({ */ export default withApollo( ({ initialState }: InitApolloOptions) => - new ApolloClient({ - link: link, - - // XXX Very important to provide the initialState, otherwise the client will replay the query upon loading, - // which is useless as the data were already fetched by the server (SSR) - cache: new InMemoryCache().restore(initialState || {}), // rehydrate the cache using the initial data passed from the server - }), { + getStandaloneApolloClient(initialState), { getDataFromTree, }, ); diff --git a/src/pages/[locale]/index.tsx b/src/pages/[locale]/index.tsx index 8cf0be245..cdfb71562 100644 --- a/src/pages/[locale]/index.tsx +++ b/src/pages/[locale]/index.tsx @@ -54,11 +54,12 @@ const HomePage: NextPage = (props): JSX.Element => { > { (layoutPageProps: LayoutPageProps): JSX.Element => { - const { locale, lang } = props; + const { locale, lang, customer } = props; console.log('layoutPageProps', layoutPageProps); return (

Page: Home

+

Customer: {customer?.label}

Locale: {locale}
diff --git a/src/pages/[locale]/terms.tsx b/src/pages/[locale]/terms.tsx index 708730bd0..d272336cc 100644 --- a/src/pages/[locale]/terms.tsx +++ b/src/pages/[locale]/terms.tsx @@ -36,12 +36,13 @@ export const getStaticPaths: GetStaticPaths = getCommonStaticPaths type Props = {} & StaticProps; const TermsPage: NextPage = (props): JSX.Element => { - const { locale, lang } = props; + const { locale, lang, customer } = props; console.log('TermsPage props', props); return (

Page: Terms

+

Customer: {customer?.label}

Locale: {locale}
diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 979c22328..5ac942bd3 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -154,7 +154,11 @@ class NRNApp extends NextApp { console.log('_app.render - App is ready, rendering...'); return ( - + ); } else { diff --git a/src/types/StaticProps.ts b/src/types/StaticProps.ts index c23abbedf..4426a1e98 100644 --- a/src/types/StaticProps.ts +++ b/src/types/StaticProps.ts @@ -1,10 +1,13 @@ import { I18nextResources } from '../utils/i18nextLocize'; +import { NormalizedCacheObject } from 'apollo-cache-inmemory'; +import { Customer } from './data/Customer'; /** * Static properties returned by getStaticProps for static pages (using SSG) */ export type StaticProps = { bestCountryCodes: string[]; + customer: Customer; customerRef: string; defaultLocales: I18nextResources; err?: Error; // Only defined if there was an error @@ -14,4 +17,5 @@ export type StaticProps = { lang: string; locale: string; statusCode?: number; + apolloStaticCache: NormalizedCacheObject, }; diff --git a/src/utils/SSG.ts b/src/utils/SSG.ts index 67cbaf659..38c921ad7 100644 --- a/src/utils/SSG.ts +++ b/src/utils/SSG.ts @@ -1,10 +1,14 @@ +import { ApolloQueryResult } from 'apollo-client'; import map from 'lodash.map'; import { GetStaticPaths, GetStaticProps } from 'next'; +import { LAYOUT_QUERY } from '../gql/common/layoutQuery'; import { allowedLocales } from '../i18nConfig'; +import { Customer } from '../types/data/Customer'; import { StaticParams } from '../types/StaticParams'; import { StaticProps } from '../types/StaticProps'; import { prepareGraphCMSLocaleHeader } from './graphcms'; +import { getStandaloneApolloClient } from './graphql'; import { resolveFallbackLanguage } from './i18n'; import { fetchTranslations, I18nextResources } from './i18nextLocize'; @@ -58,15 +62,50 @@ export const getCommonStaticProps: GetStaticProps = a const bestCountryCodes: string[] = [lang, resolveFallbackLanguage(lang)]; const gcmsLocales: string = prepareGraphCMSLocaleHeader(bestCountryCodes); const defaultLocales: I18nextResources = await fetchTranslations(lang); // Pre-fetches translations from Locize API + const apolloClient = getStandaloneApolloClient(); + const variables = { + customerRef, + }; + const queryOptions = { + displayName: 'LAYOUT_QUERY', + query: LAYOUT_QUERY, + variables, + context: { + headers: { + 'gcms-locale': gcmsLocales, + }, + }, + }; + + const { + data, + errors, + loading, + networkStatus, + stale, + }: ApolloQueryResult<{ + customer: Customer; + }> = await apolloClient.query(queryOptions); + + if (errors) { + console.error(errors); + throw new Error('Errors were detected in GraphQL query.'); + } + + const { + customer, + } = data || {}; // XXX Use empty object as fallback, to avoid app crash when destructuring, if no data is returned return { props: { + customer, lang, locale, customerRef, bestCountryCodes, gcmsLocales, defaultLocales, + apolloStaticCache: apolloClient.cache.extract(), isStaticRendering: true, isReadyToRender: true, }, diff --git a/src/utils/graphql.ts b/src/utils/graphql.ts new file mode 100644 index 000000000..276813f4f --- /dev/null +++ b/src/utils/graphql.ts @@ -0,0 +1,27 @@ +import { InMemoryCache, NormalizedCacheObject } from 'apollo-cache-inmemory'; +import { ApolloClient } from 'apollo-client'; +import { createHttpLink } from 'apollo-link-http'; +import fetch from 'isomorphic-unfetch'; + +const link = createHttpLink({ + fetch, // Switches between unfetch & node-fetch for client & server. + uri: process.env.GRAPHQL_API_ENDPOINT, + + // Headers applied here will be applied for all requests + // See the use of the "options" when running a graphQL query to specify options per-request at https://www.apollographql.com/docs/react/api/react-hooks/#options + headers: { + 'gcms-locale-no-default': false, + 'authorization': `Bearer ${process.env.GRAPHQL_API_KEY}`, + }, + credentials: 'same-origin', // XXX See https://www.apollographql.com/docs/react/recipes/authentication#cookie +}); + +export const getStandaloneApolloClient = (initialState = {}): ApolloClient => { + return new ApolloClient({ + link: link, + + // XXX Very important to provide the initialState, otherwise the client will replay the query upon loading, + // which is useless as the data were already fetched by the server (SSR) + cache: new InMemoryCache().restore(initialState || {}), // Rehydrate the cache using the initial data passed from the server + }); +};