Skip to content
This repository was archived by the owner on Feb 17, 2026. It is now read-only.

fix(i18n): globalstateservice stateupdates memory leak#343

Open
Bowen7 wants to merge 2 commits intovmware-clarity:mainfrom
Bowen7:i18n-memory-leak
Open

fix(i18n): globalstateservice stateupdates memory leak#343
Bowen7 wants to merge 2 commits intovmware-clarity:mainfrom
Bowen7:i18n-memory-leak

Conversation

@Bowen7
Copy link

@Bowen7 Bowen7 commented Jun 23, 2025

PR Checklist

Please check if your PR fulfills the following requirements:

  • Tests for the changes have been added (for bug fixes / features)
  • Docs have been added / updated (for bug fixes / features)
  • If applicable, have a visual design approval

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Documentation content changes
  • clarity.design website / infrastructure changes
  • Other... Please describe:

What is the current behavior?

Demo: https://stackblitz.com/edit/clarity-core-angularjs-yk53hdkf?file=src%2Findex.js

Continuously clicking the Show/Hide button, find that GlobalStateService.stateUpdates.subscriptions.length is continuously increasing:

10
15
20
25

And the detached cds-alert DOM in the memory is also increasing:
image

Affected components: which use @i8n, such as: alert, password...

Root Cause

protoOrDescriptor.__i18nSub = GlobalStateService.stateUpdates.subscribe(update => {

__i18nSub is on the protoOrDescriptor not the instance. Take alert as an example: all the alerts on the page will share the same __i18nSub, so if we remove all the alerts, only one __i18nSub(the newest one) will be unsubscribed. This causes the detached DOM to remain in memory.

There is also an issue that is caused by extends:
Assume that class A uses @i18n, and class B also uses @i18n while extending class A. In this case, an instance of class A will have two subscriptions when connectedCallback, but __i18nSub only saves the latest one. Therefore, only the latest subscription will be unsubscribed when disconnectedCallback.

So I added an if condition:

if (!this.__i18nSub) {

If we always use i18n as the name @i18n() i18n, it's okay, or do we need to keep these two subscriptions and unsubscribe from both of them when disconnectedCallback?

Issue Number: #67

What is the new behavior?

Unsubscribe from its subscription when the element is removed

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

@github-actions
Copy link

github-actions bot commented Jun 23, 2025

👋 @Bowen7,

  • 🙏 The Clarity team thanks you for opening a pull request
  • ⏳ The build for this PR has started
  • 📫 I'll update this comment when the build has finished

Thank you,

🤖 Clarity Release Bot

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant