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.xDescription
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
- clone https://github.com/zuzusik/angular-upgrade-ivy-bug
- run
ng serve
- observe all components rendered
- run
ng serve --configuration=production
- observe
<downgraded-component>
not being rendered - expected -
<downgraded-component>
is rendered
š„ 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)
@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 !
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
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.
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
andPhoneDetailComponent
). 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 droppednow mentioned line will not be present in the log, as
downgradeComponent
is used and so not droppedso, how can I know now that one of my components is dropped?