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>
|
</Query>
|
||||||
```
|
```
|
||||||
|
|
||||||
Use the `withApollo` HOC to wrap your pages.
|
Use the `withData` HOC to wrap your pages.
|
||||||
```jsx
|
```jsx
|
||||||
|
|
||||||
// ./frontend/pages/articles.js
|
// ./frontend/pages/articles.js
|
||||||
@ -32,7 +32,7 @@ import Layout from '../components/Layout/Layout'
|
|||||||
import SEO from '../components/SEO/SEO'
|
import SEO from '../components/SEO/SEO'
|
||||||
import Query from '../components/Query/query'
|
import Query from '../components/Query/query'
|
||||||
import ARTICLES_QUERY from '../apollo/queries/articles/articles';
|
import ARTICLES_QUERY from '../apollo/queries/articles/articles';
|
||||||
import { withApollo } from '../lib/apollo';
|
import withData from '../lib/apollo';
|
||||||
|
|
||||||
|
|
||||||
const Articles = () => {
|
const Articles = () => {
|
||||||
|
|||||||
@ -10,6 +10,10 @@ const SEO = props => {
|
|||||||
return (
|
return (
|
||||||
<Head>
|
<Head>
|
||||||
<title>{pageTitle}</title>
|
<title>{pageTitle}</title>
|
||||||
|
<meta
|
||||||
|
name="description"
|
||||||
|
content="-"
|
||||||
|
/>
|
||||||
</Head>
|
</Head>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
137
lib/apollo.js
137
lib/apollo.js
@ -1,132 +1,13 @@
|
|||||||
import React, { useMemo } from 'react'
|
import { withData } from 'next-apollo'
|
||||||
import Head from 'next/head'
|
import { HttpLink } from 'apollo-boost'
|
||||||
import { ApolloProvider } from '@apollo/react-hooks'
|
|
||||||
import { ApolloClient, InMemoryCache, HttpLink } from 'apollo-boost'
|
|
||||||
import fetch from 'isomorphic-unfetch'
|
|
||||||
|
|
||||||
const GRAPHQL_URL = process.env.BACKEND_URL || 'http://localhost:3000/api/graphql'
|
const config = {
|
||||||
|
link: new HttpLink({
|
||||||
let apolloClient = null
|
uri: 'http://localhost:3000/api/graphql',
|
||||||
|
opts: {
|
||||||
/**
|
credentials: 'same-origin'
|
||||||
* 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)
|
|
||||||
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)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default withData(config)
|
||||||
|
|||||||
65
package-lock.json
generated
65
package-lock.json
generated
@ -2038,6 +2038,16 @@
|
|||||||
"sprintf-js": "~1.0.2"
|
"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": {
|
"arity-n": {
|
||||||
"version": "1.0.4",
|
"version": "1.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/arity-n/-/arity-n-1.0.4.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.2.tgz",
|
||||||
"integrity": "sha512-uWMHxJxtfj/1oZClOxDEV1sQ1HCDkA4MG8Gr69KKeBjEVH0R84WlejZ0y2DcwyBlpAEMltmVYkVgqfLFb2oyiA=="
|
"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": {
|
"astral-regex": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz",
|
||||||
"integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug=="
|
"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": {
|
"babel-code-frame": {
|
||||||
"version": "6.26.0",
|
"version": "6.26.0",
|
||||||
"resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
|
"resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
|
||||||
@ -4146,6 +4168,12 @@
|
|||||||
"type": "^1.0.1"
|
"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": {
|
"dashdash": {
|
||||||
"version": "1.14.1",
|
"version": "1.14.1",
|
||||||
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
|
"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": {
|
"eslint-plugin-node": {
|
||||||
"version": "11.0.0",
|
"version": "11.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.0.0.tgz",
|
"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": {
|
"next-tick": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz",
|
||||||
|
|||||||
@ -16,6 +16,7 @@
|
|||||||
"graphql-tag": "^2.10.3",
|
"graphql-tag": "^2.10.3",
|
||||||
"isomorphic-unfetch": "^3.0.0",
|
"isomorphic-unfetch": "^3.0.0",
|
||||||
"next": "9.2.2",
|
"next": "9.2.2",
|
||||||
|
"next-apollo": "^3.1.10",
|
||||||
"next-with-apollo": "^5.0.0",
|
"next-with-apollo": "^5.0.0",
|
||||||
"node-sass": "^4.13.1",
|
"node-sass": "^4.13.1",
|
||||||
"optimize-css-assets-webpack-plugin": "^5.0.3",
|
"optimize-css-assets-webpack-plugin": "^5.0.3",
|
||||||
@ -27,6 +28,7 @@
|
|||||||
"eslint-config-node": "^4.0.0",
|
"eslint-config-node": "^4.0.0",
|
||||||
"eslint-config-standard-jsx": "^8.1.0",
|
"eslint-config-standard-jsx": "^8.1.0",
|
||||||
"eslint-plugin-import": "^2.20.1",
|
"eslint-plugin-import": "^2.20.1",
|
||||||
|
"eslint-plugin-jsx-a11y": "^6.2.3",
|
||||||
"eslint-plugin-node": "^11.0.0",
|
"eslint-plugin-node": "^11.0.0",
|
||||||
"eslint-plugin-promise": "^4.2.1",
|
"eslint-plugin-promise": "^4.2.1",
|
||||||
"eslint-plugin-react": "^7.18.3",
|
"eslint-plugin-react": "^7.18.3",
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import Layout from '../components/Layout/Layout'
|
|||||||
import SEO from '../components/SEO/SEO'
|
import SEO from '../components/SEO/SEO'
|
||||||
import Query from '../components/Query/query'
|
import Query from '../components/Query/query'
|
||||||
import ARTICLES_QUERY from '../apollo/queries/articles/articles'
|
import ARTICLES_QUERY from '../apollo/queries/articles/articles'
|
||||||
import { withApollo } from '../lib/apollo'
|
import withData from '../lib/apollo'
|
||||||
|
|
||||||
const Articles = () => {
|
const Articles = () => {
|
||||||
return (
|
return (
|
||||||
@ -31,4 +31,4 @@ const Articles = () => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withApollo(Articles)
|
export default withData(Articles)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user