angular: Ivy doesn't include downgraded components into production build

šŸž Bug report

Command (mark with an x)

  • new
  • build
  • serve
  • test
  • e2e
  • generate
  • add
  • update
  • lint
  • xi18n
  • run
  • config
  • help
  • version
  • doc

Is this a regression?

Yes, the previous version in which this bug was not present was: 8.x.x

Description

Consider following situation:

  • there is an AngularJS application
  • follow official upgrade guide to get it into hybrid mode with ngUpgrade
  • start writing all new components in new Angular (to not to add more legacy code) and where needed - use downgradeComponent to be able to use Angular components in AngularJS
  • if downgraded component is used only in AngularJS templates - it will be shaken off the tree with production build - this manifests itself in component just not being rendered. Silently. No errors, warnings, or whatsoever.

Workaround

It can be fixed with referencing the component somewhere, as suggested in related issues - https://github.com/angular/angular/issues/35314#issuecomment-584821399, or in https://github.com/angular/angular-cli/issues/16246#issuecomment-557051190

Fix commit: https://github.com/zuzusik/angular-upgrade-ivy-bug/commit/f123b6bcb680231f823d9260c29b9a79cd6d4c2f

Things to fix/improve

There are several things about this which donā€™t look right:

  • this is huge regression for applications using ngUpgrade - ideally this should be fixed
  • it all happens silently - no errors/warnings/logs or whatsoever - at least it should give some clues about it
  • itā€™s discrepancy between prod and dev build - in dev build all still works great - ideally these 2 builds should not have such huge discrepancies
  • official upgrade guide says to include component into entryComponents which has no effect in Ivy - at least it should have some notes about compatibility with Ivy and possible shake off of the downgraded components

šŸ”¬ Minimal Reproduction

šŸ”„ Exception or Error




No exceptions or errors or whatsoever - and this is very frustrating.

šŸŒ Your Environment




Angular CLI: 9.1.5
Node: 12.16.3
OS: darwin x64

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

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.901.5
@angular-devkit/build-angular     0.901.5
@angular-devkit/build-optimizer   0.901.5
@angular-devkit/build-webpack     0.901.5
@angular-devkit/core              9.1.5
@angular-devkit/schematics        9.1.5
@angular/cli                      9.1.5
@ngtools/webpack                  9.1.5
@schematics/angular               9.1.5
@schematics/update                0.901.5
rxjs                              6.5.5
typescript                        3.8.3
webpack                           4.42.0

Anything else relevant?

This is not really relevant, but this was very frustrating experience - literally everything is done by the guide and the app just ends up silently broken. Took me quite a time to figure all outā€¦

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 3
  • Comments: 17 (11 by maintainers)

Most upvoted comments

@alan-agius4 yes, I see that as well, but that doesnā€™t give me any clue that my component is being dropped (downgradeComponent is Angularā€™s function - not from projectā€™s code) - this message is pretty cryptic - it isnā€™t clear which part of code itā€™s coming from

@kapunahelewong Ducks generally say ā€œQuackā€! šŸ¦†

That data is already available if you use ā€”-verbose flag.

It will return all statements and functions that were dropped.

Ha! @JoostK itā€™s my goofy dictation app! 80% of the time it says ducks instead of docs! Iā€™m here everyday. Tune in tomorrow for more! šŸ˜†

thanks for your input, @JoostK !

import ā€˜./downgrade.componentā€™;

Yes, this would work, but I personally donā€™t like it cause it creates a double import situation - it is also required to import component class to register it in NgModule

Alternatively, you may want to consider registering the downgraded components in the same file as the NgModule.

Yes, this would work as well, though it somehow contradicts commonly adopted approach of writing Angular.js code.

Generally speaking - the issue has workaround, yes. Even several of them. I personally ended up with declaring components in a static array property of the module class.

In my opinion the documentation should be adjusted for those two components (moving the registration into the NgModule file) and perhaps a note about this situation could be added.

This sounds good, but again - registering components like that is not a common thing in Angular.js world, so there is a big chance this specific approach would be just ignored (unless we make it super clear, that itā€™s required to avoid situations with possible tree shaking)

In this particular instance, I would consider the call with global side-effects at the top-level of a module to be the culprit:

https://github.com/zuzusik/angular-upgrade-ivy-bug/blob/c31e260096d0e1436fe781c7e5c44cc98b4b7a51/src/app/downgraded.component.ts#L12-L14

The compiler elides the import to enable tree-shaking, however this will also drop the side-effect. For a module with global side-effects, itā€™s generally a good idea to have an import that is unequivocally a side-effectful import:

import './downgrade.component';

Alternatively, you may want to consider registering the downgraded components in the same file as the NgModule. Looking at the documentation, that is what is done for HeroDetailComponent but not the others (PhoneListComponent and PhoneDetailComponent). In my opinion the documentation should be adjusted for those two components (moving the registration into the NgModule file) and perhaps a note about this situation could be added.

@alan-agius4 I get it

but still it doesnā€™t give any clue that some component is dropped

imagine there are 2 components using downgradeComponent - one is dropped, the other is not dropped

now mentioned line will not be present in the log, as downgradeComponent is used and so not dropped

so, how can I know now that one of my components is dropped?