Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(material/button): make button ripples lazy #26568

Merged
merged 1 commit into from Apr 5, 2023

Conversation

wagnermaciel
Copy link
Contributor

No description provided.

@angular-robot angular-robot bot added the detected: feature PR contains a feature commit label Feb 3, 2023
@wagnermaciel
Copy link
Contributor Author

Here is the design doc which describes this feature as well as the rationale for why it was written this way:
https://docs.google.com/document/d/13paaXem1sXg6462-bb05M8GHguvQcsXGC8FxDeK6w_Q/edit?usp=sharing

src/material/button/button-lazy-loader.ts Outdated Show resolved Hide resolved
* Traverses the element and its parents (heading toward the document root)
* until it finds a mat-button that has not been initialized.
*/
private _closest(element: Element): Element | null {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can use the native Element.closest API here instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mleibman could probably speak to this best but from what I remember in our last discussions, this is actually a performance improvement. I have added a link to their example at the bottom of our design doc

https://docs.google.com/document/d/13paaXem1sXg6462-bb05M8GHguvQcsXGC8FxDeK6w_Q/edit?usp=sharing

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that's not exactly the same, because it's setting a symbol on the DOM node whereas here we have an attribute.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I'm very skeptical that a userspace closest is faster than the browser native closest. I would need to see some compelling evidence, and then I would go complain to Chrome.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds plausible - I could have just misremembered. I switched to using the native Element.closest and I can revisit this if it really is a performance bottleneck

src/material/button/button-lazy-loader.ts Outdated Show resolved Hide resolved
src/material/button/button.ts Outdated Show resolved Hide resolved
src/material/button/button-ripple.ts Outdated Show resolved Hide resolved
src/material/button/button-base.ts Outdated Show resolved Hide resolved
src/material/button/button-base.ts Outdated Show resolved Hide resolved
src/material/button/button-lazy-loader.ts Show resolved Hide resolved
src/material/button/button-lazy-loader.ts Show resolved Hide resolved
src/material/button/button-lazy-loader.ts Outdated Show resolved Hide resolved
* Traverses the element and its parents (heading toward the document root)
* until it finds a mat-button that has not been initialized.
*/
private _closest(element: Element): Element | null {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I'm very skeptical that a userspace closest is faster than the browser native closest. I would need to see some compelling evidence, and then I would go complain to Chrome.

src/material/button/button-lazy-loader.ts Show resolved Hide resolved
src/material/button/button.ts Outdated Show resolved Hide resolved
Comment on lines 52 to 62
constructor(
_elementRef: ElementRef<HTMLElement>,
readonly ngZone: NgZone,
readonly platform: Platform,
@Optional() @Inject(MAT_RIPPLE_GLOBAL_OPTIONS) globalOptions?: RippleGlobalOptions,
@Optional() @Inject(ANIMATION_MODULE_TYPE) _animationMode?: string,
@Optional() @Inject(DOCUMENT) document?: Document,
) {
super(_elementRef, ngZone, platform, globalOptions, _animationMode, document);
this._buttonEl = _elementRef.nativeElement;
this._buttonEl.classList.remove('mat-ripple');
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer the inject function

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was able to do this for document, but not any of the other symbols because they are referenced in the call to super and references to this are not allowed before super is called

src/material/button/icon-button.scss Outdated Show resolved Hide resolved
@wagnermaciel wagnermaciel force-pushed the button-perf branch 2 times, most recently from 54ba026 to fc7f0a8 Compare March 31, 2023 03:59
@jelbourn
Copy link
Member

@wagnermaciel it doesn't actually have to be a directive instance, it just has to have the same API shape, no?

rough pseudo-code for the idea

type PublicInterface<T> = {[K in keyof T]: T[K]};

class DeferredRipple implements PublicInterface<MatRipple> {
  // ripple stuff
}

class MatButton {
  get ripple(): MatRipple {
    if (!this._rippleInternal) this._rippleInternal = this.createRipple();
    return this._rippleInternal;
  }

  private _rippleInternal = null;
}

(it's possible I'm missing some detail, admittedly)

@wagnermaciel
Copy link
Contributor Author

@jelbourn Previously, when I considered this approach I was against it because I didn't want to be creating & having to maintain a MatRipple-like object. This time around, I just tried creating a new MatRipple(...). I didn't think it'd work bc it's not designed to work that way, but I was able to get it working!

@wagnermaciel wagnermaciel force-pushed the button-perf branch 2 times, most recently from b253a9a to 369e74e Compare March 31, 2023 19:56
Copy link
Member

@jelbourn jelbourn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks good- the only main thing left is adding additional tests for MatButtonLazyLoader

src/material/button/button-base.ts Show resolved Hide resolved
src/material/button/button-base.ts Outdated Show resolved Hide resolved
src/material/button/button-lazy-loader.ts Outdated Show resolved Hide resolved
src/material/button/button-lazy-loader.ts Outdated Show resolved Hide resolved
src/material/button/button-lazy-loader.ts Outdated Show resolved Hide resolved
Copy link
Member

@jelbourn jelbourn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

src/material/button/button.spec.ts Outdated Show resolved Hide resolved
@wagnermaciel wagnermaciel added target: minor This PR is targeted for the next minor release action: merge The PR is ready for merge by the caretaker labels Apr 4, 2023
@wagnermaciel wagnermaciel force-pushed the button-perf branch 2 times, most recently from 22df8c7 to 24757b4 Compare April 5, 2023 04:17
@angular-robot angular-robot bot merged commit d6d3e3e into angular:main Apr 5, 2023
19 of 22 checks passed
@isantone
Copy link
Contributor

Hi @wagnermaciel @jelbourn,
Could you please check this PR #26970 for fixing mat-fab and mat-mini-fab ripple effect?
Thanks!

@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators May 22, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
action: merge The PR is ready for merge by the caretaker detected: feature PR contains a feature commit target: minor This PR is targeted for the next minor release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants