Skip to content

Commit acb647e

Browse files
dstaleyadrienharnaybeerose
authored
Stop importing fragments that are now unused (#9194)
* Stop importing fragments that are now unused * fix: remove unused argument and import * chore: add changeset * feat: add tests for inlined fragments --------- Co-authored-by: Adrien HARNAY <[email protected]> Co-authored-by: Aleksandra <[email protected]>
1 parent e347e36 commit acb647e

File tree

3 files changed

+80
-47
lines changed

3 files changed

+80
-47
lines changed

.changeset/sharp-clouds-peel.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@graphql-codegen/visitor-plugin-common': patch
3+
---
4+
5+
Don't emit import statements for unused fragments

packages/plugins/other/visitor-plugin-common/src/client-side-base-visitor.ts

+1-46
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import {
1515
} from 'graphql';
1616
import gqlTag from 'graphql-tag';
1717
import { BaseVisitor, ParsedConfig, RawConfig } from './base-visitor.js';
18-
import { generateFragmentImportStatement } from './imports.js';
1918
import { LoadedFragment, ParsedImport } from './types.js';
2019
import { buildScalarsFromConfig, getConfigValue } from './utils.js';
2120

@@ -569,7 +568,7 @@ export class ClientSideBaseVisitor<
569568
return path;
570569
}
571570

572-
public getImports(options: { excludeFragments?: boolean } = {}): string[] {
571+
public getImports(): string[] {
573572
(this._additionalImports || []).forEach(i => this._imports.add(i));
574573

575574
switch (this.config.documentMode) {
@@ -620,50 +619,6 @@ export class ClientSideBaseVisitor<
620619
break;
621620
}
622621

623-
if (!options.excludeFragments && !this.config.globalNamespace) {
624-
const { documentMode, fragmentImports } = this.config;
625-
if (
626-
documentMode === DocumentMode.graphQLTag ||
627-
documentMode === DocumentMode.string ||
628-
documentMode === DocumentMode.documentNodeImportFragments
629-
) {
630-
// keep track of what imports we've already generated so we don't try
631-
// to import the same identifier twice
632-
const alreadyImported = new Map<string, Set<string>>();
633-
634-
const deduplicatedImports = fragmentImports
635-
.map(fragmentImport => {
636-
const { path, identifiers } = fragmentImport.importSource;
637-
if (!alreadyImported.has(path)) {
638-
alreadyImported.set(path, new Set<string>());
639-
}
640-
641-
const alreadyImportedForPath = alreadyImported.get(path);
642-
const newIdentifiers = identifiers.filter(identifier => !alreadyImportedForPath.has(identifier.name));
643-
newIdentifiers.forEach(newIdentifier => alreadyImportedForPath.add(newIdentifier.name));
644-
645-
// filter the set of identifiers in this fragment import to only
646-
// the ones we haven't already imported from this path
647-
return {
648-
...fragmentImport,
649-
importSource: {
650-
...fragmentImport.importSource,
651-
identifiers: newIdentifiers,
652-
},
653-
emitLegacyCommonJSImports: this.config.emitLegacyCommonJSImports,
654-
};
655-
})
656-
// remove any imports that now have no identifiers in them
657-
.filter(fragmentImport => fragmentImport.importSource.identifiers.length > 0);
658-
659-
deduplicatedImports.forEach(fragmentImport => {
660-
if (fragmentImport.outputPath !== fragmentImport.importSource.path) {
661-
this._imports.add(generateFragmentImportStatement(fragmentImport, 'document'));
662-
}
663-
});
664-
}
665-
}
666-
667622
return Array.from(this._imports);
668623
}
669624

packages/plugins/other/visitor-plugin-common/tests/client-side-base-visitor.spec.ts

+74-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { buildSchema, OperationDefinitionNode, parse } from 'graphql';
1+
import { buildSchema, FragmentDefinitionNode, OperationDefinitionNode, parse, Kind } from 'graphql';
22
import { ClientSideBaseVisitor, DocumentMode } from '../src/client-side-base-visitor.js';
33

44
describe('getImports', () => {
@@ -129,4 +129,77 @@ describe('getImports', () => {
129129
});
130130
});
131131
});
132+
133+
describe('when documentMode "documentNodeImportFragments"', () => {
134+
const schema = buildSchema(/* GraphQL */ `
135+
type Query {
136+
a: A
137+
}
138+
139+
type A {
140+
foo: String
141+
bar: String
142+
}
143+
`);
144+
145+
it('does not import FragmentDocs', () => {
146+
const fileName = 'fooBarQuery';
147+
const importPath = `src/queries/${fileName}`;
148+
149+
const document = parse(
150+
`query fooBarQuery {
151+
a {
152+
...fields
153+
}
154+
}
155+
fragment fields on A {
156+
foo
157+
bar
158+
}
159+
`
160+
);
161+
162+
const visitor = new ClientSideBaseVisitor(
163+
schema,
164+
(document.definitions.filter(d => d.kind === Kind.FRAGMENT_DEFINITION) as FragmentDefinitionNode[]).map(
165+
fragmentDef => ({
166+
node: fragmentDef,
167+
name: fragmentDef.name.value,
168+
onType: fragmentDef.typeCondition.name.value,
169+
isExternal: false,
170+
})
171+
),
172+
{
173+
emitLegacyCommonJSImports: true,
174+
importDocumentNodeExternallyFrom: 'near-operation-file',
175+
documentMode: DocumentMode.documentNodeImportFragments,
176+
fragmentImports: [
177+
{
178+
baseDir: '/',
179+
baseOutputDir: '',
180+
outputPath: '',
181+
importSource: {
182+
path: '~types',
183+
identifiers: [
184+
{ name: 'FieldsFragmentDoc', kind: 'document' },
185+
{ name: 'FieldsFragment', kind: 'type' },
186+
],
187+
},
188+
emitLegacyCommonJSImports: true,
189+
typesImport: false,
190+
},
191+
],
192+
},
193+
{},
194+
[{ document, location: importPath }]
195+
);
196+
197+
visitor.OperationDefinition(document.definitions[0] as OperationDefinitionNode);
198+
199+
const imports = visitor.getImports();
200+
imports.forEach(i => {
201+
expect(i).not.toContain('FragmentDoc');
202+
});
203+
});
204+
});
132205
});

0 commit comments

Comments
 (0)