Skip to content

Inputs are not inherited when Ivy is enabled #30080

Closed

Description

@kemsky

🐞 bug report

Is this a regression?

No

Description

We build our app with ngc and closure compiler. After enabling Ivy ngc fails almost immediately. Could not find any instructions for this case.

🔬 Minimal Reproduction

        import {platformBrowser} from '@angular/platform-browser';
        import {AppModuleNgFactory} from './application.module.ngfactory';

        platformBrowser()
            .bootstrapModuleFactory(AppModuleNgFactory)
            .catch(e => console.error('Application bootstrap failed', e));

🔥 Exception or Error


[11:51:23] Spa_Source/main.aot.ts:7:34 - error TS2307: Cannot find module './application.module.ngfactory'.

7 import {AppModuleNgFactory} from './application.module.ngfactory';

🌍 Your Environment

Angular Version:


8.0.0-beta.14

Activity

  1. alan-agius4 commented on Apr 24, 2019

    @alan-agius4
    Contributor

    Hi, ngfactory are only created when using NGC, Ivy uses a different compiler (NGTSC) which doesn't generate factories.

    Which means you need to remove the factory references.
    Ie from

    import {platformBrowser} from '@angular/platform-browser';
    import {AppModuleNgFactory} from './application.module.ngfactory';
    
    platformBrowser()
        .bootstrapModuleFactory(AppModuleNgFactory)
        .catch(e => console.error('Application bootstrap failed', e));

    to

    import {platformBrowser} from '@angular/platform-browser';
    import {AppModule} from './application.module';
    
    platformBrowser()
        .bootstrapModule(AppModule)
        .catch(e => console.error('Application bootstrap failed', e));

    Alternatively you can enable factory shims by adding "allowEmptyCodegenFiles": true under angularCompilerOptions in your tsconfig.json. However it's worth mentioning that the later is not recommended.

  2. kemsky commented on Apr 24, 2019

    @kemsky
    Author

    @alan-agius4, thanks for information. I've tried recommended approach, but still no success:

    node_modules/@angular/platform-browser/platform-browser.d.ts:42:22 - error NG6002: Appears in the NgModule.imports of AppModule, but could not be resolved to an NgModule class
    
    42 export declare class BrowserModule {
                            ~~~~~~~~~~~~~
    node_modules/@angular/forms/forms.d.ts:2667:22 - error NG6002: Appears in the NgModule.imports of AppModule, but could not be resolved to an NgModule class
    
    2667 export declare class FormsModule {
                              ~~~~~~~~~~~
    node_modules/@angular/router/router.d.ts:2403:22 - error NG6002: Appears in the NgModule.imports of AppModule, but could not be resolved to an NgModule class
    
    2403 export declare class RouterModule {
                              ~~~~~~~~~~~~
    node_modules/@angular/router/router.d.ts:2403:22 - error NG6002: Appears in the NgModule.imports of AppModule, but could not be resolved to an NgModule class
    
    2403 export declare class RouterModule {
                              ~~~~~~~~~~~~
    
  3. JoostK commented on Apr 24, 2019

    @JoostK
    Member

    @kemsky From that error I can tell that ngcc has not processed those libraries. Are you using latest Angular CLI to build your application?

  4. added this to the needsTriage milestone on Apr 25, 2019
  5. P3tronius commented on Apr 26, 2019

    @P3tronius

    @kemsky did you added ivy-ngcc in postinstall steps of package.json?

    "scripts": {
        "postinstall": "ivy-ngcc",
        ...
    
  6. kemsky commented on Apr 26, 2019

    @kemsky
    Author

    @Petronious, Yep, it was my fault, I did not invoke ivy-ngcc. There are a couple of problems with Ivy though.

    • If you disable Ivy and try to build as usual with regular ngc - it fails and you have to remove node_modules and install again.

    • I received a lot of strange compiler errors:

    __ng_typecheck__.ts:13549:11 - error TS2339: Property 'caption' does not exist on type 'HTMLDivElement'.
    
    13549     _t132.caption = "Defendant 4 Is Covered: ";
    

    Corresponding template:

    <div class="input" [caption]="'Defendant 4 Is Covered: '" name="defendant4IsCovered" type="checkbox" [(ngModel)]="item.defendant4IsCovered"></div>

    Code:

    export abstract class AbstractFormComponent<T extends HTMLElement> extends AbstractComponent implements ControlValueAccessor, IFocusContainer {
       ...
        @Input('caption')
        public label:string;
    ...
    }

    Looks like alias is ignored...

    Also I'd like to know is ivy-ngcc documented anywhere? I need to skip processing of certain modules.

  7. P3tronius commented on Apr 26, 2019

    @P3tronius

    Strange, Ivy is supposed to support extends on @Component : https://is-angular-ivy-ready.firebaseapp.com/#/status

    Guess you'll have to add @Input('caption') in the concrete classes meanwhile...

  8. kemsky commented on Apr 26, 2019

    @kemsky
    Author

    @JoostK @alan-agius4 what do you think?

  9. alan-agius4 commented on Apr 26, 2019

    @alan-agius4
    Contributor

    NGCC is integrated as part of @ngtools/webpack which is used in the Angular CLI.

    Unless you have a custom build system and not using any of the above, you need to run NGCC as a post install hook.

    If opting out of ivy is not working, ie a build which used to work is no longer working, we’d need to take a look at it.

    Which version of the framework are you using?

  10. JoostK commented on Apr 26, 2019

    @JoostK
    Member

    @kemsky

    • If you disable Ivy and try to build as usual with regular ngc - it fails and you have to remove node_modules and install again.

    As part of running ngcc, existing code in node_modules is AOT compiled into Ivy instructions. If you run ngcc using its executable ivy-ngcc then this step overwrites library files in-place, with a backup file suffixed with .bak being produced as well. Besides the generation of Ivy code, the original Angular decorators such as @Component and @Input etc. are removed from the code, as Ivy conveys such metadata in a different, tree-shakeable way. Therefore, the node_modules directory has then been modified in a way that it can no longer be used when disabling Ivy, as vital information is no longer present in the library files.

    The same is not true when using the Angular CLI, as its execution of ngcc under the covers will use a different approach that does not suffer from the same problem: instead of overwriting files in-place, a dedicated __ivy_ngcc__ subdirectory is created in each library that gets compiled for Ivy. The CLI will then redirect Webpack to use the sources from the subdirectory, instead of the non-Ivy code originally shipped to NPM. Hence, this way disabling Ivy should not see the need to reinstall node_modules.

    • I received a lot of strange compiler errors:
    __ng_typecheck__.ts:13549:11 - error TS2339: Property 'caption' does not exist on type 'HTMLDivElement'.
    
    13549     _t132.caption = "Defendant 4 Is Covered: ";
    

    Corresponding template:

    <div class="input" [caption]="'Defendant 4 Is Covered: '" name="defendant4IsCovered" type="checkbox" [(ngModel)]="item.defendant4IsCovered"></div>
    

    Code:

    export abstract class AbstractFormComponent<T extends HTMLElement> extends AbstractComponent implements ControlValueAccessor, IFocusContainer {
       ...
        @Input('caption')
        public label:string;
    ...
    }

    Looks like alias is ignored...

    Thanks for sharing this! The type checking of Angular template code has been completely redesigned to be far more extensive than the type checking that was done previously. It should be able to catch many more bugs that were previously not discovered. In this case however, I don't have enough insight to see if this is a false-positive in the new type-checker, of if there's legitimately reason to believe there's a type error somewhere.

    By the looks of it, a concrete directive/component of AbstractFormComponent could not be matched (leaving the property left-over for the div element) or it could not be statically determined that the parent class of the matched directive/component is AbstractFormComponent, which also currently results in applying the property to the div element.

    If you think neither of the above is the case, there may indeed be buggy behavior with either class hierarchies (which should be supported iff the class hierarchy can be statically determined) or with the aliased input (which should also be taken into account already).

    Would you be able to provide a minimal reproduction of this issue, so that we can look into what is causing it?

    Also I'd like to know is ivy-ngcc documented anywhere? I need to skip processing of certain modules.

    It doesn't currently have a lot of documentation. May I ask, why do you need to skip processing of certain libraries? Are they Angular libraries that are processed but you think they shouldn't?

  11. kemsky commented on Apr 29, 2019

    @kemsky
    Author

    @JoostK , I've tried removing input aliases and it did not help, then I tried copy-paste inputs to the inherited classes - it worked, so I'm 100% sure that inputs are not properly inherited (there are no typescript errors, tsconfig is pretty strict). Without it I can not continue testing, because inheritance is used heavily in our application. Creating reproduction on stackblitz may take some time.

    See hierarchy screenshot, all parent classes are abstract:
    image

    Another problem with hyphens, it will not compile:

    @Input('some-property')
    public hello:string;

    I want to skip processing of certain unused libraries, to minimize build times on CI.

  12. changed the title [-]ngc can not find AppModule ngfactory when Ivy is enabled[/-] [+]Inputs are not inherited when Ivy is enabled[/+] on May 3, 2019
  13. 54 remaining items

  14. dannyskoog commented on Oct 8, 2019

    @dannyskoog
    Contributor

    Thanks for re-confirming @JoostK. I just wanted to point that out in order for that specific issue not to end up in the shadow of all other base class related matters

  15. sharikovvladislav commented on Oct 8, 2019

    @sharikovvladislav

    @pkozlowski-opensource

    Are you on the latest @next version?

    Nope. I am using stable 8.2.9 at the moment. I am trying to get ivy working on it in my project.

    In short: the general idea is that abstract classes will not be added to any NgModule

    Nice to hear it. Thank you for the answer.

    Even if you are there is still a problem where we try to resolve / inject dependencies for abstract classes (this is being fixed).

    Is there any opened issue? So we can track it?

  16. kara commented on Oct 8, 2019

    @kara
    Contributor

    In this case I may expect Bar to simply share the selector of Foo, without knowing what it is. But an empty @directive() would make that not possible anymore, isn't it?

    @trotyl In that case, you would have to copy over the decorator (that's what the schematic does for you automatically). It is slightly more boilerplate, but it's more explicit, so it's easier for anyone to look at the directive and figure out what its selector is without having to drill down the inheritance tree. You do have to know what the selector is, though. It could be an argument for another feature down the line, but probably not for v9.

    In any case, thanks for pointing out the ambiguity. Seems like we need to add another FAQ to the guide about this. cc @kapunahelewong

  17. Splaktar commented on Oct 10, 2019

    @Splaktar
    Contributor

    Nope. I am using stable 8.2.9 at the moment. I am trying to get ivy working on it in my project.

    @sharikovvladislav I don't believe that selectorless @Directive() and the intelligence around not needing to import them into a NgModule is in 8.x. I believe that it first went into 9.0.0-next.3, but you would want to grab 9.0.0-next.10 to get the most fixes related to this issue.

    With 8.x, you would need to add a fake selector to your @Directive() and import it into a module. For library authors, even if you are targeting 9.x, you still need to do this for your library to support Angular 8.x apps.

  18. fr0 commented on Oct 14, 2019

    @fr0

    Using 9.0.0-next.10 and enableIvy = true, I am having trouble using a base class component with a generic type.

    import {Component, Directive, Input} from '@angular/core';
    
    @Directive()
    export class BaseComponent<T> {
      @Input() value: T;
    }
    
    @Component({
      selector: 'app-derived',
      template: `
        {{value}}
      `
    })
    export class DerivedComponent extends BaseComponent<string> {
    
    }
    

    Using this component yields the following error:

    src/app/app.component.ts:26:18 - error TS8002: 'value' is not a valid property of <app-derived>.
    
    26     <app-derived [value]="'foo'"></app-derived>
    

    Note that DerivedComponent is imported into the module, but BaseComponent<T> is not (how would I even do this with a generic class?)

    I also get an error from the Angular language service about "BaseComponent is not declared in any Angular module" but that seems like a bug in the language service.

    If I add BaseComponent to the module, I still get the error, plus an additional error:

    src/app/app.component.ts:26:5 - error TS8001: 'app-derived' is not a valid HTML element.
    
    26     <app-derived [value]="'foo'"></app-derived>
    
  19. JoostK commented on Oct 14, 2019

    @JoostK
    Member

    @fr0 thanks for the additional info. The first error you're getting is exactly this issue, for which I opened #33131 yesterday that fixes that.

    The second error is surprising to me, could it be that it's due to a hot-reload (or does the same error persist after restarting ng serve?). The reason why I'm asking is that in #32416 a very similar error is mentioned, so it may just be that issue.

  20. fr0 commented on Oct 14, 2019

    @fr0

    @fr0 thanks for the additional info. The first error you're getting is exactly this issue, for which I opened #33131 yesterday that fixes that.

    Thanks, glad to hear it.

    The second error is surprising to me, could it be that it's due to a hot-reload (or does the same error persist after restarting ng serve?). The reason why I'm asking is that in #32416 a very similar error is mentioned, so it may just be that issue.

    It happens after restarting ng serve, so I don't think it's related to that. When trying to create a reproduction repo, I discovered that it only occurs if BaseComponent is in the declarations list and the exports list. Removing it from the exports list "fixes" that particular error. Here's a reproduction repo if you think this is worth looking into: https://github.com/fr0/angular-ivy-test

  21. added a commit that references this issue on Nov 10, 2019
  22. angular-automatic-lock-bot commented on Nov 24, 2019

    @angular-automatic-lock-bot

    This issue has been automatically locked due to inactivity.
    Please file a new issue if you are encountering a similar or related problem.

    Read more about our automatic conversation locking policy.

    This action has been performed automatically by a bot.

  23. locked and limited conversation to collaborators on Nov 24, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions