Skip to content

perf: optimize compiler analysis phase#17823

Merged
Rich-Harris merged 2 commits intosveltejs:mainfrom
MathiasWP:perf/compiler-analysis-optimizations
Feb 27, 2026
Merged

perf: optimize compiler analysis phase#17823
Rich-Harris merged 2 commits intosveltejs:mainfrom
MathiasWP:perf/compiler-analysis-optimizations

Conversation

@MathiasWP
Copy link
Copy Markdown
Contributor

Summary

Two optimizations to the compiler's analysis phase:

  • Cache ignore_stack snapshots instead of structuredClone on every node. The universal _ visitor in the analysis walk runs on every AST node and calls structuredClone(ignore_stack) each time. In practice, svelte-ignore comments are rare (0–5 per component), so 99%+ of nodes deep-clone an unchanged stack. This adds a copy-on-write cache that only re-creates the snapshot when push_ignore/pop_ignore actually change the stack.

  • Walk the CSS stylesheet once instead of once per element. prune() was called in a loop for each element, each time doing a full walk() of the stylesheet AST. This restructures the loop so the stylesheet is walked once, and the element iteration happens inside the ComplexSelector visitor.

Benchmarks

Compiled each component 500 times (after 50 warmup iterations), measuring average time per compile() call:

Component Before After Speedup
has (80+ CSS selectors, 12 elements) 3.405 ms 2.680 ms 21% faster
siblings-combinator-each-nested (65 CSS rules, 15 elements) 2.034 ms 1.575 ms 23% faster
synthetic (100 CSS rules, 50 elements) 10.099 ms 4.564 ms 55% faster

The CSS pruning optimization scales with elements × CSS rules — the more elements a component has, the bigger the win since we go from N stylesheet walks down to 1. The structuredClone fix helps every component regardless of CSS, eliminating ~500–2000 deep clones per compile (one per AST node) and replacing them with 0–5 (one per svelte-ignore comment).

For typical real-world components with 10–20 elements and some CSS, expect roughly 20–30% faster compilation in the analysis phase.

Test plan

  • Full test suite passes (7329 tests, 0 failures)
  • CSS pruning tests pass (selector matching, scoping, unused rule detection)
  • svelte-ignore behavior unchanged (snapshot is consumed read-only via .has()/.some())

🤖 Generated with Claude Code

Cache ignore_stack snapshots to avoid structuredClone on every AST node,
and restructure CSS pruning to walk the stylesheet once instead of once
per element.

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

changeset-bot bot commented Feb 27, 2026

🦋 Changeset detected

Latest commit: 41dbcc2

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

Optimize the compiler analysis phase for better performance.
Copy link
Copy Markdown
Member

@Rich-Harris Rich-Harris left a comment

Choose a reason for hiding this comment

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

fantastic!

@Rich-Harris Rich-Harris merged commit 1043f79 into sveltejs:main Feb 27, 2026
17 of 18 checks passed
@github-actions github-actions bot mentioned this pull request Feb 27, 2026
Rich-Harris pushed a commit that referenced this pull request Feb 27, 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.6

### Patch Changes

- perf: optimize parser hot paths for faster compilation
([#17811](#17811))

- fix: `SvelteMap` incorrectly handles keys with `undefined` values
([#17826](#17826))

- fix: SvelteURL `search` setter now returns the normalized value,
matching native URL behavior
([#17828](#17828))

- fix: visit synthetic value node during ssr
([#17824](#17824))

- fix: always case insensitive event handlers during ssr
([#17822](#17822))

- chore: more efficient effect scheduling
([#17808](#17808))

- perf: optimize compiler analysis phase
([#17823](#17823))

- fix: skip redundant batch.apply
([#17816](#17816))

- chore: null out current_batch before committing branches
([#17809](#17809))

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