Skip to content

Improve performance of bind:clientWidth using ResizeObserver api #7583

Closed
@Gin-Quin

Description

@Gin-Quin

Describe the problem

The bind:clientWidth directive is very useful when you need to programmatically control the size of an element, but its current implementation suffers heavy performance issues.

Presently, it seems that an iframe is created to compute the element size. Adding a new element like an iframe is not a light operation, and if a developper starts to setup bind:clientWidth everywhere, its application will become very laggy.

There exists is an official and quite simple API to deal with these kind of situations: the ResizeObserver API. Its purpose is to listen to any change of the element size and trigger a callback function.

I tested the performance some time ago compared to Svelte's current approach, and when having a lot of bind:clientWidth, the performance gain is huge.

Describe the proposed solution

I am personally using these 24 lines of code instead of bind:clientWidth to create a directive named resizeObserver:

let observer: ResizeObserver;
let callbacks: WeakMap<Element, (element: Element) => any>;

export function resizeObserver(element: Element, onResize: (element: Element) => any) {
   if (!observer) {
      callbacks = new WeakMap();
      observer = new ResizeObserver(entries => {
         for (const entry of entries) {
            const onResize = callbacks.get(entry.target);
            if (onResize) onResize(entry.target);
         }
      });
   }

   callbacks.set(element, onResize);
   observer.observe(element);

   return {
      destroy: () => {
         callbacks.delete(element);
         observer.unobserve(element);
      },
   };
}

Then you can use it this way to mimic bind:clientWidth but without having to create an iframe:

<script lang="ts">
   let clientWidth = 0
</script>

<div use:resizeObserver={element => clientWidth = element.clientWidth}>
   My width is: {clientWidth}
</div>

Alternatives considered

Checking size changes is tricky. The ResizeObserver api is native and well-supported by browsers so I see no reason to not use it.

Importance

nice to have

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions