gulp: disable graphql-codegen's watch feature (#16411)

* gulp: disable graphql-codegen's watch feature

Due to https://github.com/dotansimha/graphql-code-generator/issues/1796,
gulp is currently consuming a non-trivial amount of a CPU core watching
for updates that regenerate the GraphQL operations files. Let's use
Chokidar directly (via Gulp) and then we can be smarter about when we
actually trigger the several second generation process.

* Hush eslint.

* Simplify logic and ensure graphql types are generated before first run of webpack

Co-authored-by: Erik Seliger <erikseliger@me.com>
This commit is contained in:
Adam Harvey 2020-12-07 01:22:35 -08:00 committed by GitHub
parent 8ed2c317b0
commit bebeec87ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 75 additions and 13 deletions

View File

@ -24,17 +24,17 @@ const BROWSER_DOCUMENTS_GLOB = [
'!**/*.d.ts',
]
// Define ALL_DOCUMENTS_GLOB as the union of the previous glob arrays.
const ALL_DOCUMENTS_GLOB = [...new Set([...SHARED_DOCUMENTS_GLOB, ...WEB_DOCUMENTS_GLOB, ...BROWSER_DOCUMENTS_GLOB])]
const plugins = [`${SHARED_FOLDER}/dev/extractGraphQlOperationCodegenPlugin.js`, 'typescript', 'typescript-operations']
/**
* Generates TypeScript files with types for all GraphQL operations.
*
* @param {{ watch?: boolean }} [options]
*/
async function generateGraphQlOperations({ watch } = {}) {
async function generateGraphQlOperations() {
await generate(
{
watch,
schema: SCHEMA_PATH,
hooks: {
afterOneFileWrite: 'prettier --write',
@ -103,4 +103,9 @@ async function generateGraphQlOperations({ watch } = {}) {
)
}
module.exports = { generateGraphQlOperations, SHARED_DOCUMENTS_GLOB, WEB_DOCUMENTS_GLOB }
module.exports = {
generateGraphQlOperations,
SHARED_DOCUMENTS_GLOB,
WEB_DOCUMENTS_GLOB,
ALL_DOCUMENTS_GLOB,
}

View File

@ -9,7 +9,7 @@ const { readFile, writeFile, mkdir } = require('mz/fs')
const path = require('path')
const { format, resolveConfig } = require('prettier')
const { generateGraphQlOperations } = require('./dev/generateGraphQlOperations')
const { generateGraphQlOperations, ALL_DOCUMENTS_GLOB } = require('./dev/generateGraphQlOperations')
const GRAPHQL_SCHEMA_PATH = path.join(__dirname, '../../cmd/frontend/graphqlbackend/schema.graphql')
@ -66,11 +66,63 @@ async function watchGraphQlSchema() {
})
}
/**
* Determine whether to regenerate GraphQL operations based on the given
* Chokidar event. If we can determine that the file being modified is a
* non-GraphQL-using TypeScript or JavaScript file, then we can skip the
* expensive generation step.
*
* @param {string} type
* @param {string} name
* @returns bool
*/
async function shouldRegenerateGraphQlOperations(type, name) {
if (type === 'unlink' || type === 'unlinkDir') {
// For all deletions, we'll regenerate, since we don't know if the file(s)
// that were deleted were used when generating the GraphQL operations.
return true
}
// If we're watching a JavaScript or TypeScript file, then we should only
// regenerate if there are gql-tagged strings. But first, we have to figure
// out if it is that type of file.
const isJS = ['.tsx', '.ts', '.jsx', '.js'].reduce((previous, extension) => {
if (previous) {
return previous
}
return name.endsWith(extension)
}, false)
if (isJS) {
// Look for the tagged string in the most naïve way imaginable.
return (await readFile(name)).includes('gql`')
}
// Finally, for non-JavaScript/TypeScript files, we'll be safe and always
// regenerate.
return true
}
/**
* Generates the new query-specific types on file changes.
*/
async function watchGraphQlOperations() {
await generateGraphQlOperations({ watch: true })
function watchGraphQlOperations() {
// Although graphql-codegen has watching capabilities, they don't appear to
// use chokidar correctly and rely on polling. Instead, let's get gulp to
// watch for us, since we know it'll do it more efficiently, and then we can
// trigger the code generation more selectively.
return gulp
.watch(ALL_DOCUMENTS_GLOB, {
ignored: /** @param {string} name */ name => name.endsWith('graphql-operations.ts'),
})
.on('all', (type, name) => {
;(async () => {
if (await shouldRegenerateGraphQlOperations(type, name)) {
await generateGraphQlOperations()
}
})().catch(error => {
console.error(error)
})
})
}
/**

View File

@ -97,14 +97,14 @@ async function webpackDevelopmentServer() {
/**
* Builds everything.
*/
const build = gulp.series(gulp.parallel(schema, graphQlOperations, graphQlSchema), gulp.parallel(webpack))
const build = gulp.series(gulp.parallel(schema, graphQlOperations, graphQlSchema), webpack)
/**
* Starts a development server, watches everything and rebuilds on file changes.
*/
const development = gulp.series(
// Ensure the typings that TypeScript depends on are build to avoid first-time-run errors
gulp.parallel(schema, graphQlSchema),
gulp.parallel(schema, graphQlOperations, graphQlSchema),
gulp.parallel(watchSchema, watchGraphQlSchema, watchGraphQlOperations, webpackDevelopmentServer)
)
@ -114,7 +114,7 @@ const development = gulp.series(
*/
const watch = gulp.series(
// Ensure the typings that TypeScript depends on are build to avoid first-time-run errors
gulp.parallel(schema, graphQlSchema),
gulp.parallel(schema, graphQlOperations, graphQlSchema),
gulp.parallel(watchSchema, watchGraphQlSchema, watchGraphQlOperations, watchWebpack)
)

View File

@ -16,10 +16,15 @@ const { webpack: webWebpack, webpackDevServer: webWebpackDevServer } = require('
*/
const generate = gulp.parallel(schema, graphQlSchema, graphQlOperations)
/**
* Starts all watchers on schema files.
*/
const watchGenerators = gulp.parallel(watchSchema, watchGraphQlSchema, watchGraphQlOperations)
/**
* Generates files needed for builds whenever files change.
*/
const watchGenerate = gulp.series(generate, gulp.parallel(watchSchema, watchGraphQlSchema, watchGraphQlOperations))
const watchGenerate = gulp.series(generate, watchGenerators)
/**
* Builds everything.
@ -29,7 +34,7 @@ const build = gulp.series(generate, webWebpack)
/**
* Watches everything and rebuilds on file changes.
*/
const dev = gulp.parallel(watchGenerate, webWebpackDevServer)
const dev = gulp.series(generate, gulp.parallel(watchGenerators, webWebpackDevServer))
module.exports = {
generate,