장재혁

Add init lerna setting

1 +node_modules
1 +{
2 + "useWorkspaces" : true,
3 + "npmClient": "yarn",
4 + "version": "0.0.0"
5 +}
1 +{
2 + "name": "graphql-community",
3 + "private": true,
4 + "devDependencies": {
5 + "lerna": "^4.0.0"
6 + },
7 + "scripts": {
8 + "build": "lerna run build",
9 + "build:api" : "lerna exec --scrop @graphql-community/api --stream yarn build",
10 + "build:web": "lerna exec --scrop @graphql-community/api --stream yarn build",
11 + "dev:web": "lerna exec --scrop @graphql-community/web --stream yarn dev",
12 + "dev:api": "lerna exec --scrop @graphql-community/api --stream yarn start:dev"
13 + },
14 + "workspaces": [
15 + "packages/**"
16 + ]
17 +}
1 +module.exports = {
2 + parser: '@typescript-eslint/parser',
3 + parserOptions: {
4 + project: 'tsconfig.json',
5 + sourceType: 'module',
6 + },
7 + plugins: ['@typescript-eslint/eslint-plugin'],
8 + extends: [
9 + 'plugin:@typescript-eslint/recommended',
10 + 'plugin:prettier/recommended',
11 + ],
12 + root: true,
13 + env: {
14 + node: true,
15 + jest: true,
16 + },
17 + ignorePatterns: ['.eslintrc.js'],
18 + rules: {
19 + '@typescript-eslint/interface-name-prefix': 'off',
20 + '@typescript-eslint/explicit-function-return-type': 'off',
21 + '@typescript-eslint/explicit-module-boundary-types': 'off',
22 + '@typescript-eslint/no-explicit-any': 'off',
23 + },
24 +};
1 +# compiled output
2 +/dist
3 +/node_modules
4 +
5 +# Logs
6 +logs
7 +*.log
8 +npm-debug.log*
9 +yarn-debug.log*
10 +yarn-error.log*
11 +lerna-debug.log*
12 +
13 +# OS
14 +.DS_Store
15 +
16 +# Tests
17 +/coverage
18 +/.nyc_output
19 +
20 +# IDEs and editors
21 +/.idea
22 +.project
23 +.classpath
24 +.c9/
25 +*.launch
26 +.settings/
27 +*.sublime-workspace
28 +
29 +# IDE - VSCode
30 +.vscode/*
31 +!.vscode/settings.json
32 +!.vscode/tasks.json
33 +!.vscode/launch.json
34 +!.vscode/extensions.json
...\ No newline at end of file ...\ No newline at end of file
1 +{
2 + "singleQuote": true,
3 + "trailingComma": "all"
4 +}
...\ No newline at end of file ...\ No newline at end of file
1 +<p align="center">
2 + <a href="http://nestjs.com/" target="blank"><img src="https://nestjs.com/img/logo_text.svg" width="320" alt="Nest Logo" /></a>
3 +</p>
4 +
5 +[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456
6 +[circleci-url]: https://circleci.com/gh/nestjs/nest
7 +
8 + <p align="center">A progressive <a href="http://nodejs.org" target="_blank">Node.js</a> framework for building efficient and scalable server-side applications.</p>
9 + <p align="center">
10 +<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/v/@nestjs/core.svg" alt="NPM Version" /></a>
11 +<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/l/@nestjs/core.svg" alt="Package License" /></a>
12 +<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/dm/@nestjs/common.svg" alt="NPM Downloads" /></a>
13 +<a href="https://circleci.com/gh/nestjs/nest" target="_blank"><img src="https://img.shields.io/circleci/build/github/nestjs/nest/master" alt="CircleCI" /></a>
14 +<a href="https://coveralls.io/github/nestjs/nest?branch=master" target="_blank"><img src="https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9" alt="Coverage" /></a>
15 +<a href="https://discord.gg/G7Qnnhy" target="_blank"><img src="https://img.shields.io/badge/discord-online-brightgreen.svg" alt="Discord"/></a>
16 +<a href="https://opencollective.com/nest#backer" target="_blank"><img src="https://opencollective.com/nest/backers/badge.svg" alt="Backers on Open Collective" /></a>
17 +<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://opencollective.com/nest/sponsors/badge.svg" alt="Sponsors on Open Collective" /></a>
18 + <a href="https://paypal.me/kamilmysliwiec" target="_blank"><img src="https://img.shields.io/badge/Donate-PayPal-ff3f59.svg"/></a>
19 + <a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg" alt="Support us"></a>
20 + <a href="https://twitter.com/nestframework" target="_blank"><img src="https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow"></a>
21 +</p>
22 + <!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)
23 + [![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->
24 +
25 +## Description
26 +
27 +[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.
28 +
29 +## Installation
30 +
31 +```bash
32 +$ npm install
33 +```
34 +
35 +## Running the app
36 +
37 +```bash
38 +# development
39 +$ npm run start
40 +
41 +# watch mode
42 +$ npm run start:dev
43 +
44 +# production mode
45 +$ npm run start:prod
46 +```
47 +
48 +## Test
49 +
50 +```bash
51 +# unit tests
52 +$ npm run test
53 +
54 +# e2e tests
55 +$ npm run test:e2e
56 +
57 +# test coverage
58 +$ npm run test:cov
59 +```
60 +
61 +## Support
62 +
63 +Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).
64 +
65 +## Stay in touch
66 +
67 +- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)
68 +- Website - [https://nestjs.com](https://nestjs.com/)
69 +- Twitter - [@nestframework](https://twitter.com/nestframework)
70 +
71 +## License
72 +
73 +Nest is [MIT licensed](LICENSE).
1 +{
2 + "collection": "@nestjs/schematics",
3 + "sourceRoot": "src"
4 +}
1 +{
2 + "name": "@graphql-community/api",
3 + "version": "0.0.1",
4 + "description": "",
5 + "author": "",
6 + "private": true,
7 + "license": "UNLICENSED",
8 + "scripts": {
9 + "prebuild": "rimraf dist",
10 + "build": "nest build",
11 + "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
12 + "start": "nest start",
13 + "start:dev": "nest start --watch",
14 + "start:debug": "nest start --debug --watch",
15 + "start:prod": "node dist/main",
16 + "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
17 + "test": "jest",
18 + "test:watch": "jest --watch",
19 + "test:cov": "jest --coverage",
20 + "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
21 + "test:e2e": "jest --config ./test/jest-e2e.json"
22 + },
23 + "dependencies": {
24 + "@nestjs/common": "^7.6.15",
25 + "@nestjs/core": "^7.6.15",
26 + "@nestjs/platform-express": "^7.6.15",
27 + "reflect-metadata": "^0.1.13",
28 + "rimraf": "^3.0.2",
29 + "rxjs": "^6.6.6"
30 + },
31 + "devDependencies": {
32 + "@nestjs/cli": "^7.6.0",
33 + "@nestjs/schematics": "^7.3.0",
34 + "@nestjs/testing": "^7.6.15",
35 + "@types/express": "^4.17.11",
36 + "@types/jest": "^26.0.22",
37 + "@types/node": "^14.14.36",
38 + "@types/supertest": "^2.0.10",
39 + "@typescript-eslint/eslint-plugin": "^4.19.0",
40 + "@typescript-eslint/parser": "^4.19.0",
41 + "eslint": "^7.22.0",
42 + "eslint-config-prettier": "^8.1.0",
43 + "eslint-plugin-prettier": "^3.3.1",
44 + "jest": "^26.6.3",
45 + "prettier": "^2.2.1",
46 + "supertest": "^6.1.3",
47 + "ts-jest": "^26.5.4",
48 + "ts-loader": "^8.0.18",
49 + "ts-node": "^9.1.1",
50 + "tsconfig-paths": "^3.9.0",
51 + "typescript": "^4.2.3"
52 + },
53 + "jest": {
54 + "moduleFileExtensions": [
55 + "js",
56 + "json",
57 + "ts"
58 + ],
59 + "rootDir": "src",
60 + "testRegex": ".*\\.spec\\.ts$",
61 + "transform": {
62 + "^.+\\.(t|j)s$": "ts-jest"
63 + },
64 + "collectCoverageFrom": [
65 + "**/*.(t|j)s"
66 + ],
67 + "coverageDirectory": "../coverage",
68 + "testEnvironment": "node"
69 + }
70 +}
1 +import { Test, TestingModule } from '@nestjs/testing';
2 +import { AppController } from './app.controller';
3 +import { AppService } from './app.service';
4 +
5 +describe('AppController', () => {
6 + let appController: AppController;
7 +
8 + beforeEach(async () => {
9 + const app: TestingModule = await Test.createTestingModule({
10 + controllers: [AppController],
11 + providers: [AppService],
12 + }).compile();
13 +
14 + appController = app.get<AppController>(AppController);
15 + });
16 +
17 + describe('root', () => {
18 + it('should return "Hello World!"', () => {
19 + expect(appController.getHello()).toBe('Hello World!');
20 + });
21 + });
22 +});
1 +import { Controller, Get } from '@nestjs/common';
2 +import { AppService } from './app.service';
3 +
4 +@Controller()
5 +export class AppController {
6 + constructor(private readonly appService: AppService) {}
7 +
8 + @Get()
9 + getHello(): string {
10 + return this.appService.getHello();
11 + }
12 +}
1 +import { Module } from '@nestjs/common';
2 +import { AppController } from './app.controller';
3 +import { AppService } from './app.service';
4 +
5 +@Module({
6 + imports: [],
7 + controllers: [AppController],
8 + providers: [AppService],
9 +})
10 +export class AppModule {}
1 +import { Injectable } from '@nestjs/common';
2 +
3 +@Injectable()
4 +export class AppService {
5 + getHello(): string {
6 + return 'Hello World!';
7 + }
8 +}
1 +import { NestFactory } from '@nestjs/core';
2 +import { AppModule } from './app.module';
3 +
4 +async function bootstrap() {
5 + const app = await NestFactory.create(AppModule);
6 + await app.listen(3000);
7 +}
8 +bootstrap();
1 +import { Test, TestingModule } from '@nestjs/testing';
2 +import { INestApplication } from '@nestjs/common';
3 +import * as request from 'supertest';
4 +import { AppModule } from './../src/app.module';
5 +
6 +describe('AppController (e2e)', () => {
7 + let app: INestApplication;
8 +
9 + beforeEach(async () => {
10 + const moduleFixture: TestingModule = await Test.createTestingModule({
11 + imports: [AppModule],
12 + }).compile();
13 +
14 + app = moduleFixture.createNestApplication();
15 + await app.init();
16 + });
17 +
18 + it('/ (GET)', () => {
19 + return request(app.getHttpServer())
20 + .get('/')
21 + .expect(200)
22 + .expect('Hello World!');
23 + });
24 +});
1 +{
2 + "moduleFileExtensions": ["js", "json", "ts"],
3 + "rootDir": ".",
4 + "testEnvironment": "node",
5 + "testRegex": ".e2e-spec.ts$",
6 + "transform": {
7 + "^.+\\.(t|j)s$": "ts-jest"
8 + }
9 +}
1 +{
2 + "extends": "./tsconfig.json",
3 + "exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
4 +}
1 +{
2 + "compilerOptions": {
3 + "module": "commonjs",
4 + "declaration": true,
5 + "removeComments": true,
6 + "emitDecoratorMetadata": true,
7 + "experimentalDecorators": true,
8 + "allowSyntheticDefaultImports": true,
9 + "target": "es2017",
10 + "sourceMap": true,
11 + "outDir": "./dist",
12 + "baseUrl": "./",
13 + "incremental": true
14 + }
15 +}
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
1 +# Apollo Example
2 +
3 +[Apollo](https://www.apollographql.com/client/) is a GraphQL client that allows you to easily query the exact data you need from a GraphQL server. In addition to fetching and mutating data, Apollo analyzes your queries and their results to construct a client-side cache of your data, which is kept up to date as further queries and mutations are run.
4 +
5 +In this simple example, we integrate Apollo seamlessly with [Next.js data fetching methods](https://nextjs.org/docs/basic-features/data-fetching) to fetch queries in the server and hydrate them in the browser.
6 +
7 +This example relies on [Prisma + Nexus](https://github.com/prisma-labs/nextjs-graphql-api-examples) for its GraphQL backend.
8 +
9 +## Demo
10 +
11 +[https://next-with-apollo.now.sh](https://next-with-apollo.now.sh)
12 +
13 +## Deploy your own
14 +
15 +Deploy the example using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example):
16 +
17 +[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/git/external?repository-url=https://github.com/vercel/next.js/tree/canary/examples/with-apollo&project-name=with-apollo&repository-name=with-apollo)
18 +
19 +## How to use
20 +
21 +Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init) or [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/) to bootstrap the example:
22 +
23 +```bash
24 +npx create-next-app --example with-apollo with-apollo-app
25 +# or
26 +yarn create next-app --example with-apollo with-apollo-app
27 +```
28 +
29 +Deploy it to the cloud with [Vercel](https://vercel.com/new?utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)).
1 +export default function App({ children }) {
2 + return (
3 + <main>
4 + {children}
5 + <style jsx global>{`
6 + * {
7 + font-family: Menlo, Monaco, 'Lucida Console', 'Liberation Mono',
8 + 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New',
9 + monospace, serif;
10 + }
11 + body {
12 + margin: 0;
13 + padding: 25px 50px;
14 + }
15 + a {
16 + color: #22bad9;
17 + }
18 + p {
19 + font-size: 14px;
20 + line-height: 24px;
21 + }
22 + article {
23 + margin: 0 auto;
24 + max-width: 650px;
25 + }
26 + button {
27 + align-items: center;
28 + background-color: #22bad9;
29 + border: 0;
30 + color: white;
31 + display: flex;
32 + padding: 5px 7px;
33 + transition: background-color 0.3s;
34 + }
35 + button:active {
36 + background-color: #1b9db7;
37 + }
38 + button:disabled {
39 + background-color: #b5bebf;
40 + }
41 + button:focus {
42 + outline: none;
43 + }
44 + `}</style>
45 + </main>
46 + )
47 +}
1 +export default function ErrorMessage({ message }) {
2 + return (
3 + <aside>
4 + {message}
5 + <style jsx>{`
6 + aside {
7 + padding: 1.5em;
8 + font-size: 14px;
9 + color: white;
10 + background-color: red;
11 + }
12 + `}</style>
13 + </aside>
14 + )
15 +}
1 +import { useRouter } from 'next/router'
2 +import Link from 'next/link'
3 +
4 +export default function Header() {
5 + const { pathname } = useRouter()
6 +
7 + return (
8 + <header>
9 + <Link href="/">
10 + <a className={pathname === '/' ? 'is-active' : ''}>Home</a>
11 + </Link>
12 + <Link href="/about">
13 + <a className={pathname === '/about' ? 'is-active' : ''}>About</a>
14 + </Link>
15 + <Link href="/client-only">
16 + <a className={pathname === '/client-only' ? 'is-active' : ''}>
17 + Client-Only
18 + </a>
19 + </Link>
20 + <Link href="/ssr">
21 + <a className={pathname === '/ssr' ? 'is-active' : ''}>SSR</a>
22 + </Link>
23 + <style jsx>{`
24 + header {
25 + margin-bottom: 25px;
26 + }
27 + a {
28 + font-size: 14px;
29 + margin-right: 15px;
30 + text-decoration: none;
31 + }
32 + .is-active {
33 + text-decoration: underline;
34 + }
35 + `}</style>
36 + </header>
37 + )
38 +}
1 +const InfoBox = ({ children }) => (
2 + <div className="info">
3 + <style jsx>{`
4 + .info {
5 + margin-top: 20px;
6 + margin-bottom: 20px;
7 + padding-top: 20px;
8 + padding-bottom: 20px;
9 + border-top: 1px solid #ececec;
10 + border-bottom: 1px solid #ececec;
11 + }
12 + `}</style>
13 + {children}
14 + </div>
15 +)
16 +
17 +export default InfoBox
1 +import { gql, useQuery, NetworkStatus } from '@apollo/client'
2 +import ErrorMessage from './ErrorMessage'
3 +import PostUpvoter from './PostUpvoter'
4 +
5 +export const ALL_POSTS_QUERY = gql`
6 + query allPosts($first: Int!, $skip: Int!) {
7 + allPosts(orderBy: { createdAt: desc }, first: $first, skip: $skip) {
8 + id
9 + title
10 + votes
11 + url
12 + createdAt
13 + }
14 + _allPostsMeta {
15 + count
16 + }
17 + }
18 +`
19 +
20 +export const allPostsQueryVars = {
21 + skip: 0,
22 + first: 10,
23 +}
24 +
25 +export default function PostList() {
26 + const { loading, error, data, fetchMore, networkStatus } = useQuery(
27 + ALL_POSTS_QUERY,
28 + {
29 + variables: allPostsQueryVars,
30 + // Setting this value to true will make the component rerender when
31 + // the "networkStatus" changes, so we are able to know if it is fetching
32 + // more data
33 + notifyOnNetworkStatusChange: true,
34 + }
35 + )
36 +
37 + const loadingMorePosts = networkStatus === NetworkStatus.fetchMore
38 +
39 + const loadMorePosts = () => {
40 + fetchMore({
41 + variables: {
42 + skip: allPosts.length,
43 + },
44 + })
45 + }
46 +
47 + if (error) return <ErrorMessage message="Error loading posts." />
48 + if (loading && !loadingMorePosts) return <div>Loading</div>
49 +
50 + const { allPosts, _allPostsMeta } = data
51 + const areMorePosts = allPosts.length < _allPostsMeta.count
52 +
53 + return (
54 + <section>
55 + <ul>
56 + {allPosts.map((post, index) => (
57 + <li key={post.id}>
58 + <div>
59 + <span>{index + 1}. </span>
60 + <a href={post.url}>{post.title}</a>
61 + <PostUpvoter id={post.id} votes={post.votes} />
62 + </div>
63 + </li>
64 + ))}
65 + </ul>
66 + {areMorePosts && (
67 + <button onClick={() => loadMorePosts()} disabled={loadingMorePosts}>
68 + {loadingMorePosts ? 'Loading...' : 'Show More'}
69 + </button>
70 + )}
71 + <style jsx>{`
72 + section {
73 + padding-bottom: 20px;
74 + }
75 + li {
76 + display: block;
77 + margin-bottom: 10px;
78 + }
79 + div {
80 + align-items: center;
81 + display: flex;
82 + }
83 + a {
84 + font-size: 14px;
85 + margin-right: 10px;
86 + text-decoration: none;
87 + padding-bottom: 0;
88 + border: 0;
89 + }
90 + span {
91 + font-size: 14px;
92 + margin-right: 5px;
93 + }
94 + ul {
95 + margin: 0;
96 + padding: 0;
97 + }
98 + button:before {
99 + align-self: center;
100 + border-style: solid;
101 + border-width: 6px 4px 0 4px;
102 + border-color: #ffffff transparent transparent transparent;
103 + content: '';
104 + height: 0;
105 + margin-right: 5px;
106 + width: 0;
107 + }
108 + `}</style>
109 + </section>
110 + )
111 +}
1 +import { gql, useMutation } from '@apollo/client'
2 +
3 +const UPDATE_POST_MUTATION = gql`
4 + mutation votePost($id: String!) {
5 + votePost(id: $id) {
6 + id
7 + votes
8 + __typename
9 + }
10 + }
11 +`
12 +
13 +export default function PostUpvoter({ votes, id }) {
14 + const [updatePost] = useMutation(UPDATE_POST_MUTATION)
15 +
16 + const upvotePost = () => {
17 + updatePost({
18 + variables: {
19 + id,
20 + },
21 + optimisticResponse: {
22 + __typename: 'Mutation',
23 + votePost: {
24 + __typename: 'Post',
25 + id,
26 + votes: votes + 1,
27 + },
28 + },
29 + })
30 + }
31 +
32 + return (
33 + <button onClick={() => upvotePost()}>
34 + {votes}
35 + <style jsx>{`
36 + button {
37 + background-color: transparent;
38 + border: 1px solid #e4e4e4;
39 + color: #000;
40 + }
41 + button:active {
42 + background-color: transparent;
43 + }
44 + button:before {
45 + align-self: center;
46 + border-color: transparent transparent #000000 transparent;
47 + border-style: solid;
48 + border-width: 0 4px 6px 4px;
49 + content: '';
50 + height: 0;
51 + margin-right: 5px;
52 + width: 0;
53 + }
54 + `}</style>
55 + </button>
56 + )
57 +}
1 +import { gql, useMutation } from '@apollo/client'
2 +
3 +const CREATE_POST_MUTATION = gql`
4 + mutation createPost($title: String!, $url: String!) {
5 + createPost(title: $title, url: $url) {
6 + id
7 + title
8 + votes
9 + url
10 + createdAt
11 + }
12 + }
13 +`
14 +
15 +export default function Submit() {
16 + const [createPost, { loading }] = useMutation(CREATE_POST_MUTATION)
17 +
18 + const handleSubmit = (event) => {
19 + event.preventDefault()
20 + const form = event.target
21 + const formData = new window.FormData(form)
22 + const title = formData.get('title')
23 + const url = formData.get('url')
24 + form.reset()
25 +
26 + createPost({
27 + variables: { title, url },
28 + update: (cache, { data: { createPost } }) => {
29 + cache.modify({
30 + fields: {
31 + allPosts(existingPosts = []) {
32 + const newPostRef = cache.writeFragment({
33 + data: createPost,
34 + fragment: gql`
35 + fragment NewPost on allPosts {
36 + id
37 + type
38 + }
39 + `,
40 + })
41 + return [newPostRef, ...existingPosts]
42 + },
43 + },
44 + })
45 + },
46 + })
47 + }
48 +
49 + return (
50 + <form onSubmit={handleSubmit}>
51 + <h1>Submit</h1>
52 + <input placeholder="title" name="title" type="text" required />
53 + <input placeholder="url" name="url" type="url" required />
54 + <button type="submit" disabled={loading}>
55 + Submit
56 + </button>
57 + <style jsx>{`
58 + form {
59 + border-bottom: 1px solid #ececec;
60 + padding-bottom: 20px;
61 + margin-bottom: 20px;
62 + }
63 + h1 {
64 + font-size: 20px;
65 + }
66 + input {
67 + display: block;
68 + margin-bottom: 10px;
69 + }
70 + `}</style>
71 + </form>
72 + )
73 +}
1 +import { useMemo } from 'react'
2 +import { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client'
3 +import { concatPagination } from '@apollo/client/utilities'
4 +import merge from 'deepmerge'
5 +import isEqual from 'lodash/isEqual'
6 +
7 +export const APOLLO_STATE_PROP_NAME = '__APOLLO_STATE__'
8 +
9 +let apolloClient
10 +
11 +function createApolloClient() {
12 + return new ApolloClient({
13 + ssrMode: typeof window === 'undefined',
14 + link: new HttpLink({
15 + uri: 'https://nextjs-graphql-with-prisma-simple.vercel.app/api', // Server URL (must be absolute)
16 + credentials: 'same-origin', // Additional fetch() options like `credentials` or `headers`
17 + }),
18 + cache: new InMemoryCache({
19 + typePolicies: {
20 + Query: {
21 + fields: {
22 + allPosts: concatPagination(),
23 + },
24 + },
25 + },
26 + }),
27 + })
28 +}
29 +
30 +export function initializeApollo(initialState = null) {
31 + const _apolloClient = apolloClient ?? createApolloClient()
32 +
33 + // If your page has Next.js data fetching methods that use Apollo Client, the initial state
34 + // gets hydrated here
35 + if (initialState) {
36 + // Get existing cache, loaded during client side data fetching
37 + const existingCache = _apolloClient.extract()
38 +
39 + // Merge the existing cache into data passed from getStaticProps/getServerSideProps
40 + const data = merge(initialState, existingCache, {
41 + // combine arrays using object equality (like in sets)
42 + arrayMerge: (destinationArray, sourceArray) => [
43 + ...sourceArray,
44 + ...destinationArray.filter((d) =>
45 + sourceArray.every((s) => !isEqual(d, s))
46 + ),
47 + ],
48 + })
49 +
50 + // Restore the cache with the merged data
51 + _apolloClient.cache.restore(data)
52 + }
53 + // For SSG and SSR always create a new Apollo Client
54 + if (typeof window === 'undefined') return _apolloClient
55 + // Create the Apollo Client once in the client
56 + if (!apolloClient) apolloClient = _apolloClient
57 +
58 + return _apolloClient
59 +}
60 +
61 +export function addApolloState(client, pageProps) {
62 + if (pageProps?.props) {
63 + pageProps.props[APOLLO_STATE_PROP_NAME] = client.cache.extract()
64 + }
65 +
66 + return pageProps
67 +}
68 +
69 +export function useApollo(pageProps) {
70 + const state = pageProps[APOLLO_STATE_PROP_NAME]
71 + const store = useMemo(() => initializeApollo(state), [state])
72 + return store
73 +}
1 +{
2 + "name": "@graphql-community/web",
3 + "version": "1.0.0",
4 + "scripts": {
5 + "dev": "next",
6 + "build": "next build",
7 + "start": "next start"
8 + },
9 + "dependencies": {
10 + "@apollo/client": "3.1.1",
11 + "deepmerge": "^4.2.2",
12 + "lodash": "4.17.20",
13 + "graphql": "^15.3.0",
14 + "next": "latest",
15 + "prop-types": "^15.6.2",
16 + "react": "^16.7.0",
17 + "react-dom": "^16.7.0"
18 + },
19 + "license": "MIT"
20 +}
1 +import { ApolloProvider } from '@apollo/client'
2 +import { useApollo } from '../lib/apolloClient'
3 +
4 +export default function App({ Component, pageProps }) {
5 + const apolloClient = useApollo(pageProps)
6 +
7 + return (
8 + <ApolloProvider client={apolloClient}>
9 + <Component {...pageProps} />
10 + </ApolloProvider>
11 + )
12 +}
1 +import App from '../components/App'
2 +import Header from '../components/Header'
3 +
4 +const AboutPage = () => (
5 + <App>
6 + <Header />
7 + <article>
8 + <h1>The Idea Behind This Example</h1>
9 + <p>
10 + <a href="https://www.apollographql.com/client/">Apollo</a> is a GraphQL
11 + client that allows you to easily query the exact data you need from a
12 + GraphQL server. In addition to fetching and mutating data, Apollo
13 + analyzes your queries and their results to construct a client-side cache
14 + of your data, which is kept up to date as further queries and mutations
15 + are run, fetching more results from the server.
16 + </p>
17 + <p>
18 + In this simple example, we integrate Apollo seamlessly with{' '}
19 + <a href="https://github.com/vercel/next.js">Next</a> by calling{' '}
20 + <a href="https://nextjs.org/docs/basic-features/data-fetching#getstaticprops-static-generation">
21 + getStaticProps
22 + </a>{' '}
23 + at our Page component. This approach lets us opt out of getInitialProps
24 + and let us use all the niceties provided by{' '}
25 + <a href="https://github.com/vercel/next.js">Next</a>.
26 + </p>
27 + <p>
28 + On initial page load, while on the server and inside{' '}
29 + <a href="https://nextjs.org/docs/basic-features/data-fetching#getstaticprops-static-generation">
30 + getStaticProps
31 + </a>
32 + , we fetch the query used to get the list of posts. At the point in
33 + which the query promise resolves, our Apollo Client store is completely
34 + initialized. Then we serve the initial HTML with the fetched data and
35 + hydrate Apollo in the browser.
36 + </p>
37 + <p>
38 + This example relies on <a href="http://graph.cool">graph.cool</a> for
39 + its GraphQL backend.
40 + </p>
41 + </article>
42 + </App>
43 +)
44 +
45 +export default AboutPage
1 +import App from '../components/App'
2 +import InfoBox from '../components/InfoBox'
3 +import Header from '../components/Header'
4 +import Submit from '../components/Submit'
5 +import PostList from '../components/PostList'
6 +
7 +const ClientOnlyPage = (props) => (
8 + <App>
9 + <Header />
10 + <InfoBox>
11 + ℹ️ This page shows how to use Apollo only in the client. If you{' '}
12 + <a href="/client-only">reload</a> this page, you will see a loader since
13 + Apollo didn't fetch any data on the server. This is useful when the page
14 + doesn't have SEO requirements or blocking data fetching requirements.
15 + </InfoBox>
16 + <Submit />
17 + <PostList />
18 + </App>
19 +)
20 +
21 +export default ClientOnlyPage
1 +import App from '../components/App'
2 +import InfoBox from '../components/InfoBox'
3 +import Header from '../components/Header'
4 +import Submit from '../components/Submit'
5 +import PostList, {
6 + ALL_POSTS_QUERY,
7 + allPostsQueryVars,
8 +} from '../components/PostList'
9 +import { initializeApollo, addApolloState } from '../lib/apolloClient'
10 +
11 +const IndexPage = () => (
12 + <App>
13 + <Header />
14 + <InfoBox>ℹ️ This page shows how to use SSG with Apollo.</InfoBox>
15 + <Submit />
16 + <PostList />
17 + </App>
18 +)
19 +
20 +export async function getStaticProps() {
21 + const apolloClient = initializeApollo()
22 +
23 + await apolloClient.query({
24 + query: ALL_POSTS_QUERY,
25 + variables: allPostsQueryVars,
26 + })
27 +
28 + return addApolloState(apolloClient, {
29 + props: {},
30 + revalidate: 1,
31 + })
32 +}
33 +
34 +export default IndexPage
1 +import App from '../components/App'
2 +import InfoBox from '../components/InfoBox'
3 +import Header from '../components/Header'
4 +import Submit from '../components/Submit'
5 +import PostList, {
6 + ALL_POSTS_QUERY,
7 + allPostsQueryVars,
8 +} from '../components/PostList'
9 +import { initializeApollo, addApolloState } from '../lib/apolloClient'
10 +
11 +const SSRPage = () => (
12 + <App>
13 + <Header />
14 + <InfoBox>ℹ️ This page shows how to use SSR with Apollo.</InfoBox>
15 + <Submit />
16 + <PostList />
17 + </App>
18 +)
19 +
20 +export async function getServerSideProps() {
21 + const apolloClient = initializeApollo()
22 +
23 + await apolloClient.query({
24 + query: ALL_POSTS_QUERY,
25 + variables: allPostsQueryVars,
26 + })
27 +
28 + return addApolloState(apolloClient, {
29 + props: {},
30 + })
31 +}
32 +
33 +export default SSRPage
This diff could not be displayed because it is too large.