Skip to content

Instantly share code, notes, and snippets.

@OutThisLife
Last active September 28, 2022 15:04
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save OutThisLife/587f6fc89f72fc3345b1d44880c8ae70 to your computer and use it in GitHub Desktop.
Save OutThisLife/587f6fc89f72fc3345b1d44880c8ae70 to your computer and use it in GitHub Desktop.
import withData from '@/lib/withData'
import { ApolloClient } from 'apollo-boost'
import App, { AppProps, Container } from 'next/app'
import { ApolloProvider } from 'react-apollo'
export default withData(
class extends App<MyAppProps> {
public static async getInitialProps({ Component, ...ctx }) {
let pageProps = {}
if (Component.getInitialProps) {
pageProps = await Component.getInitialProps(ctx)
}
return { pageProps }
}
public render() {
const { client } = this.props
return (
<ApolloProvider client={client}>
<Container>
<Component {...this.props} />
</Container>
</ApolloProvider>
)
}
}
)
export interface MyAppProps extends AppProps {
client: ApolloClient<{}>
}
import 'isomorphic-unfetch'
import { ApolloClient, ApolloLink, InMemoryCache } from 'apollo-boost'
import { onError } from 'apollo-link-error'
import { createHttpLink } from 'apollo-link-http'
import { createPersistedQueryLink } from 'apollo-link-persisted-queries'
import { toIdValue } from 'apollo-utilities'
import getConfig from 'next/config'
const {
publicRuntimeConfig: { API_URL, isDev }
} = getConfig()
// -------------------------------------
const errorLink = () =>
onError(({ graphQLErrors, networkError }) => {
if (graphQLErrors) {
graphQLErrors.map(
({ message, locations, path }) =>
isDev &&
console.error(
`[GraphQL error]: Message: ${message}, Location: ${JSON.stringify(
locations
)}, Path: ${path}`
)
)
}
if (networkError && isDev) {
console.error('[Network error]', networkError)
}
})
const httpLink = () =>
createPersistedQueryLink().concat(
createHttpLink({
uri: API_URL,
credentials: 'same-origin'
})
)
// -------------------------------------
let client
const createCache = () => {
const redir = typeName => (_, args = {}) =>
toIdValue(
cache.config.dataIdFromObject({
__typename: typeName,
...args
})
)
const cache = new InMemoryCache({
dataIdFromObject: o => (o.id ? `${o.__typename}:${o.id}` : null),
cacheRedirects: {
Query: {}
}
})
return cache
}
const create = (initialState = {}) => {
const cache = createCache().restore(initialState)
const link = ApolloLink.from([errorLink(), httpLink()])
return new ApolloClient({
link,
cache,
ssrMode: !('browser' in process),
connectToDevTools: 'browser' in process && isDev
})
}
export default (initialState = {}) => {
if (!('browser' in process)) {
return create(initialState)
}
if (!client) {
client = create(
initialState || (window as any).__NEXT_DATA__.props.apolloState
)
}
return client
}
const dev = process.env.NODE_ENV !== 'production'
if (dev) {
require('dotenv').config()
}
const withPlugins = require('next-compose-plugins')
const typescript = require('@zeit/next-typescript')
const offline = require('next-offline')
const withCSS = require('@zeit/next-css')
const { PHASE_DEVELOPMENT_SERVER } = require('next/constants')
module.exports = withPlugins(
[
withCSS,
typescript,
[
offline,
{
workboxOpts: {
runtimeCaching: [
{
urlPattern: /\.([A-z]{2,4})$/,
handler: 'cacheFirst'
},
{
urlPattern: /graphql$/,
handler: 'networkFirst',
options: {
cacheableResponse: {
statuses: [0, 200]
}
}
}
]
}
},
['!', PHASE_DEVELOPMENT_SERVER]
]
],
{
useFileSystemPublicRoutes: false,
publicRuntimeConfig: {
isDev: dev,
API_URL: `http://localhost:${process.env.PORT || 3000}/graphql`
},
webpack: config => {
config.module.rules.push({
test: /\.(png|jpg|gif|svg|eot|ttf|otf|woff|woff2)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 10000
}
}
]
})
return config
},
exportPathMap: async () => ({
'/': { page: '/Home', query: {} }
})
}
)
import ApolloClient from 'apollo-client'
import Head from 'next/head'
import { Component } from 'react'
import { getDataFromTree } from 'react-apollo'
import { getDisplayName } from 'recompose'
import initApollo from './initApollo'
export default App =>
class extends Component<{ serverState: any }> {
public static displayName = `withApollo(${getDisplayName(App)})`
public static async getInitialProps(ctx) {
let serverState = {}
const pageProps: any = {}
try {
const client = initApollo()
await getDataFromTree(
<App
client={client}
router={ctx.router}
Component={ctx.Component}
/>,
ctx
)
serverState = client.cache.extract() || {}
if (!('browser' in process)) {
const {
ctx: { req }
} = ctx
pageProps.headers = req.headers
Head.rewind()
}
} catch (err) {
console.error('Error while running `getDataFromTree`', err)
err.code = 'ENOENT'
throw err
}
return { pageProps, serverState }
}
private client: ApolloClient<{}>
constructor(props) {
super(props)
this.client = initApollo(this.props.serverState)
}
public render() {
const { serverState, ...props } = this.props
return <App client={this.client} {...props} />
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment