Skip to content
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

Performance issues (in Firefox) with Web Components #90

Open
sirisian opened this issue Oct 13, 2021 · 2 comments
Open

Performance issues (in Firefox) with Web Components #90

sirisian opened this issue Oct 13, 2021 · 2 comments

Comments

@sirisian
Copy link

Describe the bug
I'm using this with Webpack to load the CSS for my web components. I noticed on Firefox it inserts a style tag for each CSSStyleSheet that is loaded. I don't know if my idea below will make things faster, but if someone could test it, I'd appreciate it.

To Reproduce
Steps to reproduce the behavior:

Create a uicomponent.js and uicomponent.css. Fill the uicomponent.css with thousands of rules.

uicomponent.js

import uiComponentStyle from '!css-loader?exportType=css-style-sheet!./uicomponent.css' assert { type: "css" };

export default class UIComponent extends HTMLElement {
    constructor() {
        super();
        this.attachShadow({mode: 'open'});
        this.shadowRoot.adoptedStyleSheets = [sharedStyle, uiComponentStyle];
        // ...
    }
}
customElements.define('ui-component', UIComponent);

uicomponent.css

a { color: red; }
... thousands more rules

Insert 1000 instances of ui-component into the body. It seems to take a while to process the style tags.

Expected behavior
Create one blob per CSSStyleSheet and just @import it? I think that would skip any CSS parsing or whatever Firefox is doing when constructing the web components.

Example of using blob with @import https://jsfiddle.net/na5tz49r/

<div>hello</div>
const blob = new Blob(['div { color: red }'], { type: 'text/css' });
const url = window.URL.createObjectURL(blob);

const $style = document.createElement('style');
$style.innerText = `@import url(${url});`;
document.head.appendChild($style);

I don't know if Firefox will import the blob and reparse it for every ui-component load. I'm thinking it won't, but I could be wrong. I expect it'll be drastically faster.

Additional context
This isn't a huge issue for me right now. I tell people to use Chrome and everything is fine. I'm rewriting my own code to limit the size of styles in my web components. Still if this works it might speed things up with very little changes.

@Lodin
Copy link
Collaborator

Lodin commented Oct 14, 2021

Hi @sirisian. Thanks for the issue and a new idea.

I did a couple of tests and there are results:

Solution Firefox performance
Current ~4905ms
Blob ~3925ms

Test environment:

  • 1000 web components with the shadow dom enabled.
  • bootstrap.css as a content for the CSSStyleSheet.
  • Performance results is raw because I tested them using the performance snapshot. So the real speed is a bit better.

I think we could go with the Blob solution since it is quite simple to implement. However, it doesn't solve the main issue: each stylesheet is parsed individually, without caching. For 1000 elements there will be 1000 parsing operations (which takes the most of the time).

Here is a screenshot of the flamegraph for the test I did:
image

As you can see, there are a lot of JIT calls which are probably CSS parsing operations.

I run out of ideas. @calebdwilliams, do you have any thoughts?

@calebdwilliams
Copy link
Owner

I could be way off base, but I think this is just how Gecko works. I’d be curious if the results in Safari because I think they have Chrome’s style deduping mechanism there.

It’s been awhile since I’ve been in the weeds on this project (thanks @Lodin!), but I do have a few things I’d love to try out.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants