dotansimha / dotansimha/graphql-code-generator-community
`near-operation-file-preset` 5.2.2 emits invalid `import * from '...'` when combined with `typescript-vue-apollo` (which pins `visitor-plugin-common` v6)
- Dominant language
- TypeScript
- Stars
- 137
- Forks
- 195
- Avg merge
- 6h 20m
- Merged PRs (30d)
- 16
Description
### Which packages are impacted by your issue?
- `@graphql-codegen/near-operation-file-preset`
- `@graphql-codegen/typescript-vue-apollo`
### Describe the bug
Since `@graphql-codegen/near-operation-file-preset@5.2.2` (#1530), fragment files no longer emit fragment `*Doc` imports they don't use. When *all* of a fragment file's imports are elided this way, the generated file gets a syntactically invalid statement instead of no statement at all:
```ts
import * from './objectAttributeValues.api';
```
This is not valid TypeScript — `import *` requires an `as ` binding. The generated file fails to parse.
The 5.2.2 release notes anticipate this and state:
> Requires `@graphql-codegen/visitor-plugin-common` `^7.2.2` — earlier v7 releases emit an invalid `import * from '...'` statement for fragment files whose imports are all elided.
The problem is that **this requirement cannot be satisfied when using `typescript-vue-apollo`.** `@graphql-codegen/typescript-vue-apollo@5.0.1` (current latest) depends on `@graphql-codegen/visitor-plugin-common@6.3.0`, so the plugin that actually emits these files resolves its own v6 copy regardless of what the consuming project hoists. Our project declares `"@graphql-codegen/visitor-plugin-common": "^7.2.5"` as a direct dependency and it makes no difference.
#### Root cause
`generateImportStatement` in `visitor-plugin-common@7.2.5` (`cjs/imports.js`) guards the empty-identifier case:
```js
function generateImportStatement(statement) {
const { baseDir, importSource, outputPath, typesImport } = statement;
if (!importSource.identifiers?.length && !importSource.namespace) {
return ''; // <-- guard added in 7.2.2
}
const importPath = resolveImportPath(baseDir, outputPath, importSource.path);
const importNames = importSource.identifiers?.length
? `{ ${Array.from(new Set(importSource.identifiers)).join(', ')} }`
: '*';
...
```
`visitor-plugin-common@6.3.0` has the identical function **without** the guard, so it falls through to `importNames = '*'`. With no `importSource.namespace`, `importAlias` is `''`, and the emitted statement is a bare `import * from '...'`.
So the fix in 7.2.2 is real, but unreachable for `typescript-vue-apollo` users.
### Your Example Website or App
https://github.com/zammad/zammad
### Steps to Reproduce the Bug or Issue
The repository above reproduces this directly. No Rails, database or other backend service is needed — the GraphQL introspection dump (`app/graphql/graphql_introspection.json`) and the document transform are both committed, so codegen runs standalone:
```bash
git clone https://github.com/zammad/zammad.git
cd zammad
pnpm install
# 1. Baseline on near-operation-file-preset@5.2.1 — generated output matches the
# committed files exactly, so `git status` stays clean.
pnpm exec graphql-codegen -c .graphql_code_generator.js
git status --porcelain # -> empty
# 2. Upgrade only the preset.
pnpm add -D @graphql-codegen/near-operation-file-preset@5.2.2
pnpm exec graphql-codegen -c .graphql_code_generator.js
git diff # -> 11 invalid `import * from '...';` statements
```
Step 1 is worth running first: it establishes that the committed generated files are exactly what 5.2.1 produces, so everything step 2 changes is attributable to the preset upgrade alone.
Note that `pnpm install` pulls a full application frontend, so this is a real reproduction rather than a minimal one. If you'd rather not clone it, the root cause section above is self-contained — the missing guard in `visitor-plugin-common@6.3.0` and `typescript-vue-apollo@5.0.1`'s dependency on that version are both verifiable from the published packages alone.
### Expected behavior
I expected fragment files whose imports are all elided to emit **no import statement**, as `visitor-plugin-common@7.2.2+` does. Instead they emit `import * from '...'`, which is invalid TypeScript and breaks compilation.
### Platform
- OS: Linux (CI, Debian) and macOS
- NodeJS: 24.19.0
- `graphql` version: 16.14.2
- `@graphql-codegen/*` version(s):
- `@graphql-codegen/cli` 7.4.0
- `@graphql-codegen/near-operation-file-preset` 5.2.2
- `@graphql-codegen/typescript-vue-apollo` 5.0.1
- `@graphql-codegen/visitor-plugin-common` 7.2.5 hoisted, **6.3.0** resolved for `typescript-vue-apollo`
### Codegen Config File
```js
{
overwrite: true,
schema: 'app/graphql/graphql_introspection.json',
config: {
vueCompositionApiImportFrom: 'vue',
addDocBlocks: false,
},
generates: {
'./app/frontend/': {
documents: ['app/frontend/shared/**/*.graphql', 'app/frontend/apps/**/*.graphql'],
preset: 'near-operation-file',
presetConfig: {
baseTypesPath: '~#shared/graphql/types.ts',
importTypesNamespace: '',
extension: '.api.ts',
},
plugins: ['typescript-vue-apollo'],
config: {
importOperationTypesFrom: 'Types',
},
},
},
}
```
### Additional context
Upgrading `near-operation-file-preset` from 5.2.1 to 5.2.2 in our repository produces 11 of these invalid statements. The import specifiers involved:
```
2x './objectAttributeValues.api'
2x '../../../../graphql/fragments/objectAttributeValues.api'
1x './userPersonalSettings.api'
1x './userAttributes.api'
1x './knowledgeBaseCategoryPreInfo.api'
1x './knowledgeBaseCategoryPolicy.api'
1x './knowledgeBaseAnswerPolicy.api'
1x '../../../../knowledge-base/graphql/fragments/knowledgeBaseAnswerTaskbarTabAttributes.api'
1x '../../../../../../../shared/entities/ticket/graphql/fragments/ticketTaskbarTabAttributes.api'
```
The count grows as more fragments are added, so this scales with codebase size rather than being an isolated edge case.
#### Suggested fix
Either would resolve it, the first being the smaller change:
1. Bump `typescript-vue-apollo`'s `@graphql-codegen/visitor-plugin-common` dependency to `^7.2.2`, so the existing guard applies. Other community plugins that still pin v6 would need the same treatment.
2. Backport the empty-identifier guard to the v6 line of `visitor-plugin-common`.
A defensive check in `near-operation-file-preset` — dropping import sources with no identifiers before handing them to the visitor — would also make the preset robust regardless of which `visitor-plugin-common` a plugin resolves.
Contributor guide
No contributing guide indexed for this repository
Research direction
Reproduce the issue in the zammad repository with the documented pnpm and graphql-codegen commands, comparing 5.2.1 with 5.2.2. Then inspect near-operation-file-preset and the resolved visitor-plugin-common cjs/imports.js, especially generateImportStatement. Done means generated fragment files contain no bare `import * from` statements and the compatibility path for typescript-vue-apollo is covered.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- node.js, typescript
- Domain
- tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100