Skip to content

buildOptimizer deleted some code from a property setter in a component that came from an ng-packagr library #14084

Closed
@fr0

Description

@fr0

🐞 Bug report

Command (mark with an x)

- [ ] new
- [x] build
- [x] serve
- [ ] test
- [ ] e2e
- [ ] generate
- [ ] add
- [ ] update
- [ ] lint
- [ ] xi18n
- [ ] run
- [ ] config
- [ ] help
- [ ] version
- [ ] doc

Is this a regression?

Unknown.

Description

The build optimizer seems to have stripped out some important code. Here's my original TypeScript (template and styles ommitted for brevity):

export interface IExpandable {
  isExpanded: boolean;
  isExpandedChange: EventEmitter<boolean>;
  canExpand: boolean;
  toggleExpand(): void;
  expand();
  collapse();
}

@Component({
  selector: 'atlas-expandable-if',
  template: `
...
  `,
  styles: [`
...
  `]
})
export class ExpandableIfComponent implements IExpandable {
  @Input() preserveSpaceForIcon: boolean = true;
  @Input() canExpand: boolean = true;
  @Input() expandIcon: string;
  @Input() collapseIcon: string;
  @Input() loadingIcon: string;
  @Input() delayedExpand = false;
  @Input() overrideIcon: string|false = false;
  @Output() isExpandedChange: EventEmitter<boolean> = new EventEmitter<boolean>();
  isExpanding = false;

  constructor(public icons: AtlasIconPaths,
              private changeDetector: ChangeDetectorRef) { }

  private _isExpanded = false;
  get isExpanded(): boolean { return this._isExpanded; }
  @Input() set isExpanded(value: boolean) {
    if (this._isExpanded !== value) {
      this._isExpanded = value;
      this.isExpandedChange.emit(value);
      this.changeDetector.markForCheck();
    }
  }

  clickHeader(event: MouseEvent) {
    if (!event.shiftKey) {
      event.preventDefault();
      event.stopPropagation();
      this.toggleExpand();
    }
  }

  toggleExpand() {
    if (this.isExpanding) { return; }
    if (this.isExpanded || this.canExpand) {
      if (this.isExpanded) {
        this.collapse();
      }
      else {
        this.expand();
      }
    }
  }
  expand() {
    if (this.delayedExpand) {
      this.isExpanding = true;
      setTimeout(() => {
        this.isExpanding = false;
        this.isExpanded = true;
      });
      this.changeDetector.markForCheck();
    }
    else {
      this.isExpanded = true;
    }
  }
  collapse() {
    this.isExpanded = false;
  }
}

And here's the code that gets generated with buildOptimizer: true (un-minified, but otherwise presented as-is):

Notice the set isExpanded property setter

                    sa = class {
                        constructor(e, t) {
                            this.icons = e, this.changeDetector = t, this.preserveSpaceForIcon = !0, this.canExpand = !0, this.delayedExpand = !1, this.overrideIcon = !1, this.isExpandedChange = new it, this.isExpanding = !1, this._isExpanded = !1
                        }
                        get isExpanded() {
                            return this._isExpanded
                        }
                        set isExpanded(e) {
                            this._isExpanded !== e && (this._isExpanded = e)
                        }
                        clickHeader(e) {
                            e.shiftKey || (e.preventDefault(), e.stopPropagation(), this.toggleExpand())
                        }
                        toggleExpand() {
                            this.isExpanding || (this.isExpanded || this.canExpand) && (this.isExpanded ? this.collapse() : this.expand())
                        }
                        expand() {
                            this.delayedExpand ? (this.isExpanding = !0, setTimeout(() => {
                                this.isExpanding = !1, this.isExpanded = !0
                            }), this.changeDetector.markForCheck()) : this.isExpanded = !0
                        }
                        collapse() {
                            this.isExpanded = !1
                        }
                    },

This code is in a library that gets packaged via ng-packagr version 5.0.1. However, here is the code that ng-packagr generates:

let ExpandableIfComponent = class ExpandableIfComponent {
    constructor(icons, changeDetector) {
        this.icons = icons;
        this.changeDetector = changeDetector;
        this.preserveSpaceForIcon = true;
        this.canExpand = true;
        this.delayedExpand = false;
        this.overrideIcon = false;
        this.isExpandedChange = new EventEmitter();
        this.isExpanding = false;
        this._isExpanded = false;
    }
    get isExpanded() { return this._isExpanded; }
    set isExpanded(value) {
        if (this._isExpanded !== value) {
            this._isExpanded = value;
            this.isExpandedChange.emit(value);
            this.changeDetector.markForCheck();
        }
    }
    clickHeader(event) {
        if (!event.shiftKey) {
            event.preventDefault();
            event.stopPropagation();
            this.toggleExpand();
        }
    }
    toggleExpand() {
        if (this.isExpanding) {
            return;
        }
        if (this.isExpanded || this.canExpand) {
            if (this.isExpanded) {
                this.collapse();
            }
            else {
                this.expand();
            }
        }
    }
    expand() {
        if (this.delayedExpand) {
            this.isExpanding = true;
            setTimeout(() => {
                this.isExpanding = false;
                this.isExpanded = true;
            });
            this.changeDetector.markForCheck();
        }
        else {
            this.isExpanded = true;
        }
    }
    collapse() {
        this.isExpanded = false;
    }
};
__decorate([
    Input(),
    __metadata("design:type", Boolean)
], ExpandableIfComponent.prototype, "preserveSpaceForIcon", void 0);
__decorate([
    Input(),
    __metadata("design:type", Boolean)
], ExpandableIfComponent.prototype, "canExpand", void 0);
__decorate([
    Input(),
    __metadata("design:type", String)
], ExpandableIfComponent.prototype, "expandIcon", void 0);
__decorate([
    Input(),
    __metadata("design:type", String)
], ExpandableIfComponent.prototype, "collapseIcon", void 0);
__decorate([
    Input(),
    __metadata("design:type", String)
], ExpandableIfComponent.prototype, "loadingIcon", void 0);
__decorate([
    Input(),
    __metadata("design:type", Object)
], ExpandableIfComponent.prototype, "delayedExpand", void 0);
__decorate([
    Input(),
    __metadata("design:type", Object)
], ExpandableIfComponent.prototype, "overrideIcon", void 0);
__decorate([
    Output(),
    __metadata("design:type", EventEmitter)
], ExpandableIfComponent.prototype, "isExpandedChange", void 0);
__decorate([
    Input(),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], ExpandableIfComponent.prototype, "isExpanded", null);
ExpandableIfComponent = __decorate([
    Component({
        selector: 'atlas-expandable-if',
        template: `
...
        styles: [`
...
  `]
    }),
    __metadata("design:paramtypes", [AtlasIconPaths,
        ChangeDetectorRef])
], ExpandableIfComponent);

The correct code is generated if buildOptimizer: false is used in my angular.json.

🌍 Your Environment




Angular CLI: 7.3.7
Node: 11.12.0
OS: darwin x64
Angular: 7.2.11
... animations, common, compiler, compiler-cli, core, elements
... forms, http, language-service, platform-browser
... platform-browser-dynamic, router

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.13.7
@angular-devkit/build-angular     0.13.7
@angular-devkit/build-optimizer   0.13.7
@angular-devkit/core              7.3.7
@angular-devkit/schematics        7.3.7
@angular/cli                      7.3.7
@ngtools/json-schema              1.1.0
@schematics/angular               7.3.7
@schematics/update                0.13.7
ng-packagr                        5.0.1
rxjs                              6.4.0
typescript                        3.2.4
webpack                           4.29.6

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions