🔧 next-apollo package

This commit is contained in:
Sergey Yarkov 2020-03-03 21:17:24 +03:00
parent c5fb489720
commit f1e672cb4c
6 changed files with 84 additions and 132 deletions

View File

@ -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 = () => {

View File

@ -10,6 +10,10 @@ const SEO = props => {
return (
<Head>
<title>{pageTitle}</title>
<meta
name="description"
content="-"
/>
</Head>
)
}

View File

@ -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
View File

@ -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",

View File

@ -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",

View File

@ -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)