Graphql-code-generator: Undefined Apollo service in Apollo Angular queries/mutations

Created on 31 Mar 2019  路  15Comments  路  Source: dotansimha/graphql-code-generator

Describe the bug

When using auto-generated queries or mutations, Mutation.apollo is undefined:

in fesm5 ng.apollo.js:

mutate(variables, options) {
    return this.apollo.use(this.client).mutate(Object.assign({}, options, { variables, mutation: this.document }));
}

```
ERROR TypeError: Cannot read property 'use' of undefined
at HomeKeepInTouchMutationGQL.mutate (ng.apollo.js:417)

It's a new project, I basically copied all the configuration from another project that has virtually the same bootstrap code, so I don't know what the difference could be, except that the old project uses v0.16.1 and the new one v1.0.6.

If I import `Apollo` myself in a component, I get an instance of it, and if I manually assign it to the mutation/query, it works fine, like that:

```ts
public constructor(
    apollo: Apollo,
    private readonly keepInTouchMutation: HomeKeepInTouchMutationGQL) {

    (keepInTouchMutation as any).apollo = apollo;
}

It looks like there is a problem with inheritance. If I edit the generated file by hand, to add an appropriate constructor in the mutations, it works too:

@Injectable({
    providedIn: "root"
})
export class HomeKeepInTouchMutationGQL extends Apollo.Mutation<
    HomeKeepInTouchMutationMutation,
    HomeKeepInTouchMutationMutationVariables
> {
    document = HomeKeepInTouchMutationDocument;

    public constructor(apollo: Apollo.Apollo) { // this!
        super(apollo);
    }
}

My knowledge of Angular internals stops there, but I've already stumbled upon this problem where DI doesn't works when classes are inherited. Since you rely on this, I thought that this may interest you.

Environment:

All latest versions of codegen libraries, Apollo and Angular.

Most helpful comment

Happened to me today using Angular 8 and TS 3.4, in tests only.
Setting "target": "es5" in tsconfig.spec.json fixes the issue.

All 15 comments

@kamilkisiela any idea?

@toverux could create a small reproduction?

I've just had the intuition that this could be related to my tsconfig language level target (es5, es2015, etc).
That's not pure Angular CLI, I use things like @angular-builders/custom-webpack to add my own webpack or TypeScript config on top of what Angular CLI does.

I tested that hypothesis and I was right, changing my target to es5 (instead of es2015) made it work. The other project had es5 target too, that explained why it worked here too.

Interestingly, es2015 works when using ng build --prod, but not with serve.

I compared the output of the Mutation class in both ES5 and ES2015, and except for the syntactic sugar they're virtually the same, especially that part that Angular creates to know what types are needed for runtime injection:

Mutation.ctorParameters = () => [
    { type: Apollo }
];

So, well, I don't know where exaclty the problem is with es2015 in serve mode.

So you're saying that ng serve doesn't work when target equals es2015? Maybe it's the AOT compiler that makes the magic in prod and not es5 as a target.

Could you try ng server --prod and see what happens?

@dotansimha I'm closing this on since we didn't get any response

I came back to ES5 builds (with some regrets), the default/normal target of Angular CLI. Surely this is a problem with Angular. Although this library could emit explicit constructor on child classes of Mutation or Query to workaround the problem, that would produce heavier files, and I don't think you want that.

Angular 8 will produce both ES 2015 and ES 5 builds (loaded selectively at runtime for best browser support). If the problem comes back at that point, I'll be glad to help more!

Thanks for your help.

@toverux Stumbled with this problem too. Spent a lot of time trying to get the reason. I can't understand why es2015+ build target doesn't work. One more weird bug and caveat that I need to note somewhere ;((

So you're saying that ng serve doesn't work when target equals es2015? Maybe it's the AOT compiler that makes the magic in prod and not es5 as a target.

Could you try ng server --prod and see what happens?

I got same issue for query.

during using watch as following line, encountered same problem.
this.meWatch = this.me.watch();

And, it was gone with use of '--prod' running option

Angular 8 will produce both ES 2015 and ES 5 builds (loaded selectively at runtime for best browser support). If the problem comes back at that point, I'll be glad to help more!

And indeed, the problem seems to have been fixed, wether it comes from Angular or TypeScript (or both ?).
With Angular 8 and TS 3.4, ES 2015 bundles do not encounter this problem anymore :tada:

Happened to me today using Angular 8 and TS 3.4, in tests only.
Setting "target": "es5" in tsconfig.spec.json fixes the issue.

@tgambet Your answer helped me out!

I think this should be reopened, just stumbled upon the same issue with "target": "es2015".

However, I cannot change my target without breaking other things in the project, as it is a fairly big one.

This issue should be more visible.

Ok, upgrading to Angular 8 actually did fix this. I was on Angular 7 before.

Happened to me today using Angular 8 and TS 3.4, in tests only.
Setting "target": "es5" in tsconfig.spec.json fixes the issue.

I just stumbled upon this issue in writing my angular tests with apollo-graphql. This solution worked for me. Thanks!

Using:
"apollo-angular": "^1.9.1",
"@angular/core": "~9.1.6",

Was this page helpful?
0 / 5 - 0 ratings