fix: reset effects inside skipped branches#17581
Merged
Rich-Harris merged 40 commits intomainfrom Jan 29, 2026
Merged
Conversation
🦋 Changeset detectedLatest commit: 2e52a4c The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
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 |
Contributor
|
6 tasks
elliott-with-the-longest-name-on-github
approved these changes
Jan 28, 2026
Merged
dummdidumm
added a commit
that referenced
this pull request
Feb 2, 2026
When a branch is speculatively marked for destruction (condition temporarily falsy), its child effects are reset to `CLEAN` to prevent them running in a doomed branch (as of #17581). However, if the branch survives (condition becomes truthy again), those effects remain `CLEAN` and never run - the source was already marked dirty before the reset, so no new dirty marking occurs. The fix is to change `skipped_effects` from a `Set` to a `Map` that tracks which child effects were dirty/maybe_dirty before being reset. When a branch is unskipped (survives), restore their status and reschedule them.
Rich-Harris
added a commit
that referenced
this pull request
Feb 4, 2026
* fix: reschedule effects inside unskipped branches When a branch is speculatively marked for destruction (condition temporarily falsy), its child effects are reset to `CLEAN` to prevent them running in a doomed branch (as of #17581). However, if the branch survives (condition becomes truthy again), those effects remain `CLEAN` and never run - the source was already marked dirty before the reset, so no new dirty marking occurs. The fix is to change `skipped_effects` from a `Set` to a `Map` that tracks which child effects were dirty/maybe_dirty before being reset. When a branch is unskipped (survives), restore their status and reschedule them. * update comment * lint * make skipped_effects private * actually while we're at it let's use a more descriptive name * prettier --------- Co-authored-by: Rich Harris <rich.harris@vercel.com>
dummdidumm
added a commit
that referenced
this pull request
Feb 4, 2026
fixes #17595 When an if/key/etc block has an expression that depends on an async blocker (e.g., is inside a component with top level `await`), the compiler incorrectly treats the expression as async - even when the expression itself contains no `await`. This causes the expression to be added to `$.async`'s `expressions` array, which wraps it in an `async_derived`. This is not only unnecessary but also buggy: it breaks the direct reactive connection between the source and its dependent effects, causing inconsistent effect executions. The fix is to only add expressions to `$.async`'s `expressions` array when they actually contain an `await`. When a branch is speculatively marked for destruction (condition temporarily falsy), its child effects are reset to `CLEAN` to prevent them running in a doomed branch (as of #17581). However, if the branch survives (condition becomes truthy again), those effects remain `CLEAN` and never run - the source was already marked dirty before the reset, so no new dirty marking occurs. The fix is to change `skipped_effects` from a `Set` to a `Map` that tracks which child effects were dirty/maybe_dirty before being reset. When a branch is unskipped (survives), restore their status and reschedule them. --------- Co-authored-by: Rich Harris <rich.harris@vercel.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Alternative to #17335. When traversing, we skip any branches that will be destroyed when the batch commits, so that we don't (for example) try to evaluate
object.propertywhenobjectisundefinedwithin a batch:{#if object} {object.property} {/if}Because of this, however, it's possible for dirty effects inside skipped branches to be left dirty. If they are later rescheduled,
schedule_effectwill bail out if it hits an already-dirty branch, which can prevent state changes from having an effect. This is made more obvious by forks, but doesn't require them.This PR fixes it, by traversing skipped branches when a batch is deferred.
Closes #17197.
Before submitting the PR, please make sure you do the following
feat:,fix:,chore:, ordocs:.packages/svelte/src, add a changeset (npx changeset).Tests and linting
pnpm testand lint the project withpnpm lint