JJJCoder
JJJCoder

Reputation: 16986

Angular upgrade - Error: inject() must be called from an injection context at injectInjectorOnly

I have an angular project structured like so:

Site1

Site2

I know this isn't ideal, but it's how it is.

The package.json files are exactly the same apart from the names of the application.

The project was started on Angular 8 and has always upgraded well, but going from 11 -> 12 I'm having issues:

Site1 builds fine and runs nicely. Site2 builds fine, but errors immediately on running with

Error: inject() must be called from an injection context at injectInjectorOnly (core:4745) at Module.ɵɵinject (core:4755) at Object.RouterModule_Factory [as factory] (router:5999) at R3Injector.hydrate (core.js:11438) at R3Injector.get (core.js:11257) at core.js:11295 at Set.forEach () at R3Injector._resolveInjectorDefTypes (core.js:11295) at new NgModuleRef$1 (core.js:25325) at NgModuleFactory$1.create (core.js:25379)

As Site1 works fine, I assume it must be something in calling that SharedModule?

I've tried adding "preserveSymlinks": true, to projects.$name.architect.build.options, but that doesn't work. I'm not using npm link as the other module isn't a library (I know it should have been set up that way, but it isn't).

I've spent at least 2 days trying to get this to work (obviously checking posts such as this and this, but the answers there dont seem to work.

Does anyone know how to fix this, or at least how to debug it please?

Upvotes: 6

Views: 12546

Answers (3)

Filip Trivan
Filip Trivan

Reputation: 21

The two most common tips for this problem are:

  1. Changing the paths array inside tsconfig.json and
  2. Setting "preserveSymlinks": true inside angular.json.

For me in Angular 17, I had to delete all paths from tsconfig.json but leave "preserveSymlinks": true

This led me to the solution: https://github.com/angular/angular/issues/35586#issuecomment-2137243609

Upvotes: 0

valepu
valepu

Reputation: 3315

I know this is a relatively old question but yesterday I had a similar issue and my workspace was already correctly configured as the example that was posted in the answer, on top of that it took a lot of googling to find another solution so I thought it would be best to share it somewhere with more visibility.

My issue was that if I injected a service from my local library without other dependencies it worked fine but if I injected a service that had to inject other dependencies into itself I had the same error showed in the question. The cause was exactly the same (2 different instances of angular) but what solved it for me was this

https://github.com/angular/angular/issues/25813#issuecomment-584866010

For me, "@angular/*": [ "./node_modules/@angular/*" ] (one dot, not two in the path) was what I needed, in addition to my own other mappings for my libraries. This only applies when using TypeScript path mapping instead of linking to the libraries, as documented here. Also, I put it in the tsconfig.json, not tsconfig.app.json. Either worked.

So the paths portion of my tsconfig.json file in my main Angular app is:

{   ...,   "compilerOptions": {
    ...,
    "paths": {
      "@angular/*": ["./node_modules/@angular/*"],
      "mylib/*": ["../../location/of/my/lib/src/*"]
    }   },   ... }

I added "@angular/*": [ "./node_modules/@angular/*" ] to my tsconfig.json and it worked.

Despite the fact the github issue was closed saying it was solved with the release of Ivy I had this issue with angular 12 while using ivy

Upvotes: 7

JJJCoder
JJJCoder

Reputation: 16986

For the benefit of searchers, following not getting a response here, I asked this to Angular themselves.

Here are the answers provided.

You have two distinct workspace trees that import from each other. That is bound to suffer from duplicate @angular/core versions which confuses the runtime, resulting in the rather obscure runtime error you're seeing. You can workaround this using paths mappings, as explained in the library guide here (which also applies to your situation without libs). Not sure why it worked in earlier versions, it has always been prone to these kinds of issues.

and

The cause is that the two separate workspaces both have their own @angular/core packages, and both end up in the bundled application. The Angular runtime keeps its state in top-level module variables that are private to that module, but having two occurrences of that module (from both instances of @angular/core) you run into situations where state is only initialized correctly in one instance, not the other. In this case the injection context is only available in the "primary" runtime, but the parts of the app that were bundled from the "secondary" library parts will depend on the "secondary" runtime state.

So basically, the structure is bad. It should have been done as a proper library project in the first place.

I've made a demo of how it should have been done here.

Upvotes: 7

Related Questions