From de8ebbdfd03feca36eb891e2cd3fb54c8279211f Mon Sep 17 00:00:00 2001 From: Kara Erickson Date: Mon, 19 Aug 2019 20:00:26 -0700 Subject: [PATCH] feat(ivy): make Hammer support tree-shakable (#32203) Currently, it's not possible to tree-shake away the coordination layer between HammerJS and Angular's EventManager. This means that you get the HammerJS support code in your production bundle whether or not you actually use the library. This commit removes the Hammer providers from the default platform_browser providers list and instead provides them as part of a `HammerModule`. Apps on Ivy just need to import the `HammerModule` at root to turn on Hammer support. Otherwise all Hammer code will tree-shake away. View Engine apps will require no change. BREAKING CHANGE Previously, in Ivy applications, Hammer providers were included by default. With this commit, apps that want Hammer support must import `HammerModule` in their root module. PR Close #32203 --- integration/_payload-limits.json | 4 +- packages/platform-browser/src/browser.ts | 10 +- .../src/dom/events/hammer_gestures.ts | 49 +++++- .../platform-browser/src/platform-browser.ts | 2 +- tools/material-ci/test-blocklist.ts | 139 +++++++++++++++++- .../platform-browser/platform-browser.d.ts | 3 + 6 files changed, 193 insertions(+), 14 deletions(-) diff --git a/integration/_payload-limits.json b/integration/_payload-limits.json index ba86fd7470..5cb49533a6 100644 --- a/integration/_payload-limits.json +++ b/integration/_payload-limits.json @@ -21,7 +21,7 @@ "master": { "uncompressed": { "runtime": 1440, - "main": 136390, + "main": 134091, "polyfills": 45340 } } @@ -34,4 +34,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/platform-browser/src/browser.ts b/packages/platform-browser/src/browser.ts index bf8774e5bf..29fa0e5b36 100644 --- a/packages/platform-browser/src/browser.ts +++ b/packages/platform-browser/src/browser.ts @@ -17,7 +17,7 @@ import {ELEMENT_PROBE_PROVIDERS} from './dom/debug/ng_probe'; import {DomRendererFactory2} from './dom/dom_renderer'; import {DomEventsPlugin} from './dom/events/dom_events'; import {EVENT_MANAGER_PLUGINS, EventManager} from './dom/events/event_manager'; -import {HAMMER_GESTURE_CONFIG, HAMMER_LOADER, HammerGestureConfig, HammerGesturesPlugin} from './dom/events/hammer_gestures'; +import {HAMMER_PROVIDERS} from './dom/events/hammer_gestures'; import {KeyEventsPlugin} from './dom/events/key_events'; import {DomSharedStylesHost, SharedStylesHost} from './dom/shared_styles_host'; import {DomSanitizer, DomSanitizerImpl} from './security/dom_sanitization_service'; @@ -77,13 +77,7 @@ export const BROWSER_MODULE_PROVIDERS: StaticProvider[] = [ deps: [DOCUMENT, NgZone, PLATFORM_ID] }, {provide: EVENT_MANAGER_PLUGINS, useClass: KeyEventsPlugin, multi: true, deps: [DOCUMENT]}, - { - provide: EVENT_MANAGER_PLUGINS, - useClass: HammerGesturesPlugin, - multi: true, - deps: [DOCUMENT, HAMMER_GESTURE_CONFIG, Console, [new Optional(), HAMMER_LOADER]] - }, - {provide: HAMMER_GESTURE_CONFIG, useClass: HammerGestureConfig, deps: []}, + HAMMER_PROVIDERS, { provide: DomRendererFactory2, useClass: DomRendererFactory2, diff --git a/packages/platform-browser/src/dom/events/hammer_gestures.ts b/packages/platform-browser/src/dom/events/hammer_gestures.ts index a1be88cc05..27f7e961fb 100644 --- a/packages/platform-browser/src/dom/events/hammer_gestures.ts +++ b/packages/platform-browser/src/dom/events/hammer_gestures.ts @@ -7,9 +7,11 @@ */ import {DOCUMENT} from '@angular/common'; -import {Inject, Injectable, InjectionToken, Optional, ɵConsole as Console} from '@angular/core'; +import {Inject, Injectable, InjectionToken, NgModule, Optional, Provider, ɵConsole as Console} from '@angular/core'; + +import {EVENT_MANAGER_PLUGINS, EventManagerPlugin} from './event_manager'; + -import {EventManagerPlugin} from './event_manager'; /** * Supported HammerJS recognizer event names. @@ -56,6 +58,7 @@ const EVENT_NAMES = { * DI token for providing [HammerJS](http://hammerjs.github.io/) support to Angular. * @see `HammerGestureConfig` * + * @ngModule HammerModule * @publicApi */ export const HAMMER_GESTURE_CONFIG = new InjectionToken('HammerGestureConfig'); @@ -149,6 +152,11 @@ export class HammerGestureConfig { } } +/** + * Event plugin that adds Hammer support to an application. + * + * @ngModule HammerModule + */ @Injectable() export class HammerGesturesPlugin extends EventManagerPlugin { constructor( @@ -234,3 +242,40 @@ export class HammerGesturesPlugin extends EventManagerPlugin { isCustomEvent(eventName: string): boolean { return this._config.events.indexOf(eventName) > -1; } } + +/** + * In Ivy, support for Hammer gestures is optional, so applications must + * import the `HammerModule` at root to turn on support. This means that + * Hammer-specific code can be tree-shaken away if not needed. + */ +export const HAMMER_PROVIDERS__POST_R3__ = []; + +/** + * In View Engine, support for Hammer gestures is built-in by default. + */ +export const HAMMER_PROVIDERS__PRE_R3__: Provider[] = [ + { + provide: EVENT_MANAGER_PLUGINS, + useClass: HammerGesturesPlugin, + multi: true, + deps: [DOCUMENT, HAMMER_GESTURE_CONFIG, Console, [new Optional(), HAMMER_LOADER]] + }, + {provide: HAMMER_GESTURE_CONFIG, useClass: HammerGestureConfig, deps: []}, +]; + +export const HAMMER_PROVIDERS = HAMMER_PROVIDERS__PRE_R3__; + +/** + * Adds support for HammerJS. + * + * Import this module at the root of your application so that Angular can work with + * HammerJS to detect gesture events. + * + * Note that applications still need to include the HammerJS script itself. This module + * simply sets up the coordination layer between HammerJS and Angular's EventManager. + * + * @publicApi + */ +@NgModule({providers: HAMMER_PROVIDERS__PRE_R3__}) +export class HammerModule { +} diff --git a/packages/platform-browser/src/platform-browser.ts b/packages/platform-browser/src/platform-browser.ts index 305313a529..5c3d5ac11f 100644 --- a/packages/platform-browser/src/platform-browser.ts +++ b/packages/platform-browser/src/platform-browser.ts @@ -13,7 +13,7 @@ export {disableDebugTools, enableDebugTools} from './browser/tools/tools'; export {BrowserTransferStateModule, StateKey, TransferState, makeStateKey} from './browser/transfer_state'; export {By} from './dom/debug/by'; export {EVENT_MANAGER_PLUGINS, EventManager} from './dom/events/event_manager'; -export {HAMMER_GESTURE_CONFIG, HAMMER_LOADER, HammerGestureConfig, HammerLoader} from './dom/events/hammer_gestures'; +export {HAMMER_GESTURE_CONFIG, HAMMER_LOADER, HAMMER_PROVIDERS__POST_R3__ as ɵHAMMER_PROVIDERS__POST_R3__, HammerGestureConfig, HammerLoader, HammerModule} from './dom/events/hammer_gestures'; export {DomSanitizer, SafeHtml, SafeResourceUrl, SafeScript, SafeStyle, SafeUrl, SafeValue} from './security/dom_sanitization_service'; export * from './private_export'; diff --git a/tools/material-ci/test-blocklist.ts b/tools/material-ci/test-blocklist.ts index 84540fb3a4..2eb0dbc2de 100644 --- a/tools/material-ci/test-blocklist.ts +++ b/tools/material-ci/test-blocklist.ts @@ -24,6 +24,143 @@ interface BlocklistEntry { * repository. It should be possible to disable these tests until the component repository * migrated the broken tests. */ -export const testBlocklist: {[testName: string]: BlocklistEntry} = {}; +export const testBlocklist: {[testName: string]: BlocklistEntry} = { + "MatSlideToggle without forms with dragging should not emit a change event when the value did not change": { + "error": "Unknown", + "notes": "Restore when Material has included HammerModule or removed dep on Hammer" + }, + "MatSlideToggle without forms with dragging should ignore clicks on the label element while dragging": { + "error": "Unknown", + "notes": "Restore when Material has included HammerModule or removed dep on Hammer" + }, + "MatSlideToggle without forms with dragging should drag from end to start": { + "error": "Unknown", + "notes": "Restore when Material has included HammerModule or removed dep on Hammer" + }, + "MatSlideToggle without forms with dragging should drag from end to start in RTL": { + "error": "Unknown", + "notes": "Restore when Material has included HammerModule or removed dep on Hammer" + }, + "MatSlideToggle without forms with dragging should update the checked property of the input": { + "error": "Unknown", + "notes": "Restore when Material has included HammerModule or removed dep on Hammer" + }, + "MatSlideToggle without forms with dragging should not drag when disabled": { + "error": "Unknown", + "notes": "Restore when Material has included HammerModule or removed dep on Hammer" + }, + "MatSlideToggle without forms with dragging should emit a change event after drag": { + "error": "Unknown", + "notes": "Restore when Material has included HammerModule or removed dep on Hammer" + }, + "MatSlideToggle without forms with dragging should drag from start to end": { + "error": "Unknown", + "notes": "Restore when Material has included HammerModule or removed dep on Hammer" + }, + "MatSlideToggle without forms with dragging should drag from start to end in RTL": { + "error": "Unknown", + "notes": "Restore when Material has included HammerModule or removed dep on Hammer" + }, + "MatSlideToggle without forms custom action configuration should not change value on dragging when drag action is noop": { + "error": "Unknown", + "notes": "Restore when Material has included HammerModule or removed dep on Hammer" + }, + "MatSlider slider with thumb label should update the thumb label text on slide": { + "error": "Unknown", + "notes": "Restore when Material has included HammerModule or removed dep on Hammer" + }, + "MatSlider slider with set step should truncate long decimal values when using a decimal step": { + "error": "Unknown", + "notes": "Restore when Material has included HammerModule or removed dep on Hammer" + }, + "MatSlider slider with set step should not add decimals to the value if it is a whole number": { + "error": "Unknown", + "notes": "Restore when Material has included HammerModule or removed dep on Hammer" + }, + "MatSlider slider with set step should set the correct step value on slide": { + "error": "Unknown", + "notes": "Restore when Material has included HammerModule or removed dep on Hammer" + }, + "MatSlider slider with set step should round the value inside the label based on the provided step": { + "error": "Unknown", + "notes": "Restore when Material has included HammerModule or removed dep on Hammer" + }, + "MatSlider slider with set step should snap the thumb and fill to a step on slide": { + "error": "Unknown", + "notes": "Restore when Material has included HammerModule or removed dep on Hammer" + }, + "MatSlider slider with set value should set the correct value on slide": { + "error": "Unknown", + "notes": "Restore when Material has included HammerModule or removed dep on Hammer" + }, + "MatSlider slider with ngModel should update the model on slide": { + "error": "Unknown", + "notes": "Restore when Material has included HammerModule or removed dep on Hammer" + }, + "MatSlider slider with input event should emit an input event while sliding": { + "error": "Unknown", + "notes": "Restore when Material has included HammerModule or removed dep on Hammer" + }, + "MatSlider standard slider should add and remove the mat-slider-sliding class when sliding": { + "error": "Unknown", + "notes": "Restore when Material has included HammerModule or removed dep on Hammer" + }, + "MatSlider standard slider should not change value without emitting a change event": { + "error": "Unknown", + "notes": "Restore when Material has included HammerModule or removed dep on Hammer" + }, + "MatSlider standard slider should update the value on a slide": { + "error": "Unknown", + "notes": "Restore when Material has included HammerModule or removed dep on Hammer" + }, + "MatSlider standard slider should slide to the max value when the steps do not divide evenly into it": { + "error": "Unknown", + "notes": "Restore when Material has included HammerModule or removed dep on Hammer" + }, + "MatSlider standard slider should set the value as max when sliding past the track": { + "error": "Unknown", + "notes": "Restore when Material has included HammerModule or removed dep on Hammer" + }, + "MatSlider standard slider should update the track fill on slide": { + "error": "Unknown", + "notes": "Restore when Material has included HammerModule or removed dep on Hammer" + }, + "MatSlider standard slider should set the value as min when sliding before the track": { + "error": "Unknown", + "notes": "Restore when Material has included HammerModule or removed dep on Hammer" + }, + "MatSlider slider as a custom form control should update the control on slide": { + "error": "Unknown", + "notes": "Restore when Material has included HammerModule or removed dep on Hammer" + }, + "MatSlider slider with set min and max should set the correct value on slide": { + "error": "Unknown", + "notes": "Restore when Material has included HammerModule or removed dep on Hammer" + }, + "MatSlider slider with set min and max should snap the fill to the nearest value on slide": { + "error": "Unknown", + "notes": "Restore when Material has included HammerModule or removed dep on Hammer" + }, + "MatSlider disabled slider should not add the mat-slider-sliding class on slide when disabled": { + "error": "Unknown", + "notes": "Restore when Material has included HammerModule or removed dep on Hammer" + }, + "MatSlider disabled slider should not emit change when disabled": { + "error": "Unknown", + "notes": "Restore when Material has included HammerModule or removed dep on Hammer" + }, + "MatSlider disabled slider should not change the value on slide when disabled": { + "error": "Unknown", + "notes": "Restore when Material has included HammerModule or removed dep on Hammer" + }, + "MatSlider slider with change handler should emit change on slide": { + "error": "Unknown", + "notes": "Restore when Material has included HammerModule or removed dep on Hammer" + }, + "MatSlider slider with change handler should not emit multiple changes for same value": { + "error": "Unknown", + "notes": "Restore when Material has included HammerModule or removed dep on Hammer" + }, +}; // clang-format on diff --git a/tools/public_api_guard/platform-browser/platform-browser.d.ts b/tools/public_api_guard/platform-browser/platform-browser.d.ts index 1d380def79..7817c149ac 100644 --- a/tools/public_api_guard/platform-browser/platform-browser.d.ts +++ b/tools/public_api_guard/platform-browser/platform-browser.d.ts @@ -60,6 +60,9 @@ export declare class HammerGestureConfig { export declare type HammerLoader = () => Promise; +export declare class HammerModule { +} + export declare function makeStateKey(key: string): StateKey; export declare class Meta {