From f90a19af8c8602f75add3eeacbde5a078bb70382 Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner Date: Mon, 15 Jun 2020 15:19:41 +0200 Subject: [PATCH 1/2] build: add size-test for menu without lazy-content --- goldens/size-test.yaml | 1 + .../size-test/material/menu/BUILD.bazel | 7 ++++++ .../material/menu/without-lazy-content.ts | 24 +++++++++++++++++++ 3 files changed, 32 insertions(+) create mode 100644 integration/size-test/material/menu/BUILD.bazel create mode 100644 integration/size-test/material/menu/without-lazy-content.ts diff --git a/goldens/size-test.yaml b/goldens/size-test.yaml index adfbd99cb03d..d4a551b18f5d 100644 --- a/goldens/size-test.yaml +++ b/goldens/size-test.yaml @@ -1,2 +1,3 @@ material/list/nav-list: 130473 material/radio/without-group: 121448 +material/menu/without-lazy-content: 211926 diff --git a/integration/size-test/material/menu/BUILD.bazel b/integration/size-test/material/menu/BUILD.bazel new file mode 100644 index 000000000000..b05792da3d1d --- /dev/null +++ b/integration/size-test/material/menu/BUILD.bazel @@ -0,0 +1,7 @@ +load("//integration/size-test:index.bzl", "size_test") + +size_test( + name = "without-lazy-content", + file = "without-lazy-content.ts", + deps = ["//src/material/menu"], +) diff --git a/integration/size-test/material/menu/without-lazy-content.ts b/integration/size-test/material/menu/without-lazy-content.ts new file mode 100644 index 000000000000..4c1fb39012df --- /dev/null +++ b/integration/size-test/material/menu/without-lazy-content.ts @@ -0,0 +1,24 @@ +import {Component, NgModule} from '@angular/core'; +import {MatMenuModule} from '@angular/material/menu'; +import {platformBrowser} from '@angular/platform-browser'; + +/** + * Basic component using `MatMenu` and `MatMenuTrigger`. No lazy `MatMenuContent` is + * specified, so it should be tree-shaken away. + */ +@Component({ + template: ` + + + `, +}) +export class TestComponent {} + +@NgModule({ + imports: [MatMenuModule], + declarations: [TestComponent], + bootstrap: [TestComponent], +}) +export class AppModule {} + +platformBrowser().bootstrapModule(AppModule); From 729707f558e9edf2a96049e9649faf96988eed38 Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner Date: Mon, 15 Jun 2020 15:23:33 +0200 Subject: [PATCH 2/2] refactor: use lightweight token for lazy menu content Angular Material supports lazy content for menus. It does this by querying for the `MatMenuContent` directive in the `MatMenu` component. This is problematic though as it always causes `MatMenuContent` to be retained as its used as actual query predicate token. To solve this, we use a lightweight injection token for querying the lazy content (if present). This optimizes applications using the Angular Material menu without lazy content. Related to: #19576. --- goldens/size-test.yaml | 2 +- src/material/menu/menu-content.ts | 11 ++++++++++- src/material/menu/menu.ts | 5 +++-- tools/public_api_guard/material/menu.d.ts | 2 ++ 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/goldens/size-test.yaml b/goldens/size-test.yaml index d4a551b18f5d..ab4c6b264bc0 100644 --- a/goldens/size-test.yaml +++ b/goldens/size-test.yaml @@ -1,3 +1,3 @@ material/list/nav-list: 130473 material/radio/without-group: 121448 -material/menu/without-lazy-content: 211926 +material/menu/without-lazy-content: 210751 diff --git a/src/material/menu/menu-content.ts b/src/material/menu/menu-content.ts index 83c16daa374b..be4281eee281 100644 --- a/src/material/menu/menu-content.ts +++ b/src/material/menu/menu-content.ts @@ -14,6 +14,7 @@ import { ComponentFactoryResolver, Directive, Inject, + InjectionToken, Injector, OnDestroy, TemplateRef, @@ -21,11 +22,19 @@ import { } from '@angular/core'; import {Subject} from 'rxjs'; +/** + * Injection token that can be used to reference instances of `MatMenuContent`. It serves + * as alternative token to the actual `MatMenuContent` class which could cause unnecessary + * retention of the class and its directive metadata. + */ +export const MAT_MENU_CONTENT = new InjectionToken('MatMenuContent'); + /** * Menu content that will be rendered lazily once the menu is opened. */ @Directive({ - selector: 'ng-template[matMenuContent]' + selector: 'ng-template[matMenuContent]', + providers: [{provide: MAT_MENU_CONTENT, useExisting: MatMenuContent}], }) export class MatMenuContent implements OnDestroy { private _portal: TemplatePortal; diff --git a/src/material/menu/menu.ts b/src/material/menu/menu.ts index f700730b6dc0..f672fa2c6775 100644 --- a/src/material/menu/menu.ts +++ b/src/material/menu/menu.ts @@ -43,7 +43,7 @@ import { import {merge, Observable, Subject, Subscription} from 'rxjs'; import {startWith, switchMap, take} from 'rxjs/operators'; import {matMenuAnimations} from './menu-animations'; -import {MatMenuContent} from './menu-content'; +import {MAT_MENU_CONTENT, MatMenuContent} from './menu-content'; import {MenuPositionX, MenuPositionY} from './menu-positions'; import {throwMatMenuInvalidPositionX, throwMatMenuInvalidPositionY} from './menu-errors'; import {MatMenuItem} from './menu-item'; @@ -179,11 +179,12 @@ export class _MatMenuBase implements AfterContentInit, MatMenuPanel */ @ContentChildren(MatMenuItem, {descendants: false}) items: QueryList; + // TODO: Remove cast once https://github.com/angular/angular/pull/37506 is available. /** * Menu content that will be rendered lazily. * @docs-private */ - @ContentChild(MatMenuContent) lazyContent: MatMenuContent; + @ContentChild(MAT_MENU_CONTENT as any) lazyContent: MatMenuContent; /** Whether the menu should overlap its trigger. */ @Input() diff --git a/tools/public_api_guard/material/menu.d.ts b/tools/public_api_guard/material/menu.d.ts index b4167e72f340..24a5cf0c1e97 100644 --- a/tools/public_api_guard/material/menu.d.ts +++ b/tools/public_api_guard/material/menu.d.ts @@ -65,6 +65,8 @@ export declare class _MatMenuDirectivesModule { export declare const fadeInItems: AnimationTriggerMetadata; +export declare const MAT_MENU_CONTENT: InjectionToken; + export declare const MAT_MENU_DEFAULT_OPTIONS: InjectionToken; export declare const MAT_MENU_PANEL: InjectionToken>;