The Fade Room
Project Under Active Construction, check back for Updates
Custom Headless WordPress build for a business located in Highland Park, IL.
Technical Details
Private Repository, Contact me for Details
@graphql-codegen/*
was utilized in this project to generate types from .graphql
files by configuring a .codegen.yml
file. Initializing apollo and wrapping getStaticProps with an addApolloState provider implicitly passes GetStaticPropsResult
props into its global state/cache. This allows for types to be 100% inferred on the client function using InferGetStaticPropsType
via this server-to-client shuttle.
# .codegen.yml
overwrite: true
schema:
${WORDPRESS_API_URL_YML}:
headers:
Authorization: Bearer ${WORDPRESS_AUTH_REFRESH_TOKEN_YML}
documents: 'graphql/**/*.graphql'
generates:
graphql/generated/graphql.tsx:
plugins:
- typescript:
constEnums: false
enumsAsTypes: false
numericEnums: false
futureProofEnums: false
enumsAsConst: false
onlyOperationTypes: false
maybeValue: T | null | undefined
noExport: false
enumPrefix: true
fieldWrapperValue: T
wrapFieldDefinitions: true
skipTypename: false
nonOptionalTypename: false
useTypeImports: false
avoidOptionals: true
declarationKind:
input: interface
type: interface
- typescript-operations:
declarationKind:
input: interface
type: interface
avoidOptionals: true
exportFragmentSpreadSubTypes: true
- typescript-react-apollo:
addDocBlocks: true
reactApolloVersion: 3
documentMode: documentNodeImportFragments
config:
maybeValue: T | null | undefined
declarationKind:
input: interface
type: interface
documentNodeImportFragments: true
reactApolloVersion: 3
withHooks: true
withHOC: false
avoidOptionals: true
withComponent: false
exportFragmentSpreadSubTypes: true
addDocBlocks: true
graphql/graphql.schema.graphql:
plugins:
- schema-ast
config:
commentDescriptions: true
graphql/graphql.schema.json:
plugins:
- introspection
config:
commentDescriptions: true
hooks:
afterAllFileWrite:
- prettier --write
// pages/index.tsx
import { Container } from '@/components/UI';
import { initializeApollo, addApolloState } from '@/lib/apollo';
import {
LandingPage,
LandingPageWrapper
} from '@/components/Landing';
import ServiceTopCoalesced from '@/components/ServicesTop/services-top-coalesced';
import AppLayout from '@/components/Layout/layout';
import {
GetStaticPropsContext,
GetStaticPropsResult,
InferGetStaticPropsType
} from 'next';
import {
ServicesTopQuery,
ServicesTopQueryVariables,
ServicesTopDocument,
DynamicNavDocument,
DynamicNavQueryVariables,
DynamicNavQuery,
MenuNodeIdTypeEnum
} from '@/graphql/generated/graphql';
export function Index({
other,
popular,
Header,
Footer
}: InferGetStaticPropsType<typeof getStaticProps>) {
return (
<>
<AppLayout Header={Header} Footer={Footer}>
<Container className='fit'>
<LandingPageWrapper>
<LandingPage services={<></>}></LandingPage>
<ServiceTopCoalesced other={other} popular={popular} />
</LandingPageWrapper>
</Container>
</AppLayout>
</>
);
}
export async function getStaticProps(
ctx: GetStaticPropsContext
): Promise<
GetStaticPropsResult<{
other: ServicesTopQuery['other'];
popular: ServicesTopQuery['popular'];
Header: DynamicNavQuery['Header'];
Footer: DynamicNavQuery['Footer'];
}>
> {
const apolloClient = initializeApollo();
await apolloClient.query<
DynamicNavQuery,
DynamicNavQueryVariables
>({
query: DynamicNavDocument,
variables: {
idHead: 'Header',
idTypeHead: MenuNodeIdTypeEnum.Name,
idFoot: 'Footer',
idTypeFoot: MenuNodeIdTypeEnum.Name
}
});
await apolloClient.query<
ServicesTopQuery,
ServicesTopQueryVariables
>({
query: ServicesTopDocument,
variables: {
other: 'all',
popular: 'popular-service'
}
});
return addApolloState(apolloClient, {
props: {},
revalidate: 10
});
}
export default Index;
This logic is extended to _app.tsx
for NextApp.getInitialProps
and is subject to updates as fine details are pinned down. Why feed _app DynamicNav props? To feed the global ApolloProvider globally utilized props for consumption on the very first render before the DOM is loaded to bolster performance and enhance UX.
// _app.tsx
import '@/styles/index.css';
import '@/styles/chrome-bug.css';
import 'keen-slider/keen-slider.min.css';
import App, {
AppContext,
AppInitialProps,
AppProps,
NextWebVitalsMetric
} from 'next/app';
import { useRouter } from 'next/router';
import { ApolloProvider } from '@apollo/client';
import { useEffect, FC } from 'react';
import {
useApollo,
initializeApollo,
addApolloState
} from '@/lib/apollo';
import * as gtag from '@/lib/analytics';
import { MediaContextProvider } from '@/lib/artsy-fresnel';
import { Head } from '@/components/Head';
import { GTagPageview } from '@/types/analytics';
import {
DynamicNavQuery,
DynamicNavQueryVariables,
DynamicNavDocument,
MenuNodeIdTypeEnum
} from '@/graphql/generated/graphql';
const Noop: FC = ({ children }) => <>{children}</>;
function NextApp({
Component,
pageProps
}: AppProps<typeof NextApp.getInitialProps>) {
const apolloClient = useApollo(pageProps);
const LayoutNoop = (Component as any).LayoutNoop || Noop;
const router = useRouter();
useEffect(() => {
document.body.classList?.remove('loading');
}, []);
useEffect(() => {
const handleRouteChange = (url: GTagPageview) => {
gtag.pageview(url);
};
router.events.on('routeChangeComplete', handleRouteChange);
return () => {
router.events.off('routeChangeComplete', handleRouteChange);
};
}, [router.events]);
console.log(useApollo(pageProps));
return (
<>
<Head />
<ApolloProvider client={apolloClient}>
<MediaContextProvider>
<LayoutNoop pageProps={pageProps}>
<Component {...pageProps} />
</LayoutNoop>
</MediaContextProvider>
</ApolloProvider>
</>
);
}
NextApp.getInitialProps = async (
appContext: AppContext
): Promise<AppInitialProps> => {
const pageProps = await App.getInitialProps(appContext);
const graphqlClient = initializeApollo();
const dynamicNav = await graphqlClient.query<
DynamicNavQuery,
DynamicNavQueryVariables
>({
query: DynamicNavDocument,
variables: {
idHead: 'Header',
idTypeHead: MenuNodeIdTypeEnum.Name,
idFoot: 'Footer',
idTypeFoot: MenuNodeIdTypeEnum.Name
}
});
return addApolloState(graphqlClient, {
pageProps: {
...pageProps.pageProps,
Header: dynamicNav.data.Header,
Footer: dynamicNav.data.Footer
}
});
};
export function reportWebVitals(metric: NextWebVitalsMetric) {
console.debug(metric);
}
export default NextApp;