Repository navigation
Append inserted rules to the buckets instead of rebuilding - #3470
Conversation
173168d to
63d67a2
Compare
CSSStyleSheet.insertRule marked every sheet dirty, so the next visibility query re-parsed every stylesheet. A style rule appended at or after the sheet that emitted the last rule is last in cascade order: it now joins the buckets with the next document order and only stamps the memo, and an append that sets none of the tracked properties changes nothing at all. Inserts in the middle, into an earlier sheet, or of at-rules still take the rebuild path. Unlayered rules carry UNLAYERED_RANK from creation, so an appended rule packs exactly what a rebuild would. Materializing a <style> sheet's cssRules no longer counts as a change, since the text and rule paths now fold declarations the same way (!important included).
63d67a2 to
90bf686
Compare
|
It's a good chance, but it needs to be rebased, and, in particular, it conflicts with the --* custom property support. |
main added custom property (`--*`) tracking to the same rule-building code this branch made appendable. Both paths now share addSelectorRules, which registers the custom declarations of a rule and its visibility rules, and reports whether it added anything tracked. An insertRule append therefore reaches custom_rules too, and clears the lazily parsed selectors of a property it joins, instead of being dropped when the rule sets no visibility property. The raw-text path folds a block once for both kinds of declaration, so a rebuild does not tokenize every block twice. rule_layers lives in the rule arena so an appended rule can register its layer; the layered ranks are still stamped by finalizeLayerRanks.
|
Merged main in. You were right: the fast path only looked at visibility properties, so a rule with only Both paths now go through the same Added a case to |
Based on #3467 (independent of #3468 / #3469).
CSSStyleSheet.insertRulecalledsheetModified, so the next visibility query re-parsed every stylesheet in the document: every selector re-tokenized, every@mediaquery re-evaluated, every layer re-ranked. CSS-in-JS libraries insert rules one at a time, and a component that reads layout right after mounting pays a full rebuild per rule.StyleManager.ruleInsertednow appends directly when the rule is a style rule appended at or after the sheet that emitted the last visibility rule (last_rule_sheet, tracked by the rebuild and by appends). That is the invariant the fast path needs, "no rule with a higher document order exists", rather than list position, so a trailing<style>holding only keyframes or@font-facedoes not force rebuilds on the sheet before it. The appended rule packs the next document order and, being unlayered,UNLAYERED_RANK; unlayered rules now carry that rank from creation on the rebuild path too, so an append is byte-for-byte what a rebuild would produce andstampRuleListonly touches layered rules. An append that sets none ofdisplay/visibility/opacity/pointer-events(most CSS-in-JS rules) changes nothing and does not even stamp the memo. Everything else still rebuilds: an insert in the middle, an insert into an earlier sheet, an at-rule, or an insert while a rebuild is already pending.Two things this cleaned up on the way:
addRawRule(the<style>text path) folded declarations with a plain overwrite, so.x { display: none !important; display: block }read asblockuntilcssRuleswas touched and the CSSOM path took over. It now shares the!important-aware fold the inline scan already used, and materializing a<style>sheet'scssRulesno longer counts as a sheet change since both paths agree.addVisibilityRulereplaces the three copies of the per-selector loop;bucketusesgetOrPutValue;Selector.rightmost()is shared with the selector matcher.Tests: a unit test asserts the append path leaves
dirtyclear and agrees with the rebuild path on ordering, and that middle inserts and at-rules rebuild; fixture scripts check specificity ordering across appends, appends to an earlier sheet, an unlayered append outranking a layered rule, and the!importanttext case survivingcssRulesmaterialization.Numbers (ReleaseFast, static theverge fixture): a loop of 200 ×
insertRuleeach followed bycheckVisibility()goes from 3.0 ms to 0.5 ms, median of 3.