-
Notifications
You must be signed in to change notification settings - Fork 814
fix(utils): single global stylesheet instance for performance #6320
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
fix(utils): single global stylesheet instance for performance #6320
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great patch 👌 LGTM
src/utils/shadow-root.ts
Outdated
* This singleton avoids the performance and memory hit of | ||
* creating a new CSSStyleSheet every time a shadow root is created. | ||
*/ | ||
export const globalStyleSheet = createStyleSheetIfNeededAndSupported(globalStyles); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like the way the runtime is bundled doesn't allow to initiate it at the root level? Maybe we can do something like:
let globalStyleSheet
export function createShadowRoot(this: HTMLElement, cmpMeta: d.ComponentRuntimeMeta) {
const shadowRoot = BUILD.shadowDelegatesFocus
? this.attachShadow({
mode: 'open',
delegatesFocus: !!(cmpMeta.$flags$ & CMP_FLAGS.shadowDelegatesFocus),
})
: this.attachShadow({ mode: 'open' });
/**
* If constructable stylesheets are supported, we can use them to
* add the global styles to the shadow root.
*/
if (supportsConstructableStylesheets) {
const sheet = new CSSStyleSheet();
sheet.replaceSync(globalStyles);
shadowRoot.adoptedStyleSheets.push(sheet);
}
if (!globalStyleSheet) {
globalStyleSheet = createStyleSheetIfNeededAndSupported(globalStyles)
shadowRoot.adoptedStyleSheets.push(globalStyleSheet)
};
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting! I wonder why it worked in Voyager but not the test environment. I just added lazy initialization. Although, if it's possible rejigger the build to avoid that error in the first place, that would probably be a cleaner solution than the lazy initializer.
Lmk what you think!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 👍
What is the current behavior?
GitHub Issue Number: None
Since Ionic v8.6.0 I've been experiencing component instance creation performance issues, especially in virtual lists, where it can take items longer to appear. This was originally identified by end users: https://vger.social/post/20787019
I narrowed it down to the stencil upgrade here.
From there I found the regression occurring in Stencil v4.33.0 specifically. When I reverted 33363d4077728793e0c6f635a22dccbb5740be49 the problem went away.
Once I identified the source of the issue, I found some suspicious code that was creating a new
CSSStyleSheet
every time a new component instance is created.What is interesting is this performance issue exists even if
globalStyles
is empty. Simply creating a newCSSStyleSheets
and callingreplaceSync
on an empty string every instantiation is enough to hurt performance.What is the new behavior?
I have modified the code to only create one global
CSSStyleSheet
(if necessary) on startup that is appended toadoptedStyleSheets
in thecreateShadowRoot
function.This solves performance issues of using
globalStyles
. In addition, I added an early return to not create the global style sheet at all, ifglobalStyles
is empty. This doesn't seem to affect perf, just makes the DX a bit nicer by not having a useless/emptyCSSStyleSheet
in theadoptedStyleSheets
array.Documentation
Does this introduce a breaking change?
Testing
I tested these changes against Voyager by building stencil, building ionic, and finally installing in Voyager.
Other information