mirror of
https://github.com/cypress-io/cypress.git
synced 2026-04-24 07:59:12 -05:00
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:
@@ -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)
|
||||
|
||||
@@ -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!]!
|
||||
}
|
||||
`
|
||||
}
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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)
|
||||
// }
|
||||
@@ -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,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ ${dirs
|
||||
`pkg-${dir}`,
|
||||
)}: path.join(__dirname, '../../packages/${dir}')`
|
||||
}).join(',\n')}
|
||||
}
|
||||
} as const
|
||||
`,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user