Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AOT Can't resolve all parameters for [...]

First of all, I must say that my app works fine when "using" JIT. I can even bundle in prod (no AOT, just JIT) and it works fine.

But when I try to compile it (AOT) using ngc I am getting an error, which says:

Can't resolve all parameters for MyComponentView in /path/my-component/my-component.view.ts:
([object Object], [object Object], [object Object], [object Object], ?)

This is the constructor of MyComponent:

constructor( headerService:HeaderService, sidebarService:SidebarService, @Inject( AuthService.Token ) authService:AuthService.Class, router:Router, carbon:Carbon ) {
    …
    this.carbon = carbon;
    …
}

The last dependency (Carbon) is being provided in AppModule like this:

@NgModule( {
    imports: [
        …
    ],
    declarations: [
        …
    ],
    providers: [
        …
        CARBON_PROVIDERS,   //<---- HERE IS BEING PROVIDED
        CARBON_SERVICES_PROVIDERS,
        …
    ],
    bootstrap: [ AppComponent ],
} )
export class AppModule { }

The CARBON_PROVIDERS are being imported using the angular2-carbonldp project which is exporting them like this:

export const CARBON_PROVIDERS:any[] = [
{
        provide: Carbon,
        useFactory(): Context {
            return carbon;
        },
    },
    {
        provide: ContextToken,
        useFactory(): Context {
            return activeContextFn();
        },
    },
    {
        provide: App.Context,
        useFactory(): App.Context {
            if( ! activeContextFn.isAppContext() ) throw new Errors.IllegalStateError( "The activeContext is not an App Context" );
            return <any>activeContextFn();
        },
    },
];

But I end up having the same error and I don't understand WHY! Do you guys happen to know why is it working like that?

like image 247
Alvaro Contreras Avatar asked Mar 07 '17 16:03

Alvaro Contreras


2 Answers

Because the AOT compiler supports only a small subset of JavaScript. This fact is poorly documented, where documented at all, and not widely publicized.

It is unable to parse many JavaScript expressions inside of Angular 2 framework decorators. This includes function calls they are not legal.

The following code causes failure

useFactory(): Context {
  return activeContextFn();
}

The reason for this is that angular2 decorators under AOT are not decorators at all.

The Angular 2 AOT compiler maintains a list of known decorators that it does not persist at runtime, instead treating them as nothing more than annotations*. This means they can only contain constant expressions, references to exported names, a few forms of array literal syntax and object literal syntax that are composed of constant expressions, and little else.

In case you're wondering, yes this means you are no longer writing TypeScript code and thusly are no longer writing JavaScript code. Incidentally it also means you can not trust most of your tools as they will give you a green light for invalid code because they are not aware of the language.

It is a different language with different semantics and not simply a subset because the decorator transform that it performs violates the specification for that feature in ECMAScript. Typescript does not add or modify any runtime behavior of ECMAScript.

*For reference, the term annotation is used here as it relates to the now dead at @Script language. This is the language the Angular team invented to write their framework in and started using heavily, via dedicated transpiler, before they moved to TypeScript.

In this specific case I think you need to rewrite your factory as follows:

useFactory: contextFactory

....

export function contextFactory() {
    return activeContextFn();
}

This may not be all that you need to do and the language will no doubt change over time. It is slated to have IDE support.

Here is a fairly useful "sandbox" https://github.com/rangle/angular-2-aot-sandbox

Be aware that the repository linked above is not an official source of documentation and that it defines its own subset based on its capabilities. Use with caution.

like image 133
Aluan Haddad Avatar answered Oct 04 '22 17:10

Aluan Haddad


For anyone else searching this specific error text:

I encountered this error when building a parent angular project with AOT enabled that had a child angular library project I had packaged with ng-packagr, which used barrels internally. I was able to solve the problem by changing all of the barrel references in the library project to explicit references.

Before

import { MyService } from './featureFolder';

After

import { MyService } from './featureFolder/my.service';

Issue Link The dev team claims this was fixed, but it seems to be back in some form in Angular 8. https://github.com/angular/angular/issues/23713

like image 40
DJKeeg Avatar answered Oct 04 '22 19:10

DJKeeg