├── .gitignore
├── README.md
├── next-env.d.ts
├── package.json
├── pages
├── _app.tsx
├── api
│ └── graphql.ts
└── index.tsx
├── public
├── favicon.ico
└── vercel.svg
├── src
├── apollo.ts
└── schema.ts
├── styles
├── Home.module.css
└── globals.css
├── tsconfig.json
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | *.pem
21 |
22 | # debug
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 |
27 | # local env files
28 | .env.local
29 | .env.development.local
30 | .env.test.local
31 | .env.production.local
32 |
33 | # vercel
34 | .vercel
35 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Apollo Client v3 in Next.js
2 |
3 | - Video: https://youtu.be/y34ym0-KZ8A
4 | - Next.js Example: https://github.com/vercel/next.js/tree/canary/examples/api-routes-apollo-server-and-client
5 |
--------------------------------------------------------------------------------
/next-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "apollo-nextjs",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start"
9 | },
10 | "dependencies": {
11 | "@apollo/client": "^3.1.3",
12 | "@nexus/schema": "^0.15.0",
13 | "apollo-server-micro": "^2.16.1",
14 | "next": "9.5.2",
15 | "react": "16.13.1",
16 | "react-dom": "16.13.1"
17 | },
18 | "devDependencies": {
19 | "@types/react": "^16.9.46",
20 | "typescript": "^3.9.7"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/pages/_app.tsx:
--------------------------------------------------------------------------------
1 | import { ApolloProvider } from "@apollo/client";
2 | import { useApollo } from "src/apollo";
3 | import "../styles/globals.css";
4 |
5 | function MyApp({ Component, pageProps }) {
6 | const client = useApollo(pageProps.initialApolloState);
7 |
8 | return (
9 |
10 |
11 |
12 | );
13 | }
14 |
15 | export default MyApp;
16 |
--------------------------------------------------------------------------------
/pages/api/graphql.ts:
--------------------------------------------------------------------------------
1 | import { ApolloServer } from "apollo-server-micro";
2 | import { schema } from "src/schema";
3 |
4 | const server = new ApolloServer({ schema });
5 | const handler = server.createHandler({ path: "/api/graphql" });
6 |
7 | export const config = {
8 | api: {
9 | bodyParser: false,
10 | },
11 | };
12 |
13 | export default handler;
14 |
--------------------------------------------------------------------------------
/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import { useQuery, gql } from "@apollo/client";
2 | import { initializeApollo } from "src/apollo";
3 |
4 | const MyQuery = gql`
5 | query MyQuery {
6 | name
7 | }
8 | `;
9 |
10 | export default function Home() {
11 | const { data, loading } = useQuery(MyQuery);
12 |
13 | if (loading) return loading...;
14 |
15 | return (
16 |
17 |
{JSON.stringify(data, null, 2)}
18 |
19 | );
20 | }
21 |
22 | export async function getStaticProps() {
23 | const apolloClient = initializeApollo();
24 |
25 | await apolloClient.query({
26 | query: MyQuery,
27 | });
28 |
29 | return {
30 | props: {
31 | initialApolloState: apolloClient.cache.extract(),
32 | },
33 | };
34 | }
35 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/leighhalliday/apollo-nextjs/952e534ee916ff1cc8dc02ff11a2090c9eec62c9/public/favicon.ico
--------------------------------------------------------------------------------
/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/apollo.ts:
--------------------------------------------------------------------------------
1 | import {
2 | ApolloClient,
3 | InMemoryCache,
4 | NormalizedCacheObject,
5 | } from "@apollo/client";
6 | import { useMemo } from "react";
7 |
8 | let apolloClient: ApolloClient;
9 |
10 | function createIsomorphicLink() {
11 | if (typeof window === "undefined") {
12 | // server
13 | const { SchemaLink } = require("@apollo/client/link/schema");
14 | const { schema } = require("./schema");
15 | return new SchemaLink({ schema });
16 | } else {
17 | // client
18 | const { HttpLink } = require("@apollo/client/link/http");
19 | return new HttpLink({ uri: "/api/graphql" });
20 | }
21 | }
22 |
23 | function createApolloClient() {
24 | return new ApolloClient({
25 | ssrMode: typeof window === "undefined",
26 | link: createIsomorphicLink(),
27 | cache: new InMemoryCache(),
28 | });
29 | }
30 |
31 | export function initializeApollo(initialState = null) {
32 | const _apolloClient = apolloClient ?? createApolloClient();
33 |
34 | if (initialState) {
35 | _apolloClient.cache.restore(initialState);
36 | }
37 |
38 | if (typeof window === "undefined") return _apolloClient;
39 | apolloClient = apolloClient ?? _apolloClient;
40 |
41 | return apolloClient;
42 | }
43 |
44 | export function useApollo(initialState) {
45 | const store = useMemo(() => initializeApollo(initialState), [initialState]);
46 | return store;
47 | }
48 |
--------------------------------------------------------------------------------
/src/schema.ts:
--------------------------------------------------------------------------------
1 | import { makeSchema, queryType } from "@nexus/schema";
2 |
3 | const Query = queryType({
4 | definition(t) {
5 | t.string("name", () => "Leigh Halliday");
6 | },
7 | });
8 |
9 | const types = { Query };
10 |
11 | export const schema = makeSchema({
12 | types,
13 | });
14 |
--------------------------------------------------------------------------------
/styles/Home.module.css:
--------------------------------------------------------------------------------
1 | .container {
2 | min-height: 100vh;
3 | padding: 0 0.5rem;
4 | display: flex;
5 | flex-direction: column;
6 | justify-content: center;
7 | align-items: center;
8 | }
9 |
10 | .main {
11 | padding: 5rem 0;
12 | flex: 1;
13 | display: flex;
14 | flex-direction: column;
15 | justify-content: center;
16 | align-items: center;
17 | }
18 |
19 | .footer {
20 | width: 100%;
21 | height: 100px;
22 | border-top: 1px solid #eaeaea;
23 | display: flex;
24 | justify-content: center;
25 | align-items: center;
26 | }
27 |
28 | .footer img {
29 | margin-left: 0.5rem;
30 | }
31 |
32 | .footer a {
33 | display: flex;
34 | justify-content: center;
35 | align-items: center;
36 | }
37 |
38 | .title a {
39 | color: #0070f3;
40 | text-decoration: none;
41 | }
42 |
43 | .title a:hover,
44 | .title a:focus,
45 | .title a:active {
46 | text-decoration: underline;
47 | }
48 |
49 | .title {
50 | margin: 0;
51 | line-height: 1.15;
52 | font-size: 4rem;
53 | }
54 |
55 | .title,
56 | .description {
57 | text-align: center;
58 | }
59 |
60 | .description {
61 | line-height: 1.5;
62 | font-size: 1.5rem;
63 | }
64 |
65 | .code {
66 | background: #fafafa;
67 | border-radius: 5px;
68 | padding: 0.75rem;
69 | font-size: 1.1rem;
70 | font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono,
71 | Bitstream Vera Sans Mono, Courier New, monospace;
72 | }
73 |
74 | .grid {
75 | display: flex;
76 | align-items: center;
77 | justify-content: center;
78 | flex-wrap: wrap;
79 |
80 | max-width: 800px;
81 | margin-top: 3rem;
82 | }
83 |
84 | .card {
85 | margin: 1rem;
86 | flex-basis: 45%;
87 | padding: 1.5rem;
88 | text-align: left;
89 | color: inherit;
90 | text-decoration: none;
91 | border: 1px solid #eaeaea;
92 | border-radius: 10px;
93 | transition: color 0.15s ease, border-color 0.15s ease;
94 | }
95 |
96 | .card:hover,
97 | .card:focus,
98 | .card:active {
99 | color: #0070f3;
100 | border-color: #0070f3;
101 | }
102 |
103 | .card h3 {
104 | margin: 0 0 1rem 0;
105 | font-size: 1.5rem;
106 | }
107 |
108 | .card p {
109 | margin: 0;
110 | font-size: 1.25rem;
111 | line-height: 1.5;
112 | }
113 |
114 | .logo {
115 | height: 1em;
116 | }
117 |
118 | @media (max-width: 600px) {
119 | .grid {
120 | width: 100%;
121 | flex-direction: column;
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/styles/globals.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | padding: 0;
4 | margin: 0;
5 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
6 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
7 | }
8 |
9 | a {
10 | color: inherit;
11 | text-decoration: none;
12 | }
13 |
14 | * {
15 | box-sizing: border-box;
16 | }
17 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": ["dom", "dom.iterable", "esnext"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "strict": false,
8 | "forceConsistentCasingInFileNames": true,
9 | "noEmit": true,
10 | "esModuleInterop": true,
11 | "module": "esnext",
12 | "moduleResolution": "node",
13 | "resolveJsonModule": true,
14 | "isolatedModules": true,
15 | "jsx": "preserve",
16 | "baseUrl": "."
17 | },
18 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
19 | "exclude": ["node_modules"]
20 | }
21 |
--------------------------------------------------------------------------------