mirror of
https://github.com/sergeyyarkov/next-apollo-graphql-setup.git
synced 2026-10-11 10:19:43 +03:00
⚡ fixed SSR
This commit is contained in:
parent
1694936927
commit
63ddaa7f6e
@ -5,10 +5,10 @@ services:
|
|||||||
restart: always
|
restart: always
|
||||||
build: .
|
build: .
|
||||||
ports:
|
ports:
|
||||||
- '3000:3000'
|
- '3000'
|
||||||
# webserver:
|
webserver:
|
||||||
# container_name: webserver
|
container_name: webserver
|
||||||
# restart: unless-stopped
|
restart: unless-stopped
|
||||||
# build: nginx
|
build: nginx
|
||||||
# ports:
|
ports:
|
||||||
# - '80:80'
|
- '80:80'
|
||||||
8
graphql/index.js
Normal file
8
graphql/index.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { makeExecutableSchema } from 'graphql-tools'
|
||||||
|
import { typeDefs } from './typeDefs'
|
||||||
|
import { resolvers } from './resolvers'
|
||||||
|
|
||||||
|
export const schema = makeExecutableSchema({
|
||||||
|
typeDefs,
|
||||||
|
resolvers
|
||||||
|
})
|
||||||
151
lib/apollo.js
151
lib/apollo.js
@ -1,13 +1,148 @@
|
|||||||
import { withData } from 'next-apollo'
|
import React from 'react'
|
||||||
import { HttpLink } from 'apollo-boost'
|
import Head from 'next/head'
|
||||||
|
import { ApolloProvider } from '@apollo/react-hooks'
|
||||||
|
import { ApolloClient } from 'apollo-client'
|
||||||
|
import { InMemoryCache } from 'apollo-cache-inmemory'
|
||||||
|
|
||||||
const config = {
|
let globalApolloClient = null
|
||||||
link: new HttpLink({
|
|
||||||
uri: process.env.GRAPHQL_API_URI,
|
/**
|
||||||
opts: {
|
* Creates and provides the apolloContext
|
||||||
credentials: 'same-origin'
|
* 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 = 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})`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ssr || PageComponent.getInitialProps) {
|
||||||
|
WithApollo.getInitialProps = async ctx => {
|
||||||
|
const { AppTree } = ctx
|
||||||
|
|
||||||
|
// Initialize ApolloClient, add it to the ctx object so
|
||||||
|
// we can use it in `PageComponent.getInitialProp`.
|
||||||
|
const apolloClient = (ctx.apolloClient = initApolloClient())
|
||||||
|
|
||||||
|
// Run wrapped getInitialProps methods
|
||||||
|
let pageProps = {}
|
||||||
|
if (PageComponent.getInitialProps) {
|
||||||
|
pageProps = await PageComponent.getInitialProps(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only on the server:
|
||||||
|
if (typeof window === 'undefined') {
|
||||||
|
// When redirecting, the response is finished.
|
||||||
|
// No point in continuing to render
|
||||||
|
if (ctx.res && ctx.res.finished) {
|
||||||
|
return pageProps
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only if ssr is enabled
|
||||||
|
if (ssr) {
|
||||||
|
try {
|
||||||
|
// Run all GraphQL queries
|
||||||
|
const { getDataFromTree } = await import('@apollo/react-ssr')
|
||||||
|
await 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 (!globalApolloClient) {
|
||||||
|
globalApolloClient = createApolloClient(initialState)
|
||||||
|
}
|
||||||
|
|
||||||
|
return globalApolloClient
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and configures the ApolloClient
|
||||||
|
* @param {Object} [initialState={}]
|
||||||
|
*/
|
||||||
|
function createApolloClient (initialState = {}) {
|
||||||
|
const ssrMode = typeof window === 'undefined'
|
||||||
|
const cache = new InMemoryCache().restore(initialState)
|
||||||
|
|
||||||
|
// Check out https://github.com/zeit/next.js/pull/4611 if you want to use the AWSAppSyncClient
|
||||||
|
return new ApolloClient({
|
||||||
|
ssrMode,
|
||||||
|
link: createIsomorphLink(),
|
||||||
|
cache
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withData(config)
|
function createIsomorphLink () {
|
||||||
|
if (typeof window === 'undefined') {
|
||||||
|
const { SchemaLink } = require('apollo-link-schema')
|
||||||
|
const { schema } = require('../graphql')
|
||||||
|
return new SchemaLink({ schema })
|
||||||
|
} else {
|
||||||
|
const { HttpLink } = require('apollo-link-http')
|
||||||
|
return new HttpLink({
|
||||||
|
uri: '/api/graphql',
|
||||||
|
credentials: 'same-origin'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -9,8 +9,5 @@ module.exports = withSass({
|
|||||||
config.optimization.minimizer.push(new OptimizeCSSAssetsPlugin({}))
|
config.optimization.minimizer.push(new OptimizeCSSAssetsPlugin({}))
|
||||||
|
|
||||||
return config
|
return config
|
||||||
},
|
|
||||||
env: {
|
|
||||||
GRAPHQL_API_URI: 'http://localhost:3000/api/graphql'
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
38
package-lock.json
generated
38
package-lock.json
generated
@ -1911,6 +1911,15 @@
|
|||||||
"tslib": "^1.9.3"
|
"tslib": "^1.9.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"apollo-link-schema": {
|
||||||
|
"version": "1.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/apollo-link-schema/-/apollo-link-schema-1.2.4.tgz",
|
||||||
|
"integrity": "sha512-tLpqd2PSddXJDqA25aERh1U6SsZZBX1isPXSa8FbxvU4Dd8n/DmCOE4mqHyFasgjqLN1zFWL7jgf964LPrAp7A==",
|
||||||
|
"requires": {
|
||||||
|
"apollo-link": "^1.2.13",
|
||||||
|
"tslib": "^1.9.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"apollo-server-caching": {
|
"apollo-server-caching": {
|
||||||
"version": "0.5.1",
|
"version": "0.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/apollo-server-caching/-/apollo-server-caching-0.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/apollo-server-caching/-/apollo-server-caching-0.5.1.tgz",
|
||||||
@ -6932,15 +6941,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
|
||||||
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
|
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
|
||||||
},
|
},
|
||||||
"isomorphic-unfetch": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/isomorphic-unfetch/-/isomorphic-unfetch-3.0.0.tgz",
|
|
||||||
"integrity": "sha512-V0tmJSYfkKokZ5mgl0cmfQMTb7MLHsBMngTkbLY0eXvKqiVRRoZP04Ly+KhKrJfKtzC9E6Pp15Jo+bwh7Vi2XQ==",
|
|
||||||
"requires": {
|
|
||||||
"node-fetch": "^2.2.0",
|
|
||||||
"unfetch": "^4.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"isstream": {
|
"isstream": {
|
||||||
"version": "0.1.2",
|
"version": "0.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
|
||||||
@ -8214,31 +8214,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"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",
|
||||||
"integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw="
|
"integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw="
|
||||||
},
|
},
|
||||||
"next-with-apollo": {
|
|
||||||
"version": "5.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/next-with-apollo/-/next-with-apollo-5.0.0.tgz",
|
|
||||||
"integrity": "sha512-JcMecKv6XtzsLf1hPKrbxM6g9sygnGdQugglmCDkfWhHZt1yziPa+g515qtw7in8A7Ed5W9PdaaaUn7CWWQ71w==",
|
|
||||||
"requires": {
|
|
||||||
"isomorphic-unfetch": "^3.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nice-try": {
|
"nice-try": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
|
||||||
|
|||||||
@ -12,12 +12,11 @@
|
|||||||
"@apollo/react-ssr": "^3.1.3",
|
"@apollo/react-ssr": "^3.1.3",
|
||||||
"@zeit/next-sass": "^1.0.1",
|
"@zeit/next-sass": "^1.0.1",
|
||||||
"apollo-boost": "^0.4.7",
|
"apollo-boost": "^0.4.7",
|
||||||
|
"apollo-link-schema": "^1.2.4",
|
||||||
"apollo-server-micro": "^2.10.1",
|
"apollo-server-micro": "^2.10.1",
|
||||||
"graphql-tag": "^2.10.3",
|
"graphql-tag": "^2.10.3",
|
||||||
"isomorphic-unfetch": "^3.0.0",
|
"graphql-tools": "^4.0.7",
|
||||||
"next": "9.2.2",
|
"next": "9.2.2",
|
||||||
"next-apollo": "^3.1.10",
|
|
||||||
"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",
|
||||||
"react": "16.13.0",
|
"react": "16.13.0",
|
||||||
|
|||||||
@ -1,9 +1,7 @@
|
|||||||
const { ApolloServer, gql } = require('apollo-server-micro')
|
import { ApolloServer } from 'apollo-server-micro'
|
||||||
const { typeDefs } = require('../../graphql/typeDefs')
|
import { schema } from '../../graphql'
|
||||||
const { resolvers } = require('../../graphql/resolvers')
|
|
||||||
|
|
||||||
const apolloServer = new ApolloServer({ typeDefs, resolvers })
|
const apolloServer = new ApolloServer({ schema })
|
||||||
const handler = apolloServer.createHandler({ path: '/api/graphql' })
|
|
||||||
|
|
||||||
export const config = { api: { bodyParser: false } }
|
export const config = { api: { bodyParser: false } }
|
||||||
export default handler
|
export default apolloServer.createHandler({ path: '/api/graphql' })
|
||||||
|
|||||||
@ -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 withData from '../lib/apollo'
|
import { withApollo } from '../lib/apollo'
|
||||||
|
|
||||||
const Articles = () => {
|
const Articles = () => {
|
||||||
return (
|
return (
|
||||||
@ -31,4 +31,4 @@ const Articles = () => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withData(Articles)
|
export default withApollo(Articles)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user