Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't retrieve exported components from 傻mod when using production mode #21952

Closed
1 of 15 tasks
nohanna opened this issue Oct 14, 2021 · 6 comments
Closed
1 of 15 tasks

Comments

@nohanna
Copy link

nohanna commented Oct 14, 2021

馃悶 Bug report

Command (mark with an x)

  • new
  • build
  • serve
  • test
  • e2e
  • generate
  • add
  • update
  • lint
  • extract-i18n
  • run
  • config
  • help
  • version
  • doc

Is this a regression?

This behavior also happens in Angular 11 (in production mode) and happens in Angular 12 because of default production mode.

Description

Note: I already posted on stackoverflow, but got no answer. Since it is really blocking and I'm not sure if it is a bug, I'm opening a bug report here because it is linked to the AOT compilation.

I'm using Angular with Webpack 5 Module Federation for micro-frontends. I have 2 apps (let's call them app1 and app2) and my main app, app1, is federating components of app2.

In app2, my exposed components are exported by my main module, so when I try to federate some component, I can get it from the export section of my module. Everything works fine in dev mode, I can get my exposed module, retrieve my exported components and then use the component factory resolver to create it where I want in app1.

But when I build in production (I used ng serve --prod to reproduce the prod environment and test it) my exported components are gone but not the imports and providers. This is the module I get:

MyApp2Module: class e
  傻fac: 茠 (t)
  傻inj:
    imports: Array(1)
      0: (12) [茠, 茠, 茠, 茠, 茠, 茠, 茠, 茠, 茠, 茠, 茠, 茠]
      length: 1
      [[Prototype]]: Array(0)
    providers: [茠]
    [[Prototype]]: Object
  傻mod:
    bootstrap: []
    declarations: []
    exports: []
    id: null
    imports: []
    schemas: null
    transitiveCompileScopes: null
    type: class e
    [[Prototype]]: Object

As you can see, in 傻mod, I have no exported components and no declarations and I expected to see my components here. I guess it is due to AOT compilation and the optimization since it is working in dev mode. Is AOT removing everything in 傻mod on purpose or it is because my components are tree-shaked since they are not directly used by my app2?
I tried to use sideEffects but it is not working. Is there another way to tell the compiler to not remove those components?

馃敩 Minimal Reproduction

I created a reproduction here.
Just use:

If you go to http://localhost:4200 and click in the navbar on "second app" you will see that the sidebar added 3 links which are loaded from second-app.

Now if you do the same in production mode:

Open the devtools, if you go to http://localhost:4200 and click in the navbar on "second app" you will see the object and the error.

馃敟 Exception or Error




ERROR Error: Uncaught (in promise): TypeError: Cannot read properties of undefined (reading '傻cmp')
TypeError: Cannot read properties of undefined (reading '傻cmp')
    at ye (main.js:1)
    at Qg.resolveComponentFactory (main.js:1)
    at main.js:1
    at c.invoke (polyfills.js:1)
    at Object.onInvoke (main.js:1)
    at c.invoke (polyfills.js:1)
    at u.run (polyfills.js:1)
    at polyfills.js:1
    at c.invokeTask (polyfills.js:1)
    at Object.onInvokeTask (main.js:1)
    at k (polyfills.js:1)
    at polyfills.js:1
    at c.invokeTask (polyfills.js:1)
    at Object.onInvokeTask (main.js:1)
    at c.invokeTask (polyfills.js:1)
    at u.runTask (polyfills.js:1)
    at _ (polyfills.js:1)

馃實 Your Environment




Angular CLI: 11.2.14
Node: 16.9.1
OS: linux x64

Angular: 11.2.14
... animations, cli, common, compiler, compiler-cli, core, forms
... platform-browser, platform-browser-dynamic, router
Ivy Workspace: Yes

Package                         Version
---------------------------------------------------------
@angular-devkit/architect       0.1102.14
@angular-devkit/build-angular   0.1102.14
@angular-devkit/core            11.2.14
@angular-devkit/schematics      11.2.14
@schematics/angular             11.2.14
@schematics/update              0.1102.14
ng-packagr                      11.2.4
rxjs                            6.6.7
typescript                      4.1.6
@clydin
Copy link
Member

clydin commented Oct 14, 2021

Unfortunately for this situation, customized Webpack configurations and/or usage of Webpack specific features are not officially supported by the Angular CLI. Customization of the Webpack configuration is also only possible by using third-party builders which are not maintained nor directly supported by the Angular Team. Within the Angular CLI, Webpack is considered an internal implementation detail which may or may not be used to fully build the application in all modes, now or in the future.

However, it may be useful to open an issue with the maintainers of either the https://github.com/just-jeb/angular-builders or https://github.com/manfredsteyer/ngx-build-plus projects as they may have more experience in this area.

@nohanna
Copy link
Author

nohanna commented Oct 14, 2021

Thanks for the answer, I will open an issue with them.

I'm aware that this is a specific case, but do you know if there any way to explicitly tell terser to not remove classes or is it totally related to Webpack? Because I know that Angular is using "build-optimizer" so that's why I tried to use sideEffects since it is directly related to Webpack. I guess something like build-optimizer does with /*@__PURE__*/.

@alan-agius4
Copy link
Collaborator

I think what might work is to assign a static field on the NgModule class that declares the "unused" components. While t NgModule.declarations field is removed by the AOT compiler, the custom static field isn't. This would causes the components to be flagged as used and therefore they shouldn't get removed.

const DECLARATIONS = [
      Cmp1,
      Cmp2 
 ];

@NgModule({
  declarations: DECLARATIONS,
})
export class MyModule {
  static declarations: DECLARATIONS
}

That said as @clydin mentioned customized Webpack configurations and/or using Webpack specific features are not officially supported by the Angular tooling team.

@clydin
Copy link
Member

clydin commented Oct 18, 2021

One additional note regarding why this currently works in development but not production is that the JIT mode support code is removed in production. This support code adds metadata to the Angular module definitions at runtime which is allowing the reproduction to function. However, since JIT mode support code forces all unused components (including from libraries) to be retained and the application is AOT compiled, the JIT mode support code is removed in production.

@nohanna
Copy link
Author

nohanna commented Oct 18, 2021

Ok I get it, I fixed it with a static field.
Thanks for your answers.

@angular-automatic-lock-bot
Copy link

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.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Nov 18, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants