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)

Open
#1,584 0 comments 1 reaction 0 assignees View on GitHub
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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.