examples(with-typescript-graphql): migrate to Yoga v3 and codegen new preset: client
(#41597)
Co-authored-by: Balázs Orbán <info@balazsorban.com>
This commit is contained in:
parent
fedcae42d0
commit
792c661264
12 changed files with 279 additions and 56 deletions
|
@ -34,3 +34,4 @@ packages/next-swc/crates/**
|
|||
bench/nested-deps/pages/**
|
||||
bench/nested-deps/components/**
|
||||
packages/next-bundle-analyzer/index.d.ts
|
||||
examples/with-typescript-graphql/lib/gql/
|
||||
|
|
23
examples/with-typescript-graphql/codegen.ts
Normal file
23
examples/with-typescript-graphql/codegen.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
import type { CodegenConfig } from '@graphql-codegen/cli'
|
||||
|
||||
const config: CodegenConfig = {
|
||||
schema: [
|
||||
{
|
||||
'lib/schema.ts': {
|
||||
noRequire: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
documents: './pages/**/*.tsx',
|
||||
generates: {
|
||||
'./lib/gql/': {
|
||||
preset: 'client',
|
||||
plugins: [],
|
||||
},
|
||||
'./lib/resolvers-types.ts': {
|
||||
plugins: ['typescript', 'typescript-resolvers'],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export default config
|
|
@ -1,14 +0,0 @@
|
|||
schema:
|
||||
- 'lib/schema.ts':
|
||||
noRequire: true
|
||||
documents: ./lib/documents/*.graphql
|
||||
generates:
|
||||
./lib/graphql-operations.ts:
|
||||
plugins:
|
||||
- typescript
|
||||
- typescript-operations
|
||||
- typed-document-node
|
||||
./lib/resolvers-types.ts:
|
||||
plugins:
|
||||
- typescript
|
||||
- typescript-resolvers
|
|
@ -1,7 +0,0 @@
|
|||
mutation UpdateName($name: String!) {
|
||||
updateName(name: $name) {
|
||||
id
|
||||
name
|
||||
status
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
query Viewer {
|
||||
viewer {
|
||||
...Partial
|
||||
status
|
||||
}
|
||||
}
|
||||
|
||||
fragment Partial on User {
|
||||
id
|
||||
name
|
||||
}
|
44
examples/with-typescript-graphql/lib/gql/fragment-masking.ts
Normal file
44
examples/with-typescript-graphql/lib/gql/fragment-masking.ts
Normal file
|
@ -0,0 +1,44 @@
|
|||
import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'
|
||||
|
||||
export type FragmentType<TDocumentType extends DocumentNode<any, any>> =
|
||||
TDocumentType extends DocumentNode<infer TType, any>
|
||||
? TType extends { ' $fragmentName'?: infer TKey }
|
||||
? TKey extends string
|
||||
? { ' $fragmentRefs'?: { [key in TKey]: TType } }
|
||||
: never
|
||||
: never
|
||||
: never
|
||||
|
||||
// return non-nullable if `fragmentType` is non-nullable
|
||||
export function useFragment<TType>(
|
||||
_documentNode: DocumentNode<TType, any>,
|
||||
fragmentType: FragmentType<DocumentNode<TType, any>>
|
||||
): TType
|
||||
// return nullable if `fragmentType` is nullable
|
||||
export function useFragment<TType>(
|
||||
_documentNode: DocumentNode<TType, any>,
|
||||
fragmentType: FragmentType<DocumentNode<TType, any>> | null | undefined
|
||||
): TType | null | undefined
|
||||
// return array of non-nullable if `fragmentType` is array of non-nullable
|
||||
export function useFragment<TType>(
|
||||
_documentNode: DocumentNode<TType, any>,
|
||||
fragmentType: ReadonlyArray<FragmentType<DocumentNode<TType, any>>>
|
||||
): ReadonlyArray<TType>
|
||||
// return array of nullable if `fragmentType` is array of nullable
|
||||
export function useFragment<TType>(
|
||||
_documentNode: DocumentNode<TType, any>,
|
||||
fragmentType:
|
||||
| ReadonlyArray<FragmentType<DocumentNode<TType, any>>>
|
||||
| null
|
||||
| undefined
|
||||
): ReadonlyArray<TType> | null | undefined
|
||||
export function useFragment<TType>(
|
||||
_documentNode: DocumentNode<TType, any>,
|
||||
fragmentType:
|
||||
| FragmentType<DocumentNode<TType, any>>
|
||||
| ReadonlyArray<FragmentType<DocumentNode<TType, any>>>
|
||||
| null
|
||||
| undefined
|
||||
): TType | ReadonlyArray<TType> | null | undefined {
|
||||
return fragmentType as any
|
||||
}
|
25
examples/with-typescript-graphql/lib/gql/gql.ts
Normal file
25
examples/with-typescript-graphql/lib/gql/gql.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
/* eslint-disable */
|
||||
import * as types from './graphql'
|
||||
import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'
|
||||
|
||||
const documents = {
|
||||
'\n mutation UpdateName($name: String!) {\n updateName(name: $name) {\n id\n name\n status\n }\n }\n':
|
||||
types.UpdateNameDocument,
|
||||
'\n query Viewer {\n viewer {\n id\n name\n status\n }\n }\n':
|
||||
types.ViewerDocument,
|
||||
}
|
||||
|
||||
export function graphql(
|
||||
source: '\n mutation UpdateName($name: String!) {\n updateName(name: $name) {\n id\n name\n status\n }\n }\n'
|
||||
): typeof documents['\n mutation UpdateName($name: String!) {\n updateName(name: $name) {\n id\n name\n status\n }\n }\n']
|
||||
export function graphql(
|
||||
source: '\n query Viewer {\n viewer {\n id\n name\n status\n }\n }\n'
|
||||
): typeof documents['\n query Viewer {\n viewer {\n id\n name\n status\n }\n }\n']
|
||||
|
||||
export function graphql(source: string): unknown
|
||||
export function graphql(source: string) {
|
||||
return (documents as any)[source] ?? {}
|
||||
}
|
||||
|
||||
export type DocumentType<TDocumentNode extends DocumentNode<any, any>> =
|
||||
TDocumentNode extends DocumentNode<infer TType, any> ? TType : never
|
136
examples/with-typescript-graphql/lib/gql/graphql.ts
Normal file
136
examples/with-typescript-graphql/lib/gql/graphql.ts
Normal file
|
@ -0,0 +1,136 @@
|
|||
/* eslint-disable */
|
||||
import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'
|
||||
export type Maybe<T> = T | null
|
||||
export type InputMaybe<T> = Maybe<T>
|
||||
export type Exact<T extends { [key: string]: unknown }> = {
|
||||
[K in keyof T]: T[K]
|
||||
}
|
||||
export type MakeOptional<T, K extends keyof T> = Omit<T, K> & {
|
||||
[SubKey in K]?: Maybe<T[SubKey]>
|
||||
}
|
||||
export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & {
|
||||
[SubKey in K]: Maybe<T[SubKey]>
|
||||
}
|
||||
/** All built-in and custom scalars, mapped to their actual values */
|
||||
export type Scalars = {
|
||||
ID: string
|
||||
String: string
|
||||
Boolean: boolean
|
||||
Int: number
|
||||
Float: number
|
||||
}
|
||||
|
||||
export type Mutation = {
|
||||
__typename?: 'Mutation'
|
||||
updateName: User
|
||||
}
|
||||
|
||||
export type MutationUpdateNameArgs = {
|
||||
name: Scalars['String']
|
||||
}
|
||||
|
||||
export type Query = {
|
||||
__typename?: 'Query'
|
||||
viewer: User
|
||||
}
|
||||
|
||||
export type User = {
|
||||
__typename?: 'User'
|
||||
id: Scalars['ID']
|
||||
name: Scalars['String']
|
||||
status: Scalars['String']
|
||||
}
|
||||
|
||||
export type UpdateNameMutationVariables = Exact<{
|
||||
name: Scalars['String']
|
||||
}>
|
||||
|
||||
export type UpdateNameMutation = {
|
||||
__typename?: 'Mutation'
|
||||
updateName: { __typename?: 'User'; id: string; name: string; status: string }
|
||||
}
|
||||
|
||||
export type ViewerQueryVariables = Exact<{ [key: string]: never }>
|
||||
|
||||
export type ViewerQuery = {
|
||||
__typename?: 'Query'
|
||||
viewer: { __typename?: 'User'; id: string; name: string; status: string }
|
||||
}
|
||||
|
||||
export const UpdateNameDocument = {
|
||||
kind: 'Document',
|
||||
definitions: [
|
||||
{
|
||||
kind: 'OperationDefinition',
|
||||
operation: 'mutation',
|
||||
name: { kind: 'Name', value: 'UpdateName' },
|
||||
variableDefinitions: [
|
||||
{
|
||||
kind: 'VariableDefinition',
|
||||
variable: { kind: 'Variable', name: { kind: 'Name', value: 'name' } },
|
||||
type: {
|
||||
kind: 'NonNullType',
|
||||
type: {
|
||||
kind: 'NamedType',
|
||||
name: { kind: 'Name', value: 'String' },
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
selectionSet: {
|
||||
kind: 'SelectionSet',
|
||||
selections: [
|
||||
{
|
||||
kind: 'Field',
|
||||
name: { kind: 'Name', value: 'updateName' },
|
||||
arguments: [
|
||||
{
|
||||
kind: 'Argument',
|
||||
name: { kind: 'Name', value: 'name' },
|
||||
value: {
|
||||
kind: 'Variable',
|
||||
name: { kind: 'Name', value: 'name' },
|
||||
},
|
||||
},
|
||||
],
|
||||
selectionSet: {
|
||||
kind: 'SelectionSet',
|
||||
selections: [
|
||||
{ kind: 'Field', name: { kind: 'Name', value: 'id' } },
|
||||
{ kind: 'Field', name: { kind: 'Name', value: 'name' } },
|
||||
{ kind: 'Field', name: { kind: 'Name', value: 'status' } },
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
} as unknown as DocumentNode<UpdateNameMutation, UpdateNameMutationVariables>
|
||||
export const ViewerDocument = {
|
||||
kind: 'Document',
|
||||
definitions: [
|
||||
{
|
||||
kind: 'OperationDefinition',
|
||||
operation: 'query',
|
||||
name: { kind: 'Name', value: 'Viewer' },
|
||||
selectionSet: {
|
||||
kind: 'SelectionSet',
|
||||
selections: [
|
||||
{
|
||||
kind: 'Field',
|
||||
name: { kind: 'Name', value: 'viewer' },
|
||||
selectionSet: {
|
||||
kind: 'SelectionSet',
|
||||
selections: [
|
||||
{ kind: 'Field', name: { kind: 'Name', value: 'id' } },
|
||||
{ kind: 'Field', name: { kind: 'Name', value: 'name' } },
|
||||
{ kind: 'Field', name: { kind: 'Name', value: 'status' } },
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
} as unknown as DocumentNode<ViewerQuery, ViewerQueryVariables>
|
2
examples/with-typescript-graphql/lib/gql/index.ts
Normal file
2
examples/with-typescript-graphql/lib/gql/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
export * from './gql'
|
||||
export * from './fragment-masking'
|
|
@ -1,17 +1,17 @@
|
|||
{
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"codegen": "graphql-codegen -r ts-node/register",
|
||||
"dev": "yarn codegen && next",
|
||||
"build": "yarn codegen && next build",
|
||||
"test": "yarn codegen && jest",
|
||||
"codegen": "graphql-codegen -w",
|
||||
"dev": "yarn graphql-codegen && next",
|
||||
"build": "yarn graphql-codegen && next build",
|
||||
"test": "yarn graphql-codegen && jest",
|
||||
"start": "next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.5.10",
|
||||
"graphql-tag": "^2.12.6",
|
||||
"@graphql-tools/load-files": "6.0.18",
|
||||
"@graphql-yoga/node": "^2.2.1",
|
||||
"graphql-yoga": "three",
|
||||
"@graphql-tools/merge": "6.0.18",
|
||||
"@graphql-tools/schema": "6.0.18",
|
||||
"graphql": "15.6.0",
|
||||
|
@ -21,9 +21,8 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@graphql-codegen/typed-document-node": "^2.2.8",
|
||||
"@graphql-codegen/cli": "^2.6.2",
|
||||
"@graphql-codegen/typescript": "^2.4.8",
|
||||
"@graphql-codegen/typescript-operations": "^2.3.5",
|
||||
"@graphql-codegen/cli": "2.13.7",
|
||||
"@graphql-codegen/client-preset": "1.1.0",
|
||||
"@graphql-codegen/typescript-resolvers": "^2.6.1",
|
||||
"@types/jest": "^27.0.2",
|
||||
"@types/mocha": "^9.0.0",
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
import { createServer } from '@graphql-yoga/node'
|
||||
import { createSchema, createYoga } from 'graphql-yoga'
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
import resolvers from 'lib/resolvers'
|
||||
import typeDefs from 'lib/schema'
|
||||
import { NextApiRequest, NextApiResponse } from 'next'
|
||||
|
||||
const server = createServer({
|
||||
schema: {
|
||||
const schema = createSchema({
|
||||
typeDefs: gql(typeDefs),
|
||||
resolvers,
|
||||
},
|
||||
endpoint: '/api/graphql',
|
||||
// graphiql: false // uncomment to disable GraphiQL
|
||||
})
|
||||
|
||||
export default server
|
||||
export default createYoga<{
|
||||
req: NextApiRequest
|
||||
res: NextApiResponse
|
||||
}>({
|
||||
schema,
|
||||
// Needed to be defined explicitly because our endpoint lives at a different path other than `/graphql`
|
||||
graphqlEndpoint: '/api/graphql',
|
||||
})
|
||||
|
|
|
@ -1,13 +1,33 @@
|
|||
import { useMutation, useQuery } from '@apollo/client'
|
||||
import { UpdateNameDocument, ViewerDocument } from 'lib/graphql-operations'
|
||||
import { graphql } from 'lib/gql'
|
||||
import Link from 'next/link'
|
||||
import { useState } from 'react'
|
||||
import { initializeApollo } from '../lib/apollo'
|
||||
|
||||
const updateNameDocument = graphql(/* GraphQL */ `
|
||||
mutation UpdateName($name: String!) {
|
||||
updateName(name: $name) {
|
||||
id
|
||||
name
|
||||
status
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
const viewerDocument = graphql(/* GraphQL */ `
|
||||
query Viewer {
|
||||
viewer {
|
||||
id
|
||||
name
|
||||
status
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
const Index = () => {
|
||||
const { data } = useQuery(ViewerDocument)
|
||||
const { data } = useQuery(viewerDocument)
|
||||
const [newName, setNewName] = useState('')
|
||||
const [updateNameMutation] = useMutation(UpdateNameDocument)
|
||||
const [updateNameMutation] = useMutation(updateNameDocument)
|
||||
|
||||
const onChangeName = () => {
|
||||
updateNameMutation({
|
||||
|
@ -21,15 +41,16 @@ const Index = () => {
|
|||
if (!data) return // Cancel updating name in cache if no data is returned from mutation.
|
||||
// Read the data from our cache for this query.
|
||||
const result = cache.readQuery({
|
||||
query: ViewerDocument,
|
||||
query: viewerDocument,
|
||||
})
|
||||
|
||||
const newViewer = result ? { ...result.viewer } : null
|
||||
// Add our comment from the mutation to the end.
|
||||
// Write our data back to the cache.
|
||||
if (newViewer) {
|
||||
newViewer.name = data.updateName.name
|
||||
cache.writeQuery({
|
||||
query: ViewerDocument,
|
||||
query: viewerDocument,
|
||||
data: { viewer: newViewer },
|
||||
})
|
||||
}
|
||||
|
@ -37,7 +58,7 @@ const Index = () => {
|
|||
})
|
||||
}
|
||||
|
||||
const viewer = data?.viewer
|
||||
const viewer = data.viewer
|
||||
|
||||
return viewer ? (
|
||||
<div>
|
||||
|
@ -62,7 +83,7 @@ export async function getStaticProps() {
|
|||
const apolloClient = initializeApollo()
|
||||
|
||||
await apolloClient.query({
|
||||
query: ViewerDocument,
|
||||
query: viewerDocument,
|
||||
})
|
||||
|
||||
return {
|
||||
|
|
Loading…
Reference in a new issue