Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] Getting “inject() must be called from an injection context” after upgrading to Angular 11 #8447

Closed
falk-stefan opened this issue Jan 14, 2021 · 26 comments

Comments

@falk-stefan
Copy link

falk-stefan commented Jan 14, 2021

Description

After having generated an API-client under the org.openapi.generator:5.0.0 using the org.springdoc.openapi-gradle-plugin:1.3.0, my web application crashes, giving me the following error:

main.ts:12 Error: inject() must be called from an injection context
    at injectInjectorOnly (core.js:4901)
    at Module.ɵɵinject (core.js:4911)
    at Object.ApiModule_Factory [as factory] (meditation-rest-client.js:2885)
    at R3Injector.hydrate (core.js:11158)
    at R3Injector.get (core.js:10979)
    at core.js:11016
    at Set.forEach (<anonymous>)
    at R3Injector._resolveInjectorDefTypes (core.js:11016)
    at new NgModuleRef$1 (core.js:25046)
    at NgModuleFactory$1.create (core.js:25100)
openapi-generator version

5.0.0

OpenAPI declaration file content or url
openapi: 3.0.1
info:
  title: OpenAPI definition
  version: v0
servers:
- url: http://127.0.0.1:8080
  description: Generated server url
paths:
  // ...
Generation Details

I am using the openapi-generator-gradle-plugin:

openApiGenerate {
    generatorName = 'typescript-angular'
    inputSpec = swaggerFilePath
    outputDir = apiClientOutputDir
    configOptions = [
            npmName   : 'meditation-rest-client',  // Api-client name
            npmVersion: '0.0.1',                   // Api-client version
            ngVersion : '11.0.6'
    ]
}
Steps to reproduce
  1. Build an API-Client from a Spring Boot Application
  2. Reference the API-Client in your Angular 11 Web-Application
  3. ng serve
  4. Find the error in your console
Related issues/PRs

I have tried to apply suggestions from

without success.

@macjohnny
Copy link
Member

can you elaborate in more detail what the step "2. Reference the API-Client in your Angular 11 Web-Application" means technically? maybe you can upload a demo repo on github.

@falk-stefan
Copy link
Author

falk-stefan commented Jan 15, 2021

@macjohnny Hi! Of course.. well..

The API-Client is a compiled package which is located at <project-root>/generated/meditation-rest-client". So, in my package.json I have this as a dependency set as follows:

"meditation-rest-client": "./generated/meditation-rest-client"

This setup worked in Angular 9 and I am not sure what exactly change with Angular 11 here. On one side, I upgraded the OpenAPI tool-chain as stated, on the other side I upgraded my web-application to Angular 11.

@macjohnny
Copy link
Member

in the <project-root>/generated/meditation-rest-client, is there a node_modules folder? if so, it should be deleted, because you should use the angular code in <project-root>/node_modules

@falk-stefan
Copy link
Author

@macjohnny Interesting.. you are right. Indeed, there is one.. how did that get there? O_o

This client gets generated at build-time. So.. in my server/ project, there is a build/generated/sources/meditation-rest-client/dist and inside that dist/ folder is no node_modules/..

Any idea how it got there? Maybe from a npm install run?

@macjohnny
Copy link
Member

macjohnny commented Jan 15, 2021

if you want to run the code of the compiled npm package, you would need to reference it in your package.json as follows

"meditation-rest-client": "./generated/meditation-rest-client/dist"

if you want to compile the generated code as part of your frontend-build, you can reference

"meditation-rest-client": "./generated/meditation-rest-client"

but then you need to make sure the <project-root>/generated/meditation-rest-client/node_modules is deleted or simply not creating during the code-generation (as part of the build step), e.g. by not using the npmPackage option.

@falk-stefan
Copy link
Author

Just to clarify:

This here is already the dist/

"meditation-rest-client": "./generated/meditation-rest-client" 

Basically:

./generated/meditation-rest-client -> build/generated/sources/meditation-rest-client/dist

That's how I always did it (Angular 9).

@falk-stefan
Copy link
Author

falk-stefan commented Jan 15, 2021

And I already tried to use build/generated/sources/meditation-rest-client and compile it (by my web-applicat) but that didn't work. I can't remember what the problem was though..

@macjohnny
Copy link
Member

yes, but my guess would be that build/generated/sources/meditation-rest-client/dist/.../myapi.js will still pick the build/generated/sources/meditation-rest-client/node_modules/@angular/core instead of the <project-root>/node_modules/@angular/core.

Please try deleting build/generated/sources/meditation-rest-client/node_modules

@macjohnny
Copy link
Member

another source of issues could be symlinks

@falk-stefan
Copy link
Author

@macjohnny I'll have to make a few changes to make sure this works but from the first look.. it seems the node_modules/ directory in the API-client was indeed the issue. I'll need some time to check a few things and keep you up to date!

Thank you so far. Thanks a lot! :)

@falk-stefan
Copy link
Author

@macjohnny Just a quick question.. The problem with copying server/build/generated/sources/meditation-rest-client was that in that case I wasn't able to build the App.

The error was

node_modules/meditation-rest-client/api.module.ts 

This was why I compiled the API-Client beforehand and then copied the dist/ folder. So.. how can I make sure that this gets compiled along with my web-application?

@macjohnny
Copy link
Member

you should not place the meditation-rest-client inside the <project-root>/node_modules folder, but rather somewhere like

<project-root>/src/core/api/meditation-rest-client

this way, you can compile the generated code along with your frontend code, without the need to compile the npm package separately.

@macjohnny
Copy link
Member

I also added an answer to https://stackoverflow.com/questions/65709951/getting-inject-must-be-called-from-an-injection-context-after-upgrading-to-a/65738925

if this resolves your issue, please close the issue and if you like it, mark the answer as accepted.

@falk-stefan
Copy link
Author

falk-stefan commented Jan 15, 2021

No, no. I never put it there. It's always in <project-root>/generated/meditation-rest-client. This error:

Error: <project-root>/node_modules/meditation-rest-client/index.ts is missing from the TypeScript compilation.

comes if I put the non-compiled version of meditation-rest-client there.

@macjohnny
Copy link
Member

Could you please post more details about the error that occurs, and more details about which code is placed where?

@falk-stefan
Copy link
Author

falk-stefan commented Jan 15, 2021

So, this here is the generated (non-compiled) version of meditation-rest-client

image

What I used to do is compile this beforehand and copy the content of dist/ to <web-client>/generated/meditation-rest-client == (dist/) which I then referenced in package.json like this:

"meditation-rest-client": "./generated/meditation-rest-client" 

This meant, that I was able to import things from there like this:

import {Track} from 'meditation-rest-client';

And this seems to work but (for some reason) I have to remove this rouge node_modules/ directory first.


You suggested, however, do reference the non-compiled version. That would be (something like) this:

"meditation-rest-client": "../server/build/generated/sources/meditation-rest-client" 

But, if I reference the non-compiled version, I will get

Error: <project-root>/node_modules/meditation-rest-client/index.ts is missing from the TypeScript compilation.

when running ng serve.

Note: In my previous message I posted the wrong error message (copy&paste error)

@falk-stefan
Copy link
Author

falk-stefan commented Jan 15, 2021

This here is the dist/ after compilation. As you can see, there is no node_modules/ directory inside:

image

I am sure this didn't happen previously but as you can see, there is now a node_modules/ directory where it shouldn't be:

image

This rouge node_modules/ directory gets there after I run

<project-root>$ npm i

having reference (in package.json)

    "meditation-rest-client": "./generated/meditation-rest-client",

And I am 90% sure this was not an issue in Angular 9 (?)

@macjohnny
Copy link
Member

to avoid the

Error: <project-root>/node_modules/meditation-rest-client/index.ts is missing from the TypeScript compilation.

the simplest way would be to copy the entire content of /server/build/generated/sources/meditation-rest-client to your frontend app, e.g. <frontend-project-root>/src/core/api/meditation-rest-client.

otherwise you would need to add /server/build/generated/sources/meditation-rest-client to the includes array of <frontend-project-root>/tsconfig.json

@falk-stefan
Copy link
Author

falk-stefan commented Jan 15, 2021

Okay. So, with ./generated/meditation-rest-client being the non-compiled code of the API-Client and having

tsconfig.json

  "include": ["./generated/meditation-rest-client"]

Does not work with imports like import {Track} from 'meditation-rest-client'; instead it seems to require relative paths import {Track} from '../../../meditation-rest-client';.

This is the same for copying the code directly into <project-root>/src/core/api/meditaiton-rest-client. I'd like to avoid that because in that case I'd have to go through quite some amount of files and change these imports..

So far the only way that "works" is to link the compiled version of the code but then the question would be: "Where is the rouge node_modules/ directory coming from?" or "Why does npm i install two node_modules/ directories?"

@macjohnny
Copy link
Member

Here is what I tried to reproduce your situation:

  • In Downloads, create a new angular 11 app with
    ng new bla-mega
    
  • Clone https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/typescript-angular-v11-provided-in-root/builds/with-npm to Downloads/petstore-api/src and in that folder run
    npm install
    npm run build
    
  • Copy Downloads/petstore-api/src/dist to Downloads/bla-mega/generated/api-client-dist
  • in Downloads/bla-mega/package.json, reference it as a dependency
    "@openapitools/typescript-angular-petstore": "./generated/api-client-dist"
    
  • In Downloads/bla-mega/src/app.module.ts, import the module
    import { ApiModule } from '@openapitools/typescript-angular-petstore';
    @NgModule({
       ...
      imports: [
        ...
        ApiModule
      ],
    })
    export class AppModule { }
    
  • In Downloads/bla-mega, run
    npm install
    ng build
    

This results in
image

This compiles successfully.

@falk-stefan
Copy link
Author

falk-stefan commented Jan 15, 2021

I think I've got it. Instead of "include" I have to set compilerOptions.paths (see) like so:

/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
  "compileOnSave": false,
  "compilerOptions": {
    ..
    "paths": {
      "meditation-rest-client": ["./generated/meditation-rest-client"]
    }
  }
}

This seems to work now! :)

@macjohnny
Copy link
Member

macjohnny commented Jan 15, 2021

Okay. So, with ./generated/meditation-rest-client being the non-compiled code of the API-Client and having

tsconfig.json

  "include": ["./generated/meditation-rest-client"]

Does not work with imports like import {Track} from 'meditation-rest-client'; instead it seems to require relative paths import {Track} from '../../../meditation-rest-client';.

This is the same for copying the code directly into <project-root>/src/core/api/meditaiton-rest-client. I'd like to avoid that because in that case I'd have to go through quite some amount of files and change these imports..

To avoid having to use relative paths, you can add a path mapping to your tsconfig.json:
https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping
i.e.

{
  "compilerOptions": {
    ...
    "paths": {
      "meditation-rest-client": ["generated/meditation-rest-client"]
    }
  }
}

So far the only way that "works" is to link the compiled version of the code but then the question would be: "Where is the rouge node_modules/ directory coming from?" or "Why does npm i install two node_modules/ directories?"

I dont know why this happens, maybe some npm install is accidentally run inside the api-client/dist folder for some reason.

@macjohnny
Copy link
Member

so can you close this issue as it is resolved?

@falk-stefan
Copy link
Author

Yeah, thanks a lot man! Do you have a "buy me a coffee"-button somewhere? :D

Yeah, this issue is resolved! Thanks a hundred times!

@macjohnny
Copy link
Member

glad it works.

@falk-stefan
Copy link
Author

Falls ich mal in der Schweiz bin ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants