Skip to content

Commit 2cbcbb3

Browse files
saihajcharlypoly
andauthored
feat: add emitLegacyCommonJSImports flag (#8077)
* feat: add `emitLegacyCommonJSImports` flag * add changeset * update docs * fix * fix(emitLegacyCommonJSImports): normalize value across plugins and presets + fix specs Introduced a `shouldEmitLegacyCommonJSImports()` helper to get proper value Co-authored-by: Charly POLY <cpoly55@gmail.com>
1 parent 9e5773c commit 2cbcbb3

31 files changed

+173
-67
lines changed

‎.changeset/kind-taxis-refuse.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
---
2+
'@graphql-codegen/cli': minor
3+
'@graphql-codegen/visitor-plugin-common': minor
4+
'@graphql-codegen/gql-tag-operations': minor
5+
'@graphql-codegen/near-operation-file-preset': minor
6+
'@graphql-codegen/plugin-helpers': minor
7+
---
8+
9+
Add new flag to emit legacy common js imports. Default it will be `true` this way it ensure that generated code works with [non-compliant bundlers](https://github.com/dotansimha/graphql-code-generator/issues/8065).
10+
11+
You can use the option in your config:
12+
```yaml
13+
schema: 'schema.graphql'
14+
documents:
15+
- 'src/**/*.graphql'
16+
emitLegacyCommonJSImports: true
17+
```
18+
19+
Alternative you can use the CLI to set this option:
20+
```bash
21+
$ codegen --config-file=config.yml --emit-legacy-common-js-imports
22+
```

‎dev-test/codegen.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
hooks:
22
afterAllFileWrite:
33
- prettier --write
4+
emitLegacyCommonJSImports: false
45
generates:
56
./dev-test/test-schema/resolvers-types.ts:
67
schema: ./dev-test/test-schema/schema-text.js

‎dev-test/githunt/__generated__/comment.query.stencil-component.tsx

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎dev-test/githunt/__generated__/feed-entry.fragment.stencil-component.tsx

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎dev-test/githunt/__generated__/feed.query.stencil-component.tsx

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎dev-test/githunt/__generated__/submit-comment.mutation.stencil-component.tsx

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎dev-test/gql-tag-operations-urql/gql/gql.d.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/
44
declare module '@urql/core' {
55
export function gql(
66
source: '\n query Foo {\n Tweets {\n id\n }\n }\n'
7-
): typeof import('./graphql').FooDocument;
7+
): typeof import('./graphql.js').FooDocument;
88
export function gql(
99
source: '\n fragment Lel on Tweet {\n id\n body\n }\n'
10-
): typeof import('./graphql').LelFragmentDoc;
10+
): typeof import('./graphql.js').LelFragmentDoc;
1111
export function gql(
1212
source: '\n query Bar {\n Tweets {\n ...Lel\n }\n }\n'
13-
): typeof import('./graphql').BarDocument;
13+
): typeof import('./graphql.js').BarDocument;
1414
export function gql(source: string): unknown;
1515

1616
export type DocumentType<TDocumentNode extends DocumentNode<any, any>> = TDocumentNode extends DocumentNode<

‎dev-test/star-wars/__generated__/CreateReviewForEpisode.tsx

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎dev-test/star-wars/__generated__/HeroAndFriendsNames.tsx

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎dev-test/star-wars/__generated__/HeroAppearsIn.tsx

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎dev-test/star-wars/__generated__/HeroDetails.tsx

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎dev-test/star-wars/__generated__/HeroDetailsFragment.tsx

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎dev-test/star-wars/__generated__/HeroDetailsWithFragment.tsx

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎dev-test/star-wars/__generated__/HeroName.tsx

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎dev-test/star-wars/__generated__/HeroNameConditional.tsx

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎dev-test/star-wars/__generated__/HeroParentTypeDependentField.tsx

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎dev-test/star-wars/__generated__/HeroTypeDependentAliasedField.tsx

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎dev-test/star-wars/__generated__/HumanFields.tsx

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎dev-test/star-wars/__generated__/HumanWithNullWeight.tsx

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎dev-test/star-wars/__generated__/TwoHeroes.tsx

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎packages/graphql-codegen-cli/src/codegen.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { GraphQLError, GraphQLSchema, DocumentNode } from 'graphql';
1616
import { getPluginByName } from './plugins.js';
1717
import { getPresetByName } from './presets.js';
1818
import { debugLog } from './utils/debugging.js';
19-
import { CodegenContext, ensureContext } from './config.js';
19+
import { CodegenContext, ensureContext, shouldEmitLegacyCommonJSImports } from './config.js';
2020
import fs from 'fs';
2121
import path from 'path';
2222
import { cpus } from 'os';
@@ -315,6 +315,7 @@ export async function executeCodegen(input: CodegenContext | Types.Config): Prom
315315
...(typeof outputFileTemplateConfig === 'string'
316316
? { value: outputFileTemplateConfig }
317317
: outputFileTemplateConfig),
318+
emitLegacyCommonJSImports: shouldEmitLegacyCommonJSImports(config, filename),
318319
};
319320

320321
const outputs: Types.GenerateOptions[] = hasPreset
@@ -350,7 +351,10 @@ export async function executeCodegen(input: CodegenContext | Types.Config): Prom
350351

351352
const process = async (outputArgs: Types.GenerateOptions) => {
352353
const output = await codegen({
353-
...outputArgs,
354+
...{
355+
...outputArgs,
356+
emitLegacyCommonJSImports: shouldEmitLegacyCommonJSImports(config, outputArgs.filename),
357+
},
354358
cache,
355359
});
356360
result.push({

‎packages/graphql-codegen-cli/src/config.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export type YamlCliFlags = {
3131
errorsOnly: boolean;
3232
profile: boolean;
3333
ignoreNoDocuments?: boolean;
34+
emitLegacyCommonJSImports?: boolean;
3435
};
3536

3637
export function generateSearchPlaces(moduleName: string) {
@@ -287,6 +288,11 @@ export function updateContextWithCliFlags(context: CodegenContext, cliFlags: Yam
287288
config.ignoreNoDocuments = cliFlags['ignore-no-documents'] === true;
288289
}
289290

291+
if (cliFlags['emit-legacy-common-js-imports'] !== undefined) {
292+
// for some reason parsed value is `'false'` string so this ensure it always is a boolean.
293+
config.emitLegacyCommonJSImports = cliFlags['emit-legacy-common-js-imports'] === true;
294+
}
295+
290296
if (cliFlags.project) {
291297
context.useProject(cliFlags.project);
292298
}
@@ -439,3 +445,19 @@ function addHashToDocumentFiles(documentFilesPromise: Promise<Types.DocumentFile
439445
})
440446
);
441447
}
448+
449+
export function shouldEmitLegacyCommonJSImports(config: Types.Config, outputPath: string): boolean {
450+
const globalValue = config.emitLegacyCommonJSImports === undefined ? true : !!config.emitLegacyCommonJSImports;
451+
// const outputConfig = config.generates[outputPath];
452+
453+
// if (!outputConfig) {
454+
// debugLog(`Couldn't find a config of ${outputPath}`);
455+
// return globalValue;
456+
// }
457+
458+
// if (isConfiguredOutput(outputConfig) && typeof outputConfig.emitLegacyCommonJSImports === 'boolean') {
459+
// return outputConfig.emitLegacyCommonJSImports;
460+
// }
461+
462+
return globalValue;
463+
}

‎packages/graphql-codegen-cli/tests/cli-flags.spec.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,34 @@ describe('CLI Flags', () => {
134134
expect(config.ignoreNoDocuments).toBeFalsy();
135135
});
136136

137+
it('Should overwrite emitLegacyCommonJSImports config using cli flags to true', async () => {
138+
mockConfig(`
139+
schema: schema.graphql
140+
emitLegacyCommonJSImports: false
141+
generates:
142+
file.ts:
143+
- plugin
144+
`);
145+
const args = createArgv('--emit-legacy-common-js-imports');
146+
const context = await createContext(parseArgv(args));
147+
const config = context.getConfig();
148+
expect(config.emitLegacyCommonJSImports).toBeTruthy();
149+
});
150+
151+
it('Should overwrite emitLegacyCommonJSImports config using cli flags to false', async () => {
152+
mockConfig(`
153+
schema: schema.graphql
154+
emitLegacyCommonJSImports: true
155+
generates:
156+
file.ts:
157+
- plugin
158+
`);
159+
const args = createArgv('--emit-legacy-common-js-imports=false');
160+
const context = await createContext(parseArgv(args));
161+
const config = context.getConfig();
162+
expect(config.emitLegacyCommonJSImports).toBeFalsy();
163+
});
164+
137165
it('Should overwrite ignoreNoDocuments config using cli flags to true', async () => {
138166
mockConfig(`
139167
schema: schema.graphql

‎packages/plugins/other/visitor-plugin-common/src/imports.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export type ImportDeclaration<T = string> = {
77
baseOutputDir: string;
88
baseDir: string;
99
typesImport: boolean;
10+
emitLegacyCommonJSImports: boolean;
1011
};
1112

1213
export type ImportSource<T = string> = {
@@ -56,9 +57,14 @@ export function generateImportStatement(statement: ImportDeclaration): string {
5657
importSource.identifiers && importSource.identifiers.length
5758
? `{ ${Array.from(new Set(importSource.identifiers)).join(', ')} }`
5859
: '*';
60+
const importExtension =
61+
importPath.startsWith('/') || importPath.startsWith('.') ? (statement.emitLegacyCommonJSImports ? '' : '.js') : '';
5962
const importAlias = importSource.namespace ? ` as ${importSource.namespace}` : '';
6063
const importStatement = typesImport ? 'import type' : 'import';
61-
return `${importStatement} ${importNames}${importAlias} from '${importPath}';${importAlias ? '\n' : ''}`;
64+
return `${importStatement} ${importNames}${importAlias} from '${importPath}${importExtension}';${
65+
importAlias ? '\n' : ''
66+
}`;
67+
// return `${importStatement} ${importNames}${importAlias} from '${importPath}';${importAlias ? '\n' : ''}`;
6268
}
6369

6470
function resolveImportPath(baseDir: string, outputPath: string, sourcePath: string) {

‎packages/plugins/typescript/gql-tag-operations/src/index.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,22 @@ export const plugin: PluginFunction<{
2525
sourcesWithOperations: Array<SourceWithOperations>;
2626
useTypeImports?: boolean;
2727
augmentedModuleName?: string;
28-
}> = (_, __, { sourcesWithOperations, useTypeImports, augmentedModuleName }, _info) => {
28+
emitLegacyCommonJSImports?: boolean;
29+
}> = (_, __, { sourcesWithOperations, useTypeImports, augmentedModuleName, emitLegacyCommonJSImports }, _info) => {
2930
if (!sourcesWithOperations) {
3031
return '';
3132
}
3233

3334
if (augmentedModuleName == null) {
3435
return [
35-
`import * as graphql from './graphql.js';\n`,
36+
`import * as graphql from './graphql${emitLegacyCommonJSImports ? '' : '.js'}';\n`,
3637
`${
3738
useTypeImports ? 'import type' : 'import'
3839
} { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';\n`,
3940
`\n`,
4041
...getDocumentRegistryChunk(sourcesWithOperations),
4142
`\n`,
42-
...getGqlOverloadChunk(sourcesWithOperations, 'lookup'),
43+
...getGqlOverloadChunk(sourcesWithOperations, 'lookup', emitLegacyCommonJSImports),
4344
`\n`,
4445
`export function gql(source: string): unknown;\n`,
4546
`export function gql(source: string) {\n`,
@@ -55,7 +56,7 @@ export const plugin: PluginFunction<{
5556
`declare module "${augmentedModuleName}" {`,
5657
[
5758
`\n`,
58-
...getGqlOverloadChunk(sourcesWithOperations, 'augmented'),
59+
...getGqlOverloadChunk(sourcesWithOperations, 'augmented', emitLegacyCommonJSImports),
5960
`export function gql(source: string): unknown;\n`,
6061
`\n`,
6162
...documentTypePartial,
@@ -84,7 +85,11 @@ function getDocumentRegistryChunk(sourcesWithOperations: Array<SourceWithOperati
8485

8586
type Mode = 'lookup' | 'augmented';
8687

87-
function getGqlOverloadChunk(sourcesWithOperations: Array<SourceWithOperations>, mode: Mode) {
88+
function getGqlOverloadChunk(
89+
sourcesWithOperations: Array<SourceWithOperations>,
90+
mode: Mode,
91+
emitLegacyCommonJSImports?: boolean
92+
) {
8893
const lines = new Set<string>();
8994

9095
// We intentionally don't use a <T extends keyof typeof documents> generic, because TS
@@ -94,7 +99,9 @@ function getGqlOverloadChunk(sourcesWithOperations: Array<SourceWithOperations>,
9499
const returnType =
95100
mode === 'lookup'
96101
? `(typeof documents)[${JSON.stringify(originalString)}]`
97-
: `typeof import('./graphql').${operations[0].initialName}`;
102+
: emitLegacyCommonJSImports
103+
? `typeof import('./graphql').${operations[0].initialName}`
104+
: `typeof import('./graphql.js').${operations[0].initialName}`;
98105
lines.add(`export function gql(source: ${JSON.stringify(originalString)}): ${returnType};\n`);
99106
}
100107

‎packages/presets/gql-tag-operations/tests/gql-tag-operations.spec.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ describe('gql-tag-operations-preset', () => {
3636
const gqlFile = result.find(file => file.filename === 'out1/gql.ts');
3737
expect(gqlFile.content).toMatchInlineSnapshot(`
3838
"/* eslint-disable */
39-
import * as graphql from './graphql.js';
39+
import * as graphql from './graphql';
4040
import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';
4141
4242
const documents = {
@@ -91,7 +91,7 @@ describe('gql-tag-operations-preset', () => {
9191
const gqlFile = result.find(file => file.filename === 'out1/gql.ts');
9292
expect(gqlFile.content).toMatchInlineSnapshot(`
9393
"/* eslint-disable */
94-
import * as graphql from './graphql.js';
94+
import * as graphql from './graphql';
9595
import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';
9696
9797
const documents = {
@@ -139,7 +139,7 @@ describe('gql-tag-operations-preset', () => {
139139
const gqlFile = result.find(file => file.filename === 'out1/gql.ts');
140140
expect(gqlFile.content).toMatchInlineSnapshot(`
141141
"/* eslint-disable */
142-
import * as graphql from './graphql.js';
142+
import * as graphql from './graphql';
143143
import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';
144144
145145
const documents = {
@@ -188,7 +188,7 @@ describe('gql-tag-operations-preset', () => {
188188
const gqlFile = result.find(file => file.filename === 'out1/gql.ts');
189189
expect(gqlFile.content).toMatchInlineSnapshot(`
190190
"/* eslint-disable */
191-
import * as graphql from './graphql.js';
191+
import * as graphql from './graphql';
192192
import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';
193193
194194
const documents = {
@@ -283,7 +283,7 @@ describe('gql-tag-operations-preset', () => {
283283
const gqlFile = result.find(file => file.filename === 'out1/gql.ts');
284284
expect(gqlFile.content).toMatchInlineSnapshot(`
285285
"/* eslint-disable */
286-
import * as graphql from './graphql.js';
286+
import * as graphql from './graphql';
287287
import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';
288288
289289
const documents = {

0 commit comments

Comments
 (0)