-
Notifications
You must be signed in to change notification settings - Fork 11.9k
Description
🐞 Bug report
Command (mark with an x)
- [ ] new
- [x] 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: ....no
Description
A clear and concise description of the problem...While debugging Ivy payload size issues, I noticed that DeprecatedI18NPipesModule was not being removed from hello world cli app, but only in the Ivy mode. Digging deeper I noticed that the build pipeline doesn't make ngInjectorDef assignments avalable for DCE.
Snippet from the pre-terser code:
common_DeprecatedI18NPipesModule.ngInjectorDef = /*@__PURE__*/ ɵɵdefineInjector({
factory: function DeprecatedI18NPipesModule_Factory(t) {
return new (t || common_DeprecatedI18NPipesModule)();
},
providers: [{ provide: DEPRECATED_PLURAL_FN, useValue: common_0$2 }] });
Terser won't remove this because it's a static property assignment. So while the right handside is marked as pure, the left handside might have a side effect and therefore will be retained.
I think this is a general problem we have in the pipeline where we generally expect that the static properties will be assigned within the PURE IIFE wrapped around a class, but in this case the assignment happens outside of that IIFE likely because of two other function calls (ɵɵsetNgModuleScope and setClassMetadata) that are emitted in between the class body and the static assignment:
let common_DeprecatedI18NPipesModule = /*@__PURE__*/ (() => {
class DeprecatedI18NPipesModule {
}
DeprecatedI18NPipesModule.ngModuleDef = ɵɵdefineNgModule({ type: DeprecatedI18NPipesModule });
return DeprecatedI18NPipesModule;
})();
/*@__PURE__*/ /*@__PURE__*/ ɵɵsetNgModuleScope(common_DeprecatedI18NPipesModule, {
declarations: [common_DeprecatedDecimalPipe,
common_DeprecatedPercentPipe,
common_DeprecatedCurrencyPipe,
common_DeprecatedDatePipe], exports: [common_DeprecatedDecimalPipe,
common_DeprecatedPercentPipe,
common_DeprecatedCurrencyPipe,
common_DeprecatedDatePipe]
});
/*@__PURE__*/ /*@__PURE__*/ setClassMetadata(common_DeprecatedI18NPipesModule, [{
type: NgModule,
args: [{
declarations: [COMMON_DEPRECATED_I18N_PIPES],
exports: [COMMON_DEPRECATED_I18N_PIPES],
providers: [{ provide: DEPRECATED_PLURAL_FN, useValue: common_0$2 }]
}]
}], null, null);
common_DeprecatedI18NPipesModule.ngInjectorDef = /*@__PURE__*/ ɵɵdefineInjector({
factory: function DeprecatedI18NPipesModule_Factory(t) {
return new (t || common_DeprecatedI18NPipesModule)();
},
providers:
[{ provide: DEPRECATED_PLURAL_FN, useValue: common_0$2 }] });
Because the static property assignment is now outside of the PURE class IIFE, the static property assignment is ineligible for DCE.
To fix this we have two options:
- ensure that the static property assignment is located within the class body by changing the order in which these things are emitted by ngtsc
- wrap the static property assignment in a new PURE IIFE:
/*@__PURE__*/ (function() { common_DeprecatedI18NPipesModule.ngInjectorDef = /*@__PURE__*/ ɵɵdefineInjector({
factory: function DeprecatedI18NPipesModule_Factory(t) {
return new (t || common_DeprecatedI18NPipesModule)();
},
providers: [{ provide: DEPRECATED_PLURAL_FN, useValue: common_0$2 }] });
})();
note the IIFE around the assignment marked as pure.
I'm slightly leaning towards the options number two just because it's more generic and could catch other issues.
🔬 Minimal Reproduction
yarn global add @angular/cli@next
ng new size-test --enable-ivy
cd size-test
ng build --prod
review bundles and you'll see DeprecatedI18NPipesModule retained due to the pattern described above.
🔥 Exception or Error
🌍 Your Environment
Angular CLI: 8.2.0-rc.0
Node: 10.11.0
OS: darwin x64
Angular: 8.2.0-rc.0
... animations, cli, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... router
Package Version
-----------------------------------------------------------
@angular-devkit/architect 0.802.0-rc.0
@angular-devkit/build-angular 0.802.0-rc.0
@angular-devkit/build-optimizer 0.802.0-rc.0
@angular-devkit/build-webpack 0.802.0-rc.0
@angular-devkit/core 8.2.0-rc.0
@angular-devkit/schematics 8.2.0-rc.0
@ngtools/webpack 8.2.0-rc.0
@schematics/angular 8.2.0-rc.0
@schematics/update 0.802.0-rc.0
rxjs 6.4.0
typescript 3.5.3
webpack 4.38.0
Anything else relevant?