Skip to content

perf: optimize CSS selector pruning#17846

Merged
Rich-Harris merged 3 commits into
sveltejs:mainfrom
MathiasWP:perf-css-prune-optimizations
Mar 3, 2026
Merged

perf: optimize CSS selector pruning#17846
Rich-Harris merged 3 commits into
sveltejs:mainfrom
MathiasWP:perf-css-prune-optimizations

Conversation

@MathiasWP

@MathiasWP MathiasWP commented Mar 3, 2026

Copy link
Copy Markdown
Contributor

Summary

Reduces CSS selector pruning overhead by eliminating unnecessary allocations and redundant work in the hot path.

Changes:

  • Replace .slice() + .shift()/.pop() in apply_selector with index-based from/to params — avoids O(n) array copies per recursive call
  • Merge has_selectors/other_selectors split in relative_selector_might_apply_to_node into a single pass — eliminates 2 temporary array allocations per call
  • Hoist name.toLowerCase() out of the inner loop in attribute_matches
  • Replace value.split(/\s/).includes() with indexOf + boundary checks in test_attribute for ~= — avoids array allocation on every class match
  • Skip name.replace() regex when selector name has no backslash

Benchmark

Interleaved benchmark (5 rounds, alternating baseline/optimized):

--- Round 1 ---
  Baseline:  min=59.58ms  median=64.63ms
  Optimized: min=47.20ms  median=54.35ms
--- Round 2 ---
  Baseline:  min=59.11ms  median=64.90ms
  Optimized: min=48.36ms  median=54.74ms
--- Round 3 ---
  Baseline:  min=58.38ms  median=64.06ms
  Optimized: min=48.38ms  median=53.83ms
--- Round 4 ---
  Baseline:  min=58.49ms  median=63.99ms
  Optimized: min=48.45ms  median=53.82ms
--- Round 5 ---
  Baseline:  min=58.40ms  median=64.07ms
  Optimized: min=48.97ms  median=54.64ms

Best min:    Before=58.38ms  After=47.20ms  Improvement=19.1%
Best median: Before=63.99ms  After=53.82ms  Improvement=15.9%

CPU profile before → after:

Function Before After
relative_selector_might_apply_to_node 14.3% 5.2%
attribute_matches 4.0% 3.3%
test_attribute 3.2% <0.9%

Test plan

  • All 196 CSS tests pass (180 samples + 16 parse)
  • All 31 snapshot tests pass
  • All 2380 runtime-runes tests pass
  • All 3291 runtime-legacy tests pass
  • All 145 compiler-errors tests pass
  • All 326 validator tests pass
  • Added css-prune-edge-cases test covering: ~= word matching (substring vs whole word), deep combinator chains (4+ levels), :has() combined with class selectors, escaped selectors, :is()/:where()/:not() with combinators
  • Edge case test passes on both baseline and optimized code

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Mar 3, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 96ebbc7

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
svelte Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

@Rich-Harris Rich-Harris left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

thank you

@Rich-Harris Rich-Harris merged commit 0965028 into sveltejs:main Mar 3, 2026
17 of 18 checks passed
@github-actions github-actions Bot mentioned this pull request Mar 3, 2026
Rich-Harris pushed a commit that referenced this pull request Mar 3, 2026
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## svelte@5.53.7

### Patch Changes

- fix: correctly add \_\_svelte_meta after else-if chains
([#17830](#17830))

- perf: cache element interactivity and source line splitting in
compiler ([#17839](#17839))

- chore: avoid rescheduling effects during branch commit
([#17837](#17837))

- perf: optimize CSS selector pruning
([#17846](#17846))

- fix: preserve original boundary errors when keyed each rows are
removed during async updates
([#17843](#17843))

- perf: avoid O(n²) name scanning in scope `generate` and `unique`
([#17844](#17844))

- fix: preserve each items that are needed by pending batches
([#17819](#17819))

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
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

Successfully merging this pull request may close these issues.

2 participants