angular: Recursion of components (and circular imports) doesn't work in Ivy built libraries
🐞 bug report
Affected Package
Probably @angular/compiler
Is this a regression?
The first version I detected the bug in is 9.0.0.
Description
If I use recursion of components in an Ivy-built library, children will be not rendered.
It only appears when built with --prod
.
Relevant code:
@Component({
selector: 'lib-recursive-list',
template: `
<lib-recursive-item *ngFor="let item of list" [model]="item"></lib-recursive-item>
`,
styles: []
})
export class RecursiveListComponent {
@Input() list: RecursiveModel[];
}
@Component({
selector: 'lib-recursive-item',
template: `
<div style="padding-left: 10px;">
<div>{{model.name}}</div>
<lib-recursive-list [list]="model.children"></lib-recursive-list>
</div>
`,
styles: []
})
export class RecursiveItemComponent {
@Input() model: RecursiveModel;
}
🔬 Minimal Reproduction
https://github.com/darress/angular9_lib_bugs/tree/recursion
Build the library with ng build my-lib
, then build the app with ng build
, it will work as expected.
However if built with ng build --prod
, only the two parents will be rendered, not the children.
🔥 Exception or Error
No exceptions or errors.
🌍 Your Environment
Angular Version:
_ _ ____ _ ___
/ \ _ __ __ _ _ _| | __ _ _ __ / ___| | |_ _|
/ △ \ | '_ \ / _` | | | | |/ _` | '__| | | | | | |
/ ___ \| | | | (_| | |_| | | (_| | | | |___| |___ | |
/_/ \_\_| |_|\__, |\__,_|_|\__,_|_| \____|_____|___|
|___/
Angular CLI: 9.0.3
Node: 10.14.2
OS: win32 x64
Angular: 9.0.2
... animations, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... router
Ivy Workspace: Yes
Package Version
------------------------------------------------------------
@angular-devkit/architect 0.900.3
@angular-devkit/build-angular 0.900.3
@angular-devkit/build-ng-packagr 0.900.3
@angular-devkit/build-optimizer 0.900.3
@angular-devkit/build-webpack 0.900.3
@angular-devkit/core 9.0.3
@angular-devkit/schematics 9.0.3
@angular/cli 9.0.3
@ngtools/webpack 9.0.3
@schematics/angular 9.0.3
@schematics/update 0.900.3
ng-packagr 9.0.1
rxjs 6.5.4
typescript 3.7.5
webpack 4.41.2
Anything else relevant? Reproducable with Chrome and Firefox. Tested under Windows 10.
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Reactions: 26
- Comments: 36 (13 by maintainers)
Reproduces as reported, and the cause is exactly what I expected to find.
when ngtsc compiles the library, the cycle detector rejects the import from
RecursiveItemComponent
for thedirectiveDefs
ofRecursiveListComponent
as it would create a cycle.instead, ngtsc deopts to a side-effectful
ɵɵsetComponentScope
call next toMyLibModule
.because the module is in a library, it gets built by CLI with a
package.json
which sayssideEffects: false
Terser dutifully strips the
ɵɵsetComponentScope
call when processing the library codeOne of the components is missing its
directiveDefs
at runtime.I can think of only one real solution here: ngtsc needs to be modified to be okay with cycles externally, since external tooling can handle them. We would need to generate wrapped
directiveDef
arrays for both components in this case, as we don’t know in what order these files will be imported. This is pretty tricky to keep track of, and also has an impact on incremental build since the addition of a cycle could require the emit of new files.A workaround is to set
sideEffects: true
in the librarypackage.json
, which tells the optimizer not to remove top-level calls (among other things).We have encountered this recently.
We have moved a part of our app to a library and as our app is built with Ivy, we consumed Ivy library version as well. It was very much confusing experience when in prod mode the library turned out broken where it was working flawlessly in dev mode. The worst thing that there are zero clues how to debug and where to dig - fail happens silently and verbose mode is not much of a help - the output of terser is very cryptic - it’s not clear at all what is being shaken off and why. After hours of googling was lucky to found this issue…
With that said, I believe
--verbose
mode should provide meaningful information about things being removed from the build. That would make it much easier to troubleshoot issues like this. I have already raised this once in another issue (start reading from https://github.com/angular/angular/issues/37102#issuecomment-628782822), but that seems didn’t go anywhere.Also, I agree this issue shouldn’t be marked as low frequency and second priority - this is pretty much a fundamental issue with libraries Ivy builds and Ivy builds are promoted as main way to build libraries going forward.
If you have 2 components in the library, A and B, and you include B in A’s template and use a static method of A in B (or exported funtion/class/anything), the same problem occurs.
Reproduction is here: https://github.com/darress/angular9_lib_bugs/tree/import_recursion
This is maybe a more minimal reproduction of the problem.
The same workaround (
"sideEffects": true
) works here too.I agree that
freq1: low
is probably not appropriate - and in fact is not featuring in our triage of issues anymore anyway. The key label isP2
which I think accurately captures this issue:Hi @elesueur to build your library with view engine your tsconfig needs
enableIvy: false
in theangularCompilerOptions
, see here: https://angular.io/guide/ivy#opting-out-of-ivy-in-version-9Hi @alxhub we meet this problem too https://github.com/ng-packagr/ng-packagr/issues/1576 I think the freq label should not be low, and it is very hard to figure what happened after encountering this bug
@Phil147 indeed, this is an instance of the same problem.
This is because the application is built with
sideEffects: true
by default 😃Thank you @alxhub for the workaround, we can go full Ivy now!
Also @darress, thank you for the small and useful reproduction, it allowed me to verify what I thought was happening very easily.