mirror of
https://github.com/sergeyyarkov/next-apollo-graphql-setup.git
synced 2026-10-11 02:09:23 +03:00
⚡ fixed SSR
This commit is contained in:
parent
1694936927
commit
63ddaa7f6e
@ -5,10 +5,10 @@ services:
|
||||
restart: always
|
||||
build: .
|
||||
ports:
|
||||
- '3000:3000'
|
||||
# webserver:
|
||||
# container_name: webserver
|
||||
# restart: unless-stopped
|
||||
# build: nginx
|
||||
# ports:
|
||||
# - '80:80'
|
||||
- '3000'
|
||||
webserver:
|
||||
container_name: webserver
|
||||
restart: unless-stopped
|
||||
build: nginx
|
||||
ports:
|
||||
- '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 { HttpLink } from 'apollo-boost'
|
||||
import React from 'react'
|
||||
import Head from 'next/head'
|
||||
import { ApolloProvider } from '@apollo/react-hooks'
|
||||
import { ApolloClient } from 'apollo-client'
|
||||
import { InMemoryCache } from 'apollo-cache-inmemory'
|
||||
|
||||
const config = {
|
||||
link: new HttpLink({
|
||||
uri: process.env.GRAPHQL_API_URI,
|
||||
opts: {
|
||||
credentials: 'same-origin'
|
||||
let globalApolloClient = 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 = 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({}))
|
||||
|
||||
return config
|
||||
},
|
||||
env: {
|
||||
GRAPHQL_API_URI: 'http://localhost:3000/api/graphql'
|
||||
}
|
||||
})
|
||||
|
||||
@ -2,4 +2,4 @@ FROM nginx
|
||||
|
||||
RUN rm /etc/nginx/conf.d/default.conf
|
||||
|
||||
COPY default.conf /etc/nginx/conf.d/
|
||||
COPY default.conf /etc/nginx/conf.d/
|
||||
|
||||
38
package-lock.json
generated
38
package-lock.json
generated
@ -1911,6 +1911,15 @@
|
||||
"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": {
|
||||
"version": "0.5.1",
|
||||
"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",
|
||||
"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": {
|
||||
"version": "0.1.2",
|
||||
"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": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz",
|
||||
"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": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
|
||||
|
||||
@ -12,12 +12,11 @@
|
||||
"@apollo/react-ssr": "^3.1.3",
|
||||
"@zeit/next-sass": "^1.0.1",
|
||||
"apollo-boost": "^0.4.7",
|
||||
"apollo-link-schema": "^1.2.4",
|
||||
"apollo-server-micro": "^2.10.1",
|
||||
"graphql-tag": "^2.10.3",
|
||||
"isomorphic-unfetch": "^3.0.0",
|
||||
"graphql-tools": "^4.0.7",
|
||||
"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",
|
||||
"react": "16.13.0",
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
const { ApolloServer, gql } = require('apollo-server-micro')
|
||||
const { typeDefs } = require('../../graphql/typeDefs')
|
||||
const { resolvers } = require('../../graphql/resolvers')
|
||||
import { ApolloServer } from 'apollo-server-micro'
|
||||
import { schema } from '../../graphql'
|
||||
|
||||
const apolloServer = new ApolloServer({ typeDefs, resolvers })
|
||||
const handler = apolloServer.createHandler({ path: '/api/graphql' })
|
||||
const apolloServer = new ApolloServer({ schema })
|
||||
|
||||
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 Query from '../components/Query/query'
|
||||
import ARTICLES_QUERY from '../apollo/queries/articles/articles'
|
||||
import withData from '../lib/apollo'
|
||||
import { withApollo } from '../lib/apollo'
|
||||
|
||||
const Articles = () => {
|
||||
return (
|
||||
@ -31,4 +31,4 @@ const Articles = () => {
|
||||
)
|
||||
}
|
||||
|
||||
export default withData(Articles)
|
||||
export default withApollo(Articles)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user