From f9c2e80ab72028027bf3d240b67b91f0a2479e9a Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner Date: Thu, 18 Jun 2020 20:24:53 +0200 Subject: [PATCH 1/2] build: add size test for basic chip-list with chip --- goldens/size-test.yaml | 2 ++ .../mdc-chips/BUILD.bazel | 7 ++++++ .../material-experimental/mdc-chips/basic.ts | 25 +++++++++++++++++++ .../size-test/material/chips/BUILD.bazel | 7 ++++++ integration/size-test/material/chips/basic.ts | 25 +++++++++++++++++++ 5 files changed, 66 insertions(+) create mode 100644 integration/size-test/material-experimental/mdc-chips/BUILD.bazel create mode 100644 integration/size-test/material-experimental/mdc-chips/basic.ts create mode 100644 integration/size-test/material/chips/BUILD.bazel create mode 100644 integration/size-test/material/chips/basic.ts diff --git a/goldens/size-test.yaml b/goldens/size-test.yaml index de23533f915e..db04f45d4262 100644 --- a/goldens/size-test.yaml +++ b/goldens/size-test.yaml @@ -1,7 +1,9 @@ cdk/drag-drop/all-directives: 153063 cdk/drag-drop/basic: 150321 +material-experimental/mdc-chips/basic: 151558 material/autocomplete/without-optgroup: 208091 material/button-toggle/standalone: 119400 +material/chips/basic: 163525 material/datepicker/range-picker/without-form-field: 330101 material/expansion/without-accordion: 130562 material/list/nav-list: 130473 diff --git a/integration/size-test/material-experimental/mdc-chips/BUILD.bazel b/integration/size-test/material-experimental/mdc-chips/BUILD.bazel new file mode 100644 index 000000000000..e0da7773f1a9 --- /dev/null +++ b/integration/size-test/material-experimental/mdc-chips/BUILD.bazel @@ -0,0 +1,7 @@ +load("//integration/size-test:index.bzl", "size_test") + +size_test( + name = "basic", + file = "basic.ts", + deps = ["//src/material-experimental/mdc-chips"], +) diff --git a/integration/size-test/material-experimental/mdc-chips/basic.ts b/integration/size-test/material-experimental/mdc-chips/basic.ts new file mode 100644 index 000000000000..bf44c255ee35 --- /dev/null +++ b/integration/size-test/material-experimental/mdc-chips/basic.ts @@ -0,0 +1,25 @@ +import {Component, NgModule} from '@angular/core'; +import {platformBrowser} from '@angular/platform-browser'; +import {MatChipsModule} from '@angular/material-experimental/mdc-chips'; + +/** + * Basic component using `MatChipSet` and `MatChip`. Other supported parts of the + * chip module such as `MatChipRemove` are not used and should be tree-shaken away. + */ +@Component({ + template: ` + + First + + `, +}) +export class TestComponent {} + +@NgModule({ + imports: [MatChipsModule], + declarations: [TestComponent], + bootstrap: [TestComponent], +}) +export class AppModule {} + +platformBrowser().bootstrapModule(AppModule); diff --git a/integration/size-test/material/chips/BUILD.bazel b/integration/size-test/material/chips/BUILD.bazel new file mode 100644 index 000000000000..4a2dc13e56c0 --- /dev/null +++ b/integration/size-test/material/chips/BUILD.bazel @@ -0,0 +1,7 @@ +load("//integration/size-test:index.bzl", "size_test") + +size_test( + name = "basic", + file = "basic.ts", + deps = ["//src/material/chips"], +) diff --git a/integration/size-test/material/chips/basic.ts b/integration/size-test/material/chips/basic.ts new file mode 100644 index 000000000000..41cd96ab7096 --- /dev/null +++ b/integration/size-test/material/chips/basic.ts @@ -0,0 +1,25 @@ +import {Component, NgModule} from '@angular/core'; +import {platformBrowser} from '@angular/platform-browser'; +import {MatChipsModule} from '@angular/material/chips'; + +/** + * Basic component using `MatChipList` and `MatChip`. Other supported parts of the + * chip module such as `MatChipRemove` are not used and should be tree-shaken away. + */ +@Component({ + template: ` + + First + + `, +}) +export class TestComponent {} + +@NgModule({ + imports: [MatChipsModule], + declarations: [TestComponent], + bootstrap: [TestComponent], +}) +export class AppModule {} + +platformBrowser().bootstrapModule(AppModule); From 5a1ccb1e5b49c3f9a1c3c304804df61c5f28eb73 Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner Date: Thu, 18 Jun 2020 21:07:08 +0200 Subject: [PATCH 2/2] refactor: use lightweight token for chip avatar, remove and trailing icon Currently `MatChip` always causes `MatChipAvatar`, `MatChipRemove` and `MatChipTrailingIcon` to be retained. These are optional parts of a chip and shouldn't be retained always. The retention of these classes wasn't noticeable in View Engine as no factories were generated for directives. With Ivy though, factories and definitions are generated for these directives and a size increase is noticeable. We should use lightweight tokens for querying of those directives. That will improve tree-shaking for the case where not all of these parts are used. If all parts are used, the app will slightly increase due to the provided injection tokens, but that is of average 150b, while the savings are of ~800b in the common case. Related to: #19576 --- goldens/size-test.yaml | 4 +- .../mdc-chips/chip-icons.ts | 33 ++++++++++-- src/material-experimental/mdc-chips/chip.ts | 17 ++++-- src/material/chips/chip.ts | 53 ++++++++++++++----- tools/public_api_guard/material/chips.d.ts | 6 +++ 5 files changed, 90 insertions(+), 23 deletions(-) diff --git a/goldens/size-test.yaml b/goldens/size-test.yaml index db04f45d4262..b402f11a24dc 100644 --- a/goldens/size-test.yaml +++ b/goldens/size-test.yaml @@ -1,9 +1,9 @@ cdk/drag-drop/all-directives: 153063 cdk/drag-drop/basic: 150321 -material-experimental/mdc-chips/basic: 151558 +material-experimental/mdc-chips/basic: 147613 material/autocomplete/without-optgroup: 208091 material/button-toggle/standalone: 119400 -material/chips/basic: 163525 +material/chips/basic: 162733 material/datepicker/range-picker/without-form-field: 330101 material/expansion/without-accordion: 130562 material/list/nav-list: 130473 diff --git a/src/material-experimental/mdc-chips/chip-icons.ts b/src/material-experimental/mdc-chips/chip-icons.ts index f46e90f8aff2..6788bb0b3c90 100644 --- a/src/material-experimental/mdc-chips/chip-icons.ts +++ b/src/material-experimental/mdc-chips/chip-icons.ts @@ -7,7 +7,7 @@ */ import {BooleanInput} from '@angular/cdk/coercion'; -import {ChangeDetectorRef, Directive, ElementRef, OnDestroy} from '@angular/core'; +import {ChangeDetectorRef, Directive, ElementRef, InjectionToken, OnDestroy} from '@angular/core'; import { CanDisable, CanDisableCtor, @@ -20,6 +20,13 @@ import {MDCChipTrailingActionAdapter, MDCChipTrailingActionFoundation} from '@ma import {Subject} from 'rxjs'; +/** + * Injection token that can be used to reference instances of `MatChipAvatar`. It serves as + * alternative token to the actual `MatChipAvatar` class which could cause unnecessary + * retention of the class and its directive metadata. + */ +export const MAT_CHIP_AVATAR = new InjectionToken('MatChipAvatar'); + /** * Directive to add CSS classes to chip leading icon. * @docs-private @@ -29,7 +36,8 @@ import {Subject} from 'rxjs'; host: { 'class': 'mat-mdc-chip-avatar mdc-chip__icon mdc-chip__icon--leading', 'role': 'img' - } + }, + providers: [{provide: MAT_CHIP_AVATAR, useExisting: MatChipAvatar}], }) export class MatChipAvatar { constructor(private _changeDetectorRef: ChangeDetectorRef, @@ -42,6 +50,14 @@ export class MatChipAvatar { } } +/** + * Injection token that can be used to reference instances of `MatChipTrailingIcon`. It serves as + * alternative token to the actual `MatChipTrailingIcon` class which could cause unnecessary + * retention of the class and its directive metadata. + */ +export const MAT_CHIP_TRAILING_ICON = + new InjectionToken('MatChipTrailingIcon'); + /** * Directive to add CSS classes to and configure attributes for chip trailing icon. * @docs-private @@ -53,7 +69,8 @@ export class MatChipAvatar { 'mat-mdc-chip-trailing-icon mdc-chip__icon mdc-chip__icon--trailing', 'tabindex': '-1', 'aria-hidden': 'true', - } + }, + providers: [{provide: MAT_CHIP_TRAILING_ICON, useExisting: MatChipTrailingIcon}], }) export class MatChipTrailingIcon implements OnDestroy { private _foundation: MDCChipTrailingActionFoundation; @@ -110,6 +127,13 @@ export class MatChipTrailingIcon implements OnDestroy { } } +/** + * Injection token that can be used to reference instances of `MatChipRemove`. It serves as + * alternative token to the actual `MatChipRemove` class which could cause unnecessary + * retention of the class and its directive metadata. + */ +export const MAT_CHIP_REMOVE = new InjectionToken('MatChipRemove'); + /** * Boilerplate for applying mixins to MatChipRemove. * @docs-private @@ -154,7 +178,8 @@ const _MatChipRemoveMixinBase: // We need to remove this explicitly, because it gets inherited from MatChipTrailingIcon. '[attr.aria-hidden]': 'null', - } + }, + providers: [{provide: MAT_CHIP_REMOVE, useExisting: MatChipRemove}], }) export class MatChipRemove extends _MatChipRemoveMixinBase implements CanDisable, HasTabIndex { /** diff --git a/src/material-experimental/mdc-chips/chip.ts b/src/material-experimental/mdc-chips/chip.ts index 782ab568f510..9de75fe27d6e 100644 --- a/src/material-experimental/mdc-chips/chip.ts +++ b/src/material-experimental/mdc-chips/chip.ts @@ -47,7 +47,13 @@ import {numbers} from '@material/ripple'; import {SPACE, ENTER, hasModifierKey} from '@angular/cdk/keycodes'; import {Subject} from 'rxjs'; import {takeUntil} from 'rxjs/operators'; -import {MatChipAvatar, MatChipTrailingIcon, MatChipRemove} from './chip-icons'; +import { + MatChipAvatar, + MatChipTrailingIcon, + MatChipRemove, + MAT_CHIP_AVATAR, + MAT_CHIP_TRAILING_ICON, MAT_CHIP_REMOVE +} from './chip-icons'; let uid = 0; @@ -226,14 +232,17 @@ export class MatChip extends _MatChipMixinBase implements AfterContentInit, Afte /** Subject that emits when the component has been destroyed. */ protected _destroyed = new Subject(); + // TODO: Remove cast once https://github.com/angular/angular/pull/37506 is available. /** The chip's leading icon. */ - @ContentChild(MatChipAvatar) leadingIcon: MatChipAvatar; + @ContentChild(MAT_CHIP_AVATAR as any) leadingIcon: MatChipAvatar; + // TODO: Remove cast once https://github.com/angular/angular/pull/37506 is available. /** The chip's trailing icon. */ - @ContentChild(MatChipTrailingIcon) trailingIcon: MatChipTrailingIcon; + @ContentChild(MAT_CHIP_TRAILING_ICON as any) trailingIcon: MatChipTrailingIcon; + // TODO: Remove cast once https://github.com/angular/angular/pull/37506 is available. /** The chip's trailing remove icon. */ - @ContentChild(MatChipRemove) removeIcon: MatChipRemove; + @ContentChild(MAT_CHIP_REMOVE as any) removeIcon: MatChipRemove; /** Reference to the MatRipple instance of the chip. */ @ViewChild(MatRipple) ripple: MatRipple; diff --git a/src/material/chips/chip.ts b/src/material/chips/chip.ts index 89054b501f52..65e486c439d7 100644 --- a/src/material/chips/chip.ts +++ b/src/material/chips/chip.ts @@ -6,25 +6,25 @@ * found in the LICENSE file at https://angular.io/license */ -import {DOCUMENT} from '@angular/common'; import {FocusableOption} from '@angular/cdk/a11y'; import {BooleanInput, coerceBooleanProperty} from '@angular/cdk/coercion'; import {BACKSPACE, DELETE, SPACE} from '@angular/cdk/keycodes'; import {Platform} from '@angular/cdk/platform'; +import {DOCUMENT} from '@angular/common'; import { + Attribute, + ChangeDetectorRef, ContentChild, Directive, ElementRef, EventEmitter, - forwardRef, Inject, + InjectionToken, Input, NgZone, OnDestroy, Optional, Output, - ChangeDetectorRef, - Attribute, } from '@angular/core'; import { CanColor, @@ -33,18 +33,18 @@ import { CanDisableRippleCtor, HasTabIndex, HasTabIndexCtor, - mixinTabIndex, MAT_RIPPLE_GLOBAL_OPTIONS, mixinColor, mixinDisableRipple, + mixinTabIndex, RippleConfig, RippleGlobalOptions, RippleRenderer, RippleTarget, } from '@angular/material/core'; +import {ANIMATION_MODULE_TYPE} from '@angular/platform-browser/animations'; import {Subject} from 'rxjs'; import {take} from 'rxjs/operators'; -import {ANIMATION_MODULE_TYPE} from '@angular/platform-browser/animations'; /** Represents an event fired on an individual `mat-chip`. */ @@ -64,6 +64,27 @@ export class MatChipSelectionChange { public isUserInput = false) { } } +/** + * Injection token that can be used to reference instances of `MatChipRemove`. It serves as + * alternative token to the actual `MatChipRemove` class which could cause unnecessary + * retention of the class and its directive metadata. + */ +export const MAT_CHIP_REMOVE = new InjectionToken('MatChipRemove'); + +/** + * Injection token that can be used to reference instances of `MatChipAvatar`. It serves as + * alternative token to the actual `MatChipAvatar` class which could cause unnecessary + * retention of the class and its directive metadata. + */ +export const MAT_CHIP_AVATAR = new InjectionToken('MatChipAvatar'); + +/** + * Injection token that can be used to reference instances of `MatChipTrailingIcon`. It serves as + * alternative token to the actual `MatChipTrailingIcon` class which could cause unnecessary + * retention of the class and its directive metadata. + */ +export const MAT_CHIP_TRAILING_ICON = + new InjectionToken('MatChipTrailingIcon'); // Boilerplate for applying mixins to MatChip. /** @docs-private */ @@ -82,7 +103,8 @@ const _MatChipMixinBase: CanColorCtor & CanDisableRippleCtor & */ @Directive({ selector: 'mat-chip-avatar, [matChipAvatar]', - host: {'class': 'mat-chip-avatar'} + host: {'class': 'mat-chip-avatar'}, + providers: [{provide: MAT_CHIP_AVATAR, useExisting: MatChipAvatar}] }) export class MatChipAvatar {} @@ -92,10 +114,12 @@ export class MatChipAvatar {} */ @Directive({ selector: 'mat-chip-trailing-icon, [matChipTrailingIcon]', - host: {'class': 'mat-chip-trailing-icon'} + host: {'class': 'mat-chip-trailing-icon'}, + providers: [{provide: MAT_CHIP_TRAILING_ICON, useExisting: MatChipTrailingIcon}], }) export class MatChipTrailingIcon {} + /** * Material design styled Chip component. Used inside the MatChipList component. */ @@ -165,14 +189,17 @@ export class MatChip extends _MatChipMixinBase implements FocusableOption, OnDes /** Whether the chip list as a whole is disabled. */ _chipListDisabled: boolean = false; + // TODO: Remove cast once https://github.com/angular/angular/pull/37506 is available. /** The chip avatar */ - @ContentChild(MatChipAvatar) avatar: MatChipAvatar; + @ContentChild(MAT_CHIP_AVATAR as any) avatar: MatChipAvatar; + // TODO: Remove cast once https://github.com/angular/angular/pull/37506 is available. /** The chip's trailing icon. */ - @ContentChild(MatChipTrailingIcon) trailingIcon: MatChipTrailingIcon; + @ContentChild(MAT_CHIP_TRAILING_ICON as any) trailingIcon: MatChipTrailingIcon; + // TODO: Remove cast once https://github.com/angular/angular/pull/37506 is available. /** The chip's remove toggler. */ - @ContentChild(forwardRef(() => MatChipRemove)) removeIcon: MatChipRemove; + @ContentChild(MAT_CHIP_REMOVE as any) removeIcon: MatChipRemove; /** Whether the chip is selected. */ @Input() @@ -429,7 +456,6 @@ export class MatChip extends _MatChipMixinBase implements FocusableOption, OnDes static ngAcceptInputType_disableRipple: BooleanInput; } - /** * Applies proper (click) support and adds styling for use with the Material Design "cancel" icon * available at https://material.io/icons/#ic_cancel. @@ -448,7 +474,8 @@ export class MatChip extends _MatChipMixinBase implements FocusableOption, OnDes host: { 'class': 'mat-chip-remove mat-chip-trailing-icon', '(click)': '_handleClick($event)', - } + }, + providers: [{provide: MAT_CHIP_REMOVE, useExisting: MatChipRemove}], }) export class MatChipRemove { constructor( diff --git a/tools/public_api_guard/material/chips.d.ts b/tools/public_api_guard/material/chips.d.ts index 31b434eca948..1ac0c6d338a8 100644 --- a/tools/public_api_guard/material/chips.d.ts +++ b/tools/public_api_guard/material/chips.d.ts @@ -1,3 +1,9 @@ +export declare const MAT_CHIP_AVATAR: InjectionToken; + +export declare const MAT_CHIP_REMOVE: InjectionToken; + +export declare const MAT_CHIP_TRAILING_ICON: InjectionToken; + export declare const MAT_CHIPS_DEFAULT_OPTIONS: InjectionToken; export declare class MatChip extends _MatChipMixinBase implements FocusableOption, OnDestroy, CanColor, CanDisableRipple, RippleTarget, HasTabIndex {