refactor: remove nexus-decorators, add data context (#18211)

- Add `@packages/data-context`
- Add `yarn gulp makePackage` for scaffolding a new server package
- Removes `nexus-decorators` in favor of regular Nexus, creating better separation between data & schema
- Possible to launch project in different browser types

Co-authored-by: Jessica Sachs <jess@jessicasachs.io>
Co-authored-by: Lachlan Miller <lachlan.miller.1990@outlook.com>
Co-authored-by: Cesar <cesaravitia@outlook.com>
This commit is contained in:
Tim Griesser
2021-09-27 11:49:39 -04:00
committed by GitHub
parent 3a4b971e2f
commit 1d5b185c5b
159 changed files with 2813 additions and 3668 deletions
+16 -8
View File
@@ -1,7 +1,7 @@
import gulp from 'gulp'
import { autobarrelWatcher } from './tasks/gulpAutobarrel'
import { startCypressWatch } from './tasks/gulpCypress'
import { graphqlCodegen, graphqlCodegenWatch, nexusCodegen, nexusCodegenWatch, printUrqlSchema, syncRemoteGraphQL } from './tasks/gulpGraphql'
import { graphqlCodegen, graphqlCodegenWatch, nexusCodegen, nexusCodegenWatch, generateFrontendSchema, syncRemoteGraphQL } from './tasks/gulpGraphql'
import { checkTs } from './tasks/gulpTsc'
import { viteApp, viteCleanApp, viteCleanLaunchpad, viteLaunchpad } from './tasks/gulpVite'
import { makePathMap } from './utils/makePathMap'
@@ -9,7 +9,7 @@ import { setGulpGlobal } from './gulpConstants'
import { makePackage } from './tasks/gulpMakePackage'
gulp.task(
'dev',
'codegen',
gulp.series(
// Autobarrel watcher
autobarrelWatcher,
@@ -17,16 +17,24 @@ gulp.task(
// Fetch the latest "remote" schema from the Cypress cloud
syncRemoteGraphQL,
gulp.parallel(
// Clean the vite apps
viteCleanApp,
viteCleanLaunchpad,
),
// Codegen for our GraphQL Server so we have the latest schema to build the frontend codegen correctly
nexusCodegenWatch,
// ... and generate the correct GraphQL types for the frontend
graphqlCodegenWatch,
),
)
gulp.task(
'dev',
gulp.series(
'codegen',
gulp.parallel(
// Clean the vite apps
viteCleanApp,
viteCleanLaunchpad,
),
// Now that we have the codegen, we can start the frontend(s)
gulp.parallel(
@@ -98,7 +106,7 @@ gulp.task(
gulp.task(makePackage)
gulp.task(checkTs)
gulp.task(syncRemoteGraphQL)
gulp.task(printUrqlSchema)
gulp.task(generateFrontendSchema)
gulp.task(makePathMap)
gulp.task(nexusCodegen)
gulp.task(nexusCodegenWatch)
+38 -4
View File
@@ -4,7 +4,7 @@ import path from 'path'
import pDefer from 'p-defer'
import chalk from 'chalk'
import fs from 'fs-extra'
import { buildSchema, introspectionFromSchema } from 'graphql'
import { buildSchema, extendSchema, GraphQLSchema, introspectionFromSchema, isObjectType, parse } from 'graphql'
import { minifyIntrospectionQuery } from '@urql/introspection'
import { nexusTypegen, watchNexusTypegen } from '../utils/nexusTypegenUtil'
@@ -99,19 +99,53 @@ export async function syncRemoteGraphQL () {
// TODO(tim): fix
await fs.ensureDir(path.join(monorepoPaths.pkgGraphql, 'src/gen'))
await fs.promises.writeFile(path.join(monorepoPaths.pkgGraphql, 'schemas/cloud.graphql'), body)
await fs.promises.writeFile(path.join(monorepoPaths.pkgGraphql, 'src/gen/cloud-introspection.gen.json'), JSON.stringify(introspectionFromSchema(buildSchema(body)), null, 2))
} catch {}
}
export async function printUrqlSchema () {
/**
* Generates the schema so the urql GraphCache is
*/
export async function generateFrontendSchema () {
const schemaContents = await fs.promises.readFile(path.join(monorepoPaths.pkgGraphql, 'schemas/schema.graphql'), 'utf8')
const schema = buildSchema(schemaContents, { assumeValid: true })
const testExtensions = generateTestExtensions(schema)
const extendedSchema = extendSchema(schema, parse(testExtensions))
const URQL_INTROSPECTION_PATH = path.join(monorepoPaths.pkgFrontendShared, 'src/generated/urql-introspection.gen.ts')
await fs.ensureDir(path.dirname(URQL_INTROSPECTION_PATH))
await fs.writeFile(path.join(monorepoPaths.pkgFrontendShared, 'src/generated/schema-for-tests.gen.json'), JSON.stringify(introspectionFromSchema(extendedSchema), null, 2))
await fs.promises.writeFile(
URQL_INTROSPECTION_PATH,
`/* eslint-disable */\nexport const urqlSchema = ${JSON.stringify(minifyIntrospectionQuery(introspectionFromSchema(buildSchema(schemaContents))), null, 2)} as const`,
`/* eslint-disable */\nexport const urqlSchema = ${JSON.stringify(minifyIntrospectionQuery(introspectionFromSchema(schema)), null, 2)} as const`,
)
}
/**
* Adds two fields to the GraphQL types specific to testing
*
* @param schema
* @returns
*/
function generateTestExtensions (schema: GraphQLSchema) {
const objects: string[] = []
const typesMap = schema.getTypeMap()
for (const [typeName, type] of Object.entries(typesMap)) {
if (!typeName.startsWith('__') && isObjectType(type)) {
if (isObjectType(type)) {
objects.push(typeName)
}
}
}
return `
union TestUnion = ${objects.join(' | ')}
extend type Query {
testFragmentMember: TestUnion!
testFragmentMemberList: [TestUnion!]!
}
`
}
+1
View File
@@ -57,6 +57,7 @@ export async function makePackage () {
description: results.description,
'main': 'index.js',
'browser': 'src/index.ts',
'types': 'src/index.ts',
scripts: {
'build-prod': 'tsc || echo \'built, with errors\'',
'check-ts': 'tsc --noEmit',
+55
View File
@@ -0,0 +1,55 @@
// import path from 'path'
// import fs from 'fs-extra'
// import dedent from 'dedent'
// import { monorepoPaths } from '../monorepoPaths'
/**
* TODO(tim): revisit to see if this is useful
* Rather than copy-paste the Cypress d.ts into the @packages/types, we can regex out the ones we want -
* so we keep a single source of truth updated while getting the types we need for type-safety without
* leaking globals from everything into the server-side app
*/
// export async function extractCypressNamespacedTypes () {
// const cypressTypeFile = await fs.readFile(path.join(monorepoPaths.root, 'cli/types/cypress.d.ts'), 'utf8')
// const interfacesToExtract: Record<string, RegExp> = {
// RuntimeConfigOptions: /( +)interface RuntimeConfigOptions {((\s|.)*?)(\1)}\n\n/gm,
// ResolvedConfigOptions: /( +)interface ResolvedConfigOptions {((\s|.)*?)(\1)}\n\n/gm,
// Browser: /( +)interface Browser {((\s|.)*?)(\1)}\n\n/gm,
// RemoteState: /( +)interface RemoteState {((\s|.)*?)(\1)}\n\n/gm,
// Spec: /( +)interface Spec {((\s|.)*?)(\1)}\n\n/gm,
// ClientCertificate: /( +)interface ClientCertificate {((\s|.)*?)(\1)}\n\n/gm,
// PEMCert: /( +)interface PEMCert {((\s|.)*?)(\1)}\n\n/gm,
// PFXCert: /( +)interface PFXCert {((\s|.)*?)(\1)}\n\n/gm,
// BrowserName: /( +)type BrowserName = (.*?)\n/gm,
// BrowserChannel: /( +)type BrowserChannel = (.*?)\n/gm,
// BrowserFamily: /( +)type BrowserFamily = (.*?)\n/gm,
// CypressSpecType: /( +)type CypressSpecType = (.*?)\n/gm,
// scrollBehaviorOptions: /( +)type scrollBehaviorOptions = (.*?)\n/gm,
// TestingType: /( +)type TestingType = (.*?)\n/gm,
// }
// const typeDefs: string[] = []
// for (const key of Object.keys(interfacesToExtract).sort()) {
// const matched = cypressTypeFile.match(interfacesToExtract[key])
// if (!matched) {
// throw new Error(`Missing ${key} in extractCypressNamespacedTypes: ${__filename}`)
// }
// if (matched.length > 1) {
// throw new Error(`Mutliple matches for ${key} in extractCypressNamespacedTypes: ${__filename}`)
// }
// typeDefs.push(matched[0])
// }
// const typesToPrint = [
// typeDefs.map((def) => `// Auto-generated by ${__filename}, do not edit this type directly\nexport ${dedent(def)}\n`).join('\n'),
// ].join('\n')
// const fileContents = `type Nullable<T> = T | null\n\n${typesToPrint}`
// await fs.writeFile(path.join(monorepoPaths.pkgTypes, 'src/cypress-extracted.gen.ts'), fileContents)
// }
+2
View File
@@ -22,12 +22,14 @@ export function viteLaunchpad () {
export function viteCleanApp () {
return spawned('vite-clean', `yarn clean`, {
cwd: monorepoPaths.pkgApp,
waitForExit: true,
})
}
export function viteCleanLaunchpad () {
return spawned('vite-clean', `yarn clean`, {
cwd: monorepoPaths.pkgLaunchpad,
waitForExit: true,
})
}
+1 -1
View File
@@ -36,7 +36,7 @@ ${dirs
`pkg-${dir}`,
)}: path.join(__dirname, '../../packages/${dir}')`
}).join(',\n')}
}
} as const
`,
)
}
+2 -2
View File
@@ -6,7 +6,7 @@ import _ from 'lodash'
import path from 'path'
import fs from 'fs-extra'
import { printUrqlSchema } from '../tasks/gulpGraphql'
import { generateFrontendSchema } from '../tasks/gulpGraphql'
import { monorepoPaths } from '../monorepoPaths'
interface NexusTypegenCfg {
@@ -82,7 +82,7 @@ export async function nexusTypegen (cfg: NexusTypegenCfg) {
out.on('error', dfd.reject)
return dfd.promise.then(() => {
return printUrqlSchema()
return generateFrontendSchema()
})
}