Skip to content

When built with optimization compileModuleAndAllComponentsSync returns an empty list of component factories #36255

Closed

Description

@AndreiVajnaII

🐞 bug report

Affected Package

@angular/compiler

Is this a regression?

This seems to be the behavoir since at least 9.0.1.

Description

Calling the Compiler.compileModuleAndAllComponentsSync method is supposed to return the component factories in addition to the module factory. However, when built with --prod, that list is empty.

Looking over the compiled code, it looks like the declarations are completely removed from the module. Setting 'optimization' to false in angular.json solves the problem, but that means the code is no longer built for production.

🔬 Minimal Reproduction

The problem can be observed with this minimal repo: https://github.com/AndreiVajnaII/lazy-load-ng-modules

Just npm install and ng serve. Clicking on either "Load module 1" or "Load module 2" will call the
compileModuleAndAllComponentsSync on a lazy loaded module and display a list of components it declares. However, if started with ng serve --prod, the list will be empty.

🔥 Exception or Error

No error is given, the list of component factories is just empty

🌍 Your Environment

Angular Version:


Angular CLI: 9.0.7
Node: 10.14.1
OS: win32 x64

Angular: 9.0.7
... cli, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... router
Ivy Workspace: Yes

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.900.7
@angular-devkit/build-angular     0.900.7
@angular-devkit/build-optimizer   0.900.7
@angular-devkit/build-webpack     0.900.7
@angular-devkit/core              9.0.7
@angular-devkit/schematics        9.0.7
@ngtools/webpack                  9.0.7
@schematics/angular               9.0.7
@schematics/update                0.900.7
rxjs                              6.5.4
typescript                        3.7.5
webpack                           4.41.2

Activity

  1. added this to the needsTriage milestone on Mar 26, 2020
  2. JoostK commented on Mar 26, 2020

    @JoostK
    Member

    The Angular compiler generates AOT code that does retain this information through the setNgModuleScope function, but it's guarded by the ngJitMode global. It appears that the CLI unconditionally removes this call and it doesn't seem possible today to configure this behaviour.

    This PR in the CLI seems relevant: angular/angular-cli#16694. @clydin can you comment on any plans in the CLI regarding JIT mode interop with AOT compiled code?

  3. AndreiVajnaII commented on Mar 31, 2020

    @AndreiVajnaII
    Author

    I guess the behaviour is intentional. What I find confusing is that the behaviour is different between production and dev, not between AOT and JIT.

    What I'd like to know is if there is any way to get what components are declared in a module (even by using internal API). And if not, if it is intentional, or if there would be a way in the near future.

  4. JoostK commented on Mar 31, 2020

    @JoostK
    Member

    If you create a production build, it is generally assumed that you don't use JIT aspects to allow for much more effective tree-shaking. This is controlled using the ngJitMode variable, which is new to Ivy and can be used to mix AOT and JIT compilations. As mentioned above, the CLI always assumes this flag is false, so it will get rid of the JIT compatibility code. I don't know whether there's plans to influence this behaviour in the CLI, hence the question to @clydin.

    I would be interested to learn about your use-case, though. Could you elaborate on how you're using these APIs? Do you depend on JIT compilation using platformBrowserDynamic, or are you only using this API to get the components of a module without necessarily needing JIT compilations?

  5. AndreiVajnaII commented on Mar 31, 2020

    @AndreiVajnaII
    Author

    It's the latter. We do not want to compile anything. I didn't find any way to lazy load an NgModule. And noticed that the router does this using the compiler (which doesn't actually compile anything in AOT mode :)), so I did the same.

  6. alxhub commented on May 26, 2020

    @alxhub
    Member

    As others have mentioned, with optimizations on the part of the NgModule definition which refers to components/etc. is removed. This allows components to be tree-shaken (since otherwise they would never be removed as modules would contain references to every component).

    If you have a use case where you want to load a module and enumerate some components from it, I suggest making a custom multi-provider token and having the module register each component type via the multi-provider (sort of like how the ROUTES token works in the router). You can then load the module, create an injector from it, inject the token, and get a list of components that way. This won't be affected by the optimizer as you're writing your own references to the components, not relying on the module definition.

  7. AndreiVajnaII commented on May 29, 2020

    @AndreiVajnaII
    Author

    Yup, that sounds reasonable. Still, from an API point of view, it's weird. I can understand this feature not being available with AOT at all, but having it work or not based on whether you use optimization or not is confusing.

  8. modified the milestones: needsTriage, Backlog on Sep 22, 2020
  9. added
    P4A relatively minor issue that is not relevant to core functions
    and removed on Oct 1, 2020
  10. alan-agius4 commented on Nov 10, 2020

    @alan-agius4
    Contributor

    Hi all,

    AOT+JIT interop with any build optimizations is not a supported path and we don't recommend this approach to be used for production. The main reasons are that this approach increases drastically the bundle sizes, performance overhead and exposes your application to cross-site scripting (XSS) since compiling components at runtime is a XSS vulnerability in itself.

    I created an issue to capture and document this: #39624

  11. angular-automatic-lock-bot commented on Dec 11, 2020

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

  12. locked and limited conversation to collaborators on Dec 11, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P4A relatively minor issue that is not relevant to core functionsarea: compilerIssues related to `ngc`, Angular's template compilertype: confusing

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions