Skip to content

JIT compiler and dynamic template component issue after angular 13 upgrade #22570

Closed

Description

@manuelbve

Which @angular/* package(s) are the source of the bug?

common, compiler, core

Is this a regression?

Yes

Description

Due to business reasons, we need to have the ability of loading and executing angular code dynamically in the application, the dynamic component template comes from an API call.

After upgrading from angular 12 to angular 13 our implemented solution for dynamic components is no longer working. Updating our codebase to avoid using the deprecated ViewEngine didn't help, we get the same errors.

Can't get my head around specially as to why things like the ngIf directive is not recognized anymore.

Please provide a link to a minimal reproduction of the bug

No response

Please provide the exception or error you saw

NG0304: 'swiper' is not a known element:
1. If 'swiper' is an Angular component, then verify that it is part of this module.
2. To allow any element add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component.
core.mjs:10119 NG0303: Can't bind to 'autoplay' since it isn't a known property of 'swiper'.
core.mjs:10119 NG0303: Can't bind to 'effect' since it isn't a known property of 'swiper'.
core.mjs:10119 NG0303: Can't bind to 'grabCursor' since it isn't a known property of 'swiper'.
core.mjs:10119 NG0303: Can't bind to 'loop' since it isn't a known property of 'swiper'.
core.mjs:10119 NG0303: Can't bind to 'pagination' since it isn't a known property of 'swiper'.
core.mjs:10119 NG0303: Can't bind to 'slidesPerView' since it isn't a known property of 'swiper'.
core.mjs:10119 NG0303: Can't bind to 'spaceBetween' since it isn't a known property of 'swiper'.
core.mjs:10119 NG0303: Can't bind to 'speed' since it isn't a known property of 'swiper'.
core.mjs:10119 NG0303: Can't bind to 'ngIf' since it isn't a known property of 'null'.
core.mjs:10119 NG0303: Can't bind to 'ngIf' since it isn't a known property of 'null'.
core.mjs:10119 NG0303: Can't bind to 'ngIf' since it isn't a known property of 'p'.
core.mjs:10119 NG0303: Can't bind to 'ngIf' since it isn't a known property of 'p'.
core.mjs:10119 NG0303: Can't bind to 'ngIf' since it isn't a known property of 'a'.
core.mjs:10119 NG0303: Can't bind to 'ngIf' since it isn't a known property of 'a'.
core.mjs:10119 NG0303: Can't bind to 'ngIf' since it isn't a known property of 'a'.
core.mjs:10119 NG0303: Can't bind to 'ngIf' since it isn't a known property of 'a'.
core.mjs:10119 NG0303: Can't bind to 'ngIf' since it isn't a known property of 'div'.
core.mjs:10119 NG0303: Can't bind to 'ngIf' since it isn't a known property of 'div'.
core.mjs:10119 NG0303: Can't bind to 'ngIf' since it isn't a known property of 'div'.
core.mjs:10119 NG0303: Can't bind to 'ngIf' since it isn't a known property of 'div'.
core.mjs:10119 NG0303: Can't bind to 'ngIf' since it isn't a known property of 'div'.
core.mjs:10119 NG0303: Can't bind to 'ngIf' since it isn't a known property of 'div'.
core.mjs:10119 NG0303: Can't bind to 'ngIf' since it isn't a known property of 'div'.

Please provide the environment you discovered this bug in (run ng version)

Angular CLI: 13.1.4
Node: 12.22.5
Package Manager: npm 6.14.14
OS: win32 x64

Angular: 13.1.3
... animations, cdk, common, compiler, compiler-cli, core, forms
... language-service, material, platform-browser
... platform-browser-dynamic, platform-server, router

Package                         Version
---------------------------------------------------------
@angular-devkit/architect       0.1301.4
@angular-devkit/build-angular   13.1.4
@angular-devkit/core            13.1.4
@angular-devkit/schematics      12.0.4
@angular/cli                    13.1.4
@angular/google-maps            12.2.13
@nguniversal/builders           13.0.2
@nguniversal/express-engine     12.1.3
@schematics/angular             12.0.4
rxjs                            6.6.7
typescript                      4.5.5

Anything else?

This is esentially how we're doing the whole process after the ViewEngine deprecation:

  createDynamicComponent() {
      const component = this.createComponent();
      const module = this.createModule(component);
      this.componentRef = this.container.createComponent(component, { ngModuleRef: module });
  }
  
  createComponent(): Type<any> {
      const self = this;
      const metadata = new Component({
          selector: 'dynamic',
          template: this.template,
      });
      const componentClass = class DynamicComponent implements OnInit, OnDestroy {
          constructor() {
              SwiperCore.use([Autoplay, Pagination]);
          }
          
          ngOnInit() {}
  
          ngOnDestroy() {}
      };
              
      // Class constructor parameters
      (componentClass as any).ctorParameters = () => [];
      
      return Component(metadata)(componentClass);
  }
  
  createModule(decoratedComponent: Type<any>): NgModuleRef<any> {
      const moduleClass = class RuntimeComponentModule {};
      const decoratedNgModule = NgModule({
          imports: [CommonModule, RouterModule, SharedModule],
          jit: true,
          declarations: [decoratedComponent],
      })(moduleClass);
      
      return createNgModuleRef(decoratedNgModule, this.injector);
  }

Here the SharedModule exports common things like SwiperModule, Material modules and so on.

Activity

  1. JoostK commented on Jan 25, 2022

    @JoostK
    Member

    I think what may be happening is that the CLI configures the Angular linker using linkerJitMode: false, if aot: true is set. Linking packages without JIT support means that NgModule scoping information will not be present at all. This is unlike prior versions of Angular, where the scoping metadata would only be elided in an optimization pass.

    It would be good to have a reproduction that confirms the above hypothesis, as this is an educated guess at the moment.

  2. manuelbve commented on Jan 25, 2022

    @manuelbve
    Author

    JoostK thanks for your quick reply!
    I've tried running the application with the aot compiler disabled and the dynamic components are working again.
    Does this confirm your hypothesis?

  3. JoostK commented on Jan 25, 2022

    @JoostK
    Member

    That does make it more likely to be the case, indeed.

    I'll transfer this to the CLI repo as I think that's the best place to track this limitation of how the linker is currently configured. AFAIK the CLI does not have a mode where JIT and AOT are used interchangeably.

  4. transferred this issue fromangular/angularon Jan 25, 2022
  5. alan-agius4 commented on Jan 25, 2022

    @alan-agius4
    Collaborator

    In the Angular CLI, we don't really have a support story that covers both JIT and AOT working interchangeably. This just happened to worked previously. The Angular CLI only supports JIT or AOT exclusively.

    Somewhat related issues:

  6. manuelbve commented on Jan 25, 2022

    @manuelbve
    Author

    @alan-agius4 thanks, I was already aware of those issues and indeed it would also be necessary to have it working with optimization, but right now even without optimization doesn't work anymore.

    Would it be technically feasible to have both compilers at the same time?
    Could this be something realistically worth waiting for?
    If not, is there any other/better approach we could take in order to accomplish having dynamic templates in components?

  7. alan-agius4 commented on Jan 25, 2022

    @alan-agius4
    Collaborator

    Does the dynamic template have Angular bindings/syntax?

  8. manuelbve commented on Jan 25, 2022

    @manuelbve
    Author

    Yes, that's the whole point

  9. alan-agius4 commented on Jan 26, 2022

    @alan-agius4
    Collaborator

    Would it be technically feasible to have both compilers at the same time?

    Yes, although there are some considerations to take into consider. JIT mode is typically note recommended to be used on production environments mainly because of performance overhead.

    Could this be something realistically worth waiting for?

    Dynamic View Composition API is still in proposal phase, so it is not going to happen soon if it will happen.

    If not, is there any other/better approach we could take in order to accomplish having dynamic templates in components?

    At the moment I am not aware of any other alternative.

    I'll mark this issue for further discussion, so that we can discuss this during our next team meeting.

  10. alan-agius4 commented on Feb 1, 2022

    @alan-agius4
    Collaborator

    Hi @manuelbve,

    We have discussed this in depth over the past couple of days, in general we don't recommand using JIT in production in any form at all due to security concerns. Long term we also want to go in the opposite direction and remove JIT in Angular completely. None-the-less, as it currently stands without the dynamic view composition API, the only way to create dynamic components during runtime is to use JIT.

    While as mentioned in previous comments that using AOT+JIT interop worked in some cases, it was never a supported use-case by Angular CLI. Therefore we don't classify this as a regression in functionality. Our suggestion would be to go full JIT.

  11. self-assigned this
    on Feb 1, 2022
  12. alan-agius4 commented on Feb 3, 2022

    @alan-agius4
    Collaborator

    Closing as per above.

    Please feel free to reply to this thread.

  13. angular-automatic-lock-bot commented on Mar 6, 2022

    @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.

  14. locked and limited conversation to collaborators on Mar 6, 2022
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

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions