Skip to content

Conversation

meirish
Copy link
Collaborator

@meirish meirish commented Jul 18, 2025

๐Ÿ“Œ Summary

This PR changes Hds::Tag to use a single ResizeObserver for all instances of Hds:Tag. This drastically improves performance when rendering the component in large arrays.

๐Ÿ› ๏ธ Detailed description

๐Ÿ‘‹ This stemmed from an issue reported in Slack where users noted that when rendering a decently sized array of strings, changing from Hds::Tag to Hds::Badge drastically reduced the rendering time (60s to 5s - note: this also included all of the network calls, etc.).

Looking at the difference between those two components, the major difference is that the Hds::Tag adds a new ResizeObserver for each instance of the component. Refactoring the component so that only a single ResizeObserver is needed for all instances greatly improves the initial rendering performance.

NOTE: The best way to test this is to drop all but the first commit, and load up the Tag page in the showcase app which now renders a large list of tags. This will show the slow loading issue with the current implementation. Then adding in the second commit (or looking at the preview deploy) will show how the refactor improves the performance of the large list.

SECOND NOTE (๐Ÿ˜‚): The first commit should be dropped if / when you want to merge this.

๐Ÿ“ธ Screenshots

Tag showcase page loading time w/ new example

Before
Screenshot 2025-07-21 at 9 09 25โ€ฏAM

After
Screenshot 2025-07-21 at 9 08 21โ€ฏAM

๐Ÿ”— External links

Jira ticket: HDS-XXX
Figma file: [if it applies]


๐Ÿ‘€ Component checklist

๐Ÿ’ฌ Please consider using conventional comments when reviewing this PR.

๐Ÿ“‹ PCI review checklist
  • If applicable, I've documented a plan to revert these changes if they require more than reverting the pull request.
  • If applicable, I've worked with GRC to document the impact of any changes to security controls.
    Examples of changes to controls include access controls, encryption, logging, etc.
  • If applicable, I've worked with GRC to ensure compliance due to a significant change to the in-scope PCI environment.
    Examples include changes to operating systems, ports, protocols, services, cryptography-related components, PII processing code, etc.

@meirish meirish requested a review from a team as a code owner July 18, 2025 17:38
Copy link

vercel bot commented Jul 18, 2025

The latest updates on your projects. Learn more about Vercel for Git โ†—๏ธŽ

Name Status Preview Updated (UTC)
hds-showcase โœ… Ready (Inspect) Visit Preview Jul 23, 2025 1:22pm
hds-website โœ… Ready (Inspect) Visit Preview Jul 23, 2025 1:22pm

@@ -33,23 +34,44 @@ export interface HdsTagSignature {
Element: HTMLSpanElement;
}

const overflowed = new TrackedWeakSet<Element>();
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is the key to getting this working - externalizing the observer is only possible if we can track what elements are overflowed. To do this with ember's tracking, tracked-built-ins provides a tracking-entangled WeakSet. This means that getters and other computed properties that rely on this WeakSet will recompute when items are added or removed.

Copy link
Contributor

Choose a reason for hiding this comment

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

Checked the performance times for before and after and this fix correct the issues greatly. Will add some screenshots to the PR description for visibility.

@meirish
Copy link
Collaborator Author

meirish commented Jul 18, 2025

I think the Percy failure should go away once the showcase app commit is dropped.

@didoo didoo requested review from dchyun, a team and Copilot July 21, 2025 10:24
Copilot

This comment was marked as outdated.

@didoo
Copy link
Contributor

didoo commented Jul 21, 2025

@dchyun I've added you as reviewer, since you have more context about this feature.

Copy link
Contributor

@dchyun dchyun left a comment

Choose a reason for hiding this comment

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

@meirish thank you for catching this issues, and coming up with this solution. It looks like a great solution to the problem to me. If you would like I can pick this up and address the feedback, and make the showcase changes @didoo mentioned previously.

@@ -33,23 +34,44 @@ export interface HdsTagSignature {
Element: HTMLSpanElement;
}

const overflowed = new TrackedWeakSet<Element>();
Copy link
Contributor

Choose a reason for hiding this comment

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

Checked the performance times for before and after and this fix correct the issues greatly. Will add some screenshots to the PR description for visibility.

@meirish
Copy link
Collaborator Author

meirish commented Jul 21, 2025

@meirish thank you for catching this issues, and coming up with this solution. It looks like a great solution to the problem to me. If you would like I can pick this up and address the feedback, and make the showcase changes @didoo mentioned previously.

@dchyun thanks for taking a look! And feel free to pick it up - let me know if I can help or if you have other questions.

@dchyun dchyun changed the title POC - Use single ResizeObserver for Hds::Tag instances Tag - Fix performance issues with single ResizeObserver Jul 21, 2025
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR refactors the Hds::Tag component to use a single shared ResizeObserver instead of creating one observer per tag instance, significantly improving rendering performance when displaying large numbers of tags (reducing loading time from 60s to 5s in reported cases).

  • Replaced per-instance ResizeObserver with a single shared observer
  • Added TrackedWeakSet to manage overflow state across all tag instances
  • Created performance demonstration page with 1000 tag instances

Reviewed Changes

Copilot reviewed 7 out of 10 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
packages/components/src/components/hds/tag/index.ts Core refactoring to use shared ResizeObserver and TrackedWeakSet for overflow tracking
packages/components/package.json Added tracked-built-ins dependency
showcase/app/templates/page-components/tag/frameless/demo-observer-performance.hbs Demo template rendering 1000 tags for performance testing
showcase/app/routes/page-components/tag/frameless/demo-observer-performance.js Route generating test data array of 1000 items
showcase/app/templates/page-components/tag/index.hbs Added link to performance demo
showcase/app/router.ts Added nested route for frameless demo
.changeset/hungry-meals-serve.md Changelog entry documenting the performance fix
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

if (this._element) {
observer.unobserve(this._element);
}
delete this._element;
Copy link
Preview

Copilot AI Jul 21, 2025

Choose a reason for hiding this comment

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

Using delete operator on object properties can impact performance and prevent optimizations. Consider setting this._element = undefined instead.

Suggested change
delete this._element;
this._element = undefined;

Copilot uses AI. Check for mistakes.

@meirish
Copy link
Collaborator Author

meirish commented Jul 22, 2025

OK I take back what I said about the overflow being weird, that demo / iframe in the showcase app looks great โค๏ธ

Copy link
Contributor

@didoo didoo left a comment

Choose a reason for hiding this comment

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

left a couple of suggestions

@dchyun dchyun merged commit acf2ac2 into main Jul 23, 2025
16 checks passed
@dchyun dchyun deleted the tag-single-resize-observer branch July 23, 2025 19:07
@hashibot-hds hashibot-hds mentioned this pull request Jul 23, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants