ember-did-resize-modifier icon indicating copy to clipboard operation
ember-did-resize-modifier copied to clipboard

ResizeObserver + polyfill as alternative to element-resize-detector

Open nickschot opened this issue 5 years ago • 5 comments

I've noticed the element-resize-detector is quite a huge library for what it does. Were using the native ResizeObserver + a polyfill like https://www.npmjs.com/package/resize-observer-polyfill (2.44kB gzipped) considered? Seems like it would work just as well and save many KB. The polyfill could even be loaded conditionally based on ember's config/targets.js feature.

image

nickschot avatar Mar 28 '20 14:03 nickschot

Sounds like a great idea. I came across this addon when looking for a ResizeObserver-based modifier -- that was my expectation of how this problem would likely be solved.

lukemelia avatar Jun 03 '20 03:06 lukemelia

I'd like to see how well a modifier based on ResizeObserver works too. :)

My application is for ember-container-query, whereby O(10¹) resizes can happen at the same time (not just 1 or 2 resizes). I'm interested to see if ResizeObserver performs as well as (or better than) what element-resize-detector did.

ijlee2 avatar Jun 03 '20 03:06 ijlee2

So I looked into this a bit and found out a couple of things while tinkering with a ResizeObserver proof of concept for this addon:

  1. The native ResizeObserver has no "don't run on insertion" type implementation, has to be worked around manually by ignoring the first call (no big deal here).
  2. It is most performant to use a single ResizeObserver for the entire app. See: https://groups.google.com/a/chromium.org/g/blink-dev/c/z6ienONUb5A/m/F5-VcUZtBAAJ?pli=1 The problem with this is that you cannot distinguish between multiple modifiers on the same element. We'd have to do some manual bookkeeping here to know when to actually unobserve the element.
  3. ResizeObserver passes the callback a ResizeObserverEntry by default with some pretty useful information including the new sizes of the element. In many use cases of this modifier it would be very beneficial to also provide this information through this modifier instead of just the element as it saves on layout calculations (i.e. having to call getBoundingClientRect manually in the callback forces another layout calculation). I'd prefer to simply pass the ResizeObserverEntry as the only argument, but that would be a breaking change.

Thoughts are welcome!

nickschot avatar Jun 18 '20 08:06 nickschot

I built ember-resize-observer-service to solve exactly the problem with multiple ResizeObserver instances. Feel free to use it to migrate this addon to ResizeObserver API, if it makes sense.

Building a size-responsive modifier with it is pretty straight forward:

export default class OnResizeModifier extends Modifier {
  @service resizeObserver;

  didInstall() {
    this.resizeObserver.observe(this.element, this.handleResize);
  }

  willRemove() {
    this.resizeObserver.unobserve(this.element, this.handleResize);
  }

  @action
  handleResize(...args) {
    let [callback] = this.args.positional;
    callback(...args);
  }
}

@nickschot If you need a complete ResizeObserver based solution with a single instance optimization, I built ember-on-resize-modifier.

And in case if you need a polyfill:

ember install ember-resize-observer-polyfill

ivanvolti avatar Jun 22 '20 20:06 ivanvolti

If it already exists it makes sense to migrate to that addon in my opinion. As far is I can see (after a very quick peek) the main feature difference is that your addon also runs on insert. For my use cases that doesn’t matter though.

nickschot avatar Jun 22 '20 21:06 nickschot