Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(gatsby): Add option to emit TS types during build #36405

Merged
merged 3 commits into from
Aug 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/docs/how-to/local-development/graphql-typegen.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ examples:

If you're already using [Gatsby with TypeScript](/docs/how-to/custom-configuration/typescript) and manually typing the results of your queries, you'll learn in this guide how Gatsby's automatic GraphQL Typegen feature can make your life easier. By relying on the types that are generated by Gatsby itself and using autocompletion for GraphQL queries in your IDE you'll be able to write GraphQL queries quicker and safer.

This feature was added in `gatsby@4.15.0`.
This feature was added in `gatsby@4.15.0`. By default, this feature is only generating files during `gatsby develop`.

## Prerequisites

Expand Down
4 changes: 4 additions & 0 deletions docs/docs/reference/config-files/gatsby-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,10 @@ module.exports = {

You can specifiy the path of the generated TypeScript types file relative to the site root. Default: `src/gatsby-types.d.ts`.

### generateOnBuild

By default, `graphqlTypegen` is only run during `gatsby develop`. Set this option to `true` to create the `src/gatsby-types.d.ts` file also during `gatsby build`. Default: `false`.

## polyfill

Gatsby uses the ES6 Promise API. Because some browsers don't support this, Gatsby includes a Promise polyfill by default.
Expand Down
1 change: 1 addition & 0 deletions packages/gatsby/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ export const graphql: (query: TemplateStringsArray) => StaticQueryDocument

export interface GraphQLTypegenOptions {
typesOutputPath?: string
generateOnBuild?: boolean
}

/**
Expand Down
37 changes: 37 additions & 0 deletions packages/gatsby/src/commands/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import {
import { validateEngines } from "../utils/validate-engines"
import { constructConfigObject } from "../utils/gatsby-cloud-config"
import { waitUntilWorkerJobsAreComplete } from "../utils/jobs/worker-messaging"
import { writeTypeScriptTypes } from "../utils/graphql-typegen/ts-codegen"

module.exports = async function build(
program: IBuildArgs,
Expand Down Expand Up @@ -419,6 +420,42 @@ module.exports = async function build(
await waitMaterializePageMode
const waitWorkerPoolEnd = Promise.all(workerPool.end())

// create scope so we don't leak state object
{
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The position of this is quite arbitrary (at the very end of the build). Any reason to not keep it there?

const { schema, definitions, config } = store.getState()
const directory = program.directory
const graphqlTypegenOptions = config.graphqlTypegen

// Only generate types when the option is enabled
if (graphqlTypegenOptions && graphqlTypegenOptions.generateOnBuild) {
const typegenActivity = reporter.activityTimer(
`Generating TypeScript types`,
{
parentSpan: buildSpan,
}
)
typegenActivity.start()

try {
await writeTypeScriptTypes(
directory,
schema,
definitions,
graphqlTypegenOptions
)
} catch (err) {
typegenActivity.panicOnBuild({
id: `12100`,
context: {
sourceMessage: err,
},
})
}

typegenActivity.end()
}
}

{
let SSGCount = 0
let DSGCount = 0
Expand Down
22 changes: 21 additions & 1 deletion packages/gatsby/src/joi-schemas/__tests__/joi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ describe(`gatsby config`, () => {
expect.objectContaining({
graphqlTypegen: {
typesOutputPath: `src/gatsby-types.d.ts`,
generateOnBuild: false,
},
})
)
Expand All @@ -201,12 +202,12 @@ describe(`gatsby config`, () => {
expect.objectContaining({
graphqlTypegen: {
typesOutputPath: `src/gatsby-types.d.ts`,
generateOnBuild: false,
},
})
)
})

// TODO: Write "return partial defaults for graphqlTypegen when partial options object is set" test with more graphqlTypegen options
it(`graphqlTypegen config object can be overwritten`, () => {
const config = {
graphqlTypegen: {
Expand All @@ -219,6 +220,25 @@ describe(`gatsby config`, () => {
expect.objectContaining({
graphqlTypegen: {
typesOutputPath: `gatsby-types.d.ts`,
generateOnBuild: false,
},
})
)
})

it(`returns partial defaults for graphqlTypegen when partial options object is set`, () => {
const config = {
graphqlTypegen: {
generateOnBuild: true,
},
}

const result = gatsbyConfigSchema.validate(config)
expect(result.value).toEqual(
expect.objectContaining({
graphqlTypegen: {
typesOutputPath: `src/gatsby-types.d.ts`,
generateOnBuild: true,
},
})
)
Expand Down
2 changes: 2 additions & 0 deletions packages/gatsby/src/joi-schemas/joi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export const gatsbyConfigSchema: Joi.ObjectSchema<IGatsbyConfig> = Joi.object()
Joi.object()
.keys({
typesOutputPath: Joi.string().default(DEFAULT_TYPES_OUTPUT_PATH),
generateOnBuild: Joi.boolean().default(false),
})
.unknown(false)
)
Expand All @@ -69,6 +70,7 @@ export const gatsbyConfigSchema: Joi.ObjectSchema<IGatsbyConfig> = Joi.object()
if (value === true) {
return {
typesOutputPath: DEFAULT_TYPES_OUTPUT_PATH,
generateOnBuild: false,
}
}

Expand Down
1 change: 1 addition & 0 deletions packages/gatsby/src/redux/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ export interface IGatsbyFunction {

export interface IGraphQLTypegenOptions {
typesOutputPath: string
generateOnBuild: boolean
}

export interface IGatsbyConfig {
Expand Down
6 changes: 4 additions & 2 deletions packages/gatsby/src/services/initialize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -659,10 +659,12 @@ export async function initialize({

const workerPool = WorkerPool.create()

// This is only run during `gatsby develop`
if (state.config.graphqlTypegen) {
telemetry.trackFeatureIsUsed(`GraphQLTypegen`)
writeGraphQLConfig(program)
// This is only run during `gatsby develop`
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is correcting the implementation to actually do what the comment said (this file is not needed during gatsby build)

if (process.env.gatsby_executing_command === `develop`) {
writeGraphQLConfig(program)
}
}

return {
Expand Down