mirror of
https://github.com/sergeyyarkov/next-apollo-graphql-setup.git
synced 2026-10-11 10:19:43 +03:00
🔧 next-apollo package
This commit is contained in:
parent
c5fb489720
commit
f1e672cb4c
@ -24,7 +24,7 @@ You can easily use `Query` component to send queries to the GraphQL server. Just
|
||||
</Query>
|
||||
```
|
||||
|
||||
Use the `withApollo` HOC to wrap your pages.
|
||||
Use the `withData` HOC to wrap your pages.
|
||||
```jsx
|
||||
|
||||
// ./frontend/pages/articles.js
|
||||
@ -32,7 +32,7 @@ import Layout from '../components/Layout/Layout'
|
||||
import SEO from '../components/SEO/SEO'
|
||||
import Query from '../components/Query/query'
|
||||
import ARTICLES_QUERY from '../apollo/queries/articles/articles';
|
||||
import { withApollo } from '../lib/apollo';
|
||||
import withData from '../lib/apollo';
|
||||
|
||||
|
||||
const Articles = () => {
|
||||
|
||||
@ -10,6 +10,10 @@ const SEO = props => {
|
||||
return (
|
||||
<Head>
|
||||
<title>{pageTitle}</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="-"
|
||||
/>
|
||||
</Head>
|
||||
)
|
||||
}
|
||||
|
||||
137
lib/apollo.js
137
lib/apollo.js
@ -1,132 +1,13 @@
|
||||
import React, { useMemo } from 'react'
|
||||
import Head from 'next/head'
|
||||
import { ApolloProvider } from '@apollo/react-hooks'
|
||||
import { ApolloClient, InMemoryCache, HttpLink } from 'apollo-boost'
|
||||
import fetch from 'isomorphic-unfetch'
|
||||
import { withData } from 'next-apollo'
|
||||
import { HttpLink } from 'apollo-boost'
|
||||
|
||||
const GRAPHQL_URL = process.env.BACKEND_URL || 'http://localhost:3000/api/graphql'
|
||||
|
||||
let apolloClient = null
|
||||
|
||||
/**
|
||||
* Creates and provides the apolloContext
|
||||
* to a next.js PageTree. Use it by wrapping
|
||||
* your PageComponent via HOC pattern.
|
||||
* @param {Function|Class} PageComponent
|
||||
* @param {Object} [config]
|
||||
* @param {Boolean} [config.ssr=true]
|
||||
*/
|
||||
export function withApollo (PageComponent, { ssr = true } = {}) {
|
||||
const WithApollo = ({ apolloClient, apolloState, ...pageProps }) => {
|
||||
const client = useMemo(
|
||||
() => apolloClient || initApolloClient(apolloState),
|
||||
[]
|
||||
)
|
||||
return (
|
||||
<ApolloProvider client={client}>
|
||||
<PageComponent {...pageProps} />
|
||||
</ApolloProvider>
|
||||
)
|
||||
}
|
||||
|
||||
// Set the correct displayName in development
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
const displayName =
|
||||
PageComponent.displayName || PageComponent.name || 'Component'
|
||||
|
||||
if (displayName === 'App') {
|
||||
console.warn('This withApollo HOC only works with PageComponents.')
|
||||
}
|
||||
|
||||
WithApollo.displayName = `withApollo(${displayName})`
|
||||
}
|
||||
|
||||
// Allow Next.js to remove getInitialProps from the browser build
|
||||
if (typeof window === 'undefined') {
|
||||
if (ssr) {
|
||||
WithApollo.getInitialProps = async ctx => {
|
||||
const { AppTree } = ctx
|
||||
|
||||
let pageProps = {}
|
||||
if (PageComponent.getInitialProps) {
|
||||
pageProps = await PageComponent.getInitialProps(ctx)
|
||||
}
|
||||
|
||||
// Run all GraphQL queries in the component tree
|
||||
// and extract the resulting data
|
||||
const apolloClient = initApolloClient()
|
||||
|
||||
try {
|
||||
// Run all GraphQL queries
|
||||
await require('@apollo/react-ssr').getDataFromTree(
|
||||
<AppTree
|
||||
pageProps={{
|
||||
...pageProps,
|
||||
apolloClient
|
||||
}}
|
||||
/>
|
||||
)
|
||||
} catch (error) {
|
||||
// Prevent Apollo Client GraphQL errors from crashing SSR.
|
||||
// Handle them in components via the data.error prop:
|
||||
// https://www.apollographql.com/docs/react/api/react-apollo.html#graphql-query-data-error
|
||||
console.error('Error while running `getDataFromTree`', error)
|
||||
}
|
||||
|
||||
// getDataFromTree does not call componentWillUnmount
|
||||
// head side effect therefore need to be cleared manually
|
||||
Head.rewind()
|
||||
|
||||
// Extract query data from the Apollo store
|
||||
const apolloState = apolloClient.cache.extract()
|
||||
|
||||
return {
|
||||
...pageProps,
|
||||
apolloState
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return WithApollo
|
||||
}
|
||||
|
||||
/**
|
||||
* Always creates a new apollo client on the server
|
||||
* Creates or reuses apollo client in the browser.
|
||||
* @param {Object} initialState
|
||||
*/
|
||||
function initApolloClient (initialState) {
|
||||
// Make sure to create a new client for every server-side request so that data
|
||||
// isn't shared between connections (which would be bad)
|
||||
if (typeof window === 'undefined') {
|
||||
return createApolloClient(initialState)
|
||||
}
|
||||
|
||||
// Reuse client on the client-side
|
||||
if (!apolloClient) {
|
||||
apolloClient = createApolloClient(initialState)
|
||||
}
|
||||
|
||||
return apolloClient
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and configures the ApolloClient
|
||||
* @param {Object} [initialState={}]
|
||||
*/
|
||||
function createApolloClient (initialState = {}) {
|
||||
// Check out https://github.com/zeit/next.js/pull/4611 if you want to use the AWSAppSyncClient
|
||||
const isBrowser = typeof window !== 'undefined'
|
||||
return new ApolloClient({
|
||||
connectToDevTools: isBrowser,
|
||||
ssrMode: !isBrowser, // Disables forceFetch on the server (so queries are only run once)
|
||||
const config = {
|
||||
link: new HttpLink({
|
||||
uri: GRAPHQL_URL, // Server URL (must be absolute)
|
||||
credentials: 'same-origin', // Additional fetch() options like `credentials` or `headers`
|
||||
// Use fetch() polyfill on the server
|
||||
fetch: !isBrowser && fetch
|
||||
}),
|
||||
cache: new InMemoryCache().restore(initialState)
|
||||
uri: 'http://localhost:3000/api/graphql',
|
||||
opts: {
|
||||
credentials: 'same-origin'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export default withData(config)
|
||||
|
||||
65
package-lock.json
generated
65
package-lock.json
generated
@ -2038,6 +2038,16 @@
|
||||
"sprintf-js": "~1.0.2"
|
||||
}
|
||||
},
|
||||
"aria-query": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz",
|
||||
"integrity": "sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ast-types-flow": "0.0.7",
|
||||
"commander": "^2.11.0"
|
||||
}
|
||||
},
|
||||
"arity-n": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/arity-n/-/arity-n-1.0.4.tgz",
|
||||
@ -2148,6 +2158,12 @@
|
||||
"resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.2.tgz",
|
||||
"integrity": "sha512-uWMHxJxtfj/1oZClOxDEV1sQ1HCDkA4MG8Gr69KKeBjEVH0R84WlejZ0y2DcwyBlpAEMltmVYkVgqfLFb2oyiA=="
|
||||
},
|
||||
"ast-types-flow": {
|
||||
"version": "0.0.7",
|
||||
"resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz",
|
||||
"integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=",
|
||||
"dev": true
|
||||
},
|
||||
"astral-regex": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz",
|
||||
@ -2294,6 +2310,12 @@
|
||||
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz",
|
||||
"integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug=="
|
||||
},
|
||||
"axobject-query": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.1.2.tgz",
|
||||
"integrity": "sha512-ICt34ZmrVt8UQnvPl6TVyDTkmhXmAyAT4Jh5ugfGUX4MOrZ+U/ZY6/sdylRw3qGNr9Ub5AJsaHeDMzNLehRdOQ==",
|
||||
"dev": true
|
||||
},
|
||||
"babel-code-frame": {
|
||||
"version": "6.26.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
|
||||
@ -4146,6 +4168,12 @@
|
||||
"type": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"damerau-levenshtein": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.6.tgz",
|
||||
"integrity": "sha512-JVrozIeElnj3QzfUIt8tB8YMluBJom4Vw9qTPpjGYQ9fYlB3D/rb6OordUxf3xeFB35LKWs0xqcO5U6ySvBtug==",
|
||||
"dev": true
|
||||
},
|
||||
"dashdash": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
|
||||
@ -5305,6 +5333,31 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"eslint-plugin-jsx-a11y": {
|
||||
"version": "6.2.3",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.2.3.tgz",
|
||||
"integrity": "sha512-CawzfGt9w83tyuVekn0GDPU9ytYtxyxyFZ3aSWROmnRRFQFT2BiPJd7jvRdzNDi6oLWaS2asMeYSNMjWTV4eNg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.4.5",
|
||||
"aria-query": "^3.0.0",
|
||||
"array-includes": "^3.0.3",
|
||||
"ast-types-flow": "^0.0.7",
|
||||
"axobject-query": "^2.0.2",
|
||||
"damerau-levenshtein": "^1.0.4",
|
||||
"emoji-regex": "^7.0.2",
|
||||
"has": "^1.0.3",
|
||||
"jsx-ast-utils": "^2.2.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"emoji-regex": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
|
||||
"integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"eslint-plugin-node": {
|
||||
"version": "11.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.0.0.tgz",
|
||||
@ -8161,6 +8214,18 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"next-apollo": {
|
||||
"version": "3.1.10",
|
||||
"resolved": "https://registry.npmjs.org/next-apollo/-/next-apollo-3.1.10.tgz",
|
||||
"integrity": "sha512-VX64IW7h6Rdg+Ma0y8ryAIz7IfyLaz6Nd4VITuhfXFZ3nj51blcjRR6kc4E945SPk2WdrIMlLRZubgPRAgh9Ug==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.4.5",
|
||||
"isomorphic-unfetch": "^3.0.0",
|
||||
"prop-types": "15.7.2",
|
||||
"prop-types-exact": "1.2.0",
|
||||
"url": "0.11.0"
|
||||
}
|
||||
},
|
||||
"next-tick": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz",
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
"graphql-tag": "^2.10.3",
|
||||
"isomorphic-unfetch": "^3.0.0",
|
||||
"next": "9.2.2",
|
||||
"next-apollo": "^3.1.10",
|
||||
"next-with-apollo": "^5.0.0",
|
||||
"node-sass": "^4.13.1",
|
||||
"optimize-css-assets-webpack-plugin": "^5.0.3",
|
||||
@ -27,6 +28,7 @@
|
||||
"eslint-config-node": "^4.0.0",
|
||||
"eslint-config-standard-jsx": "^8.1.0",
|
||||
"eslint-plugin-import": "^2.20.1",
|
||||
"eslint-plugin-jsx-a11y": "^6.2.3",
|
||||
"eslint-plugin-node": "^11.0.0",
|
||||
"eslint-plugin-promise": "^4.2.1",
|
||||
"eslint-plugin-react": "^7.18.3",
|
||||
|
||||
@ -2,7 +2,7 @@ import Layout from '../components/Layout/Layout'
|
||||
import SEO from '../components/SEO/SEO'
|
||||
import Query from '../components/Query/query'
|
||||
import ARTICLES_QUERY from '../apollo/queries/articles/articles'
|
||||
import { withApollo } from '../lib/apollo'
|
||||
import withData from '../lib/apollo'
|
||||
|
||||
const Articles = () => {
|
||||
return (
|
||||
@ -31,4 +31,4 @@ const Articles = () => {
|
||||
)
|
||||
}
|
||||
|
||||
export default withApollo(Articles)
|
||||
export default withData(Articles)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user