fix: {#await await ...} and async dependencies fixes#18243
Conversation
Investigating reports of unresponsive reactivity in non-async-mode. No clear culprit yet but found that `#merge` can be called wrongfully. Part of the reason for that is that we are unsetting the current batch prior to invoking the `{#await ...}` promise. This can result in writes going into a different batch while traversal is happening, which can cause weird downstream effects.
No test because not sure what to test here what can go wrong specifically, but it certainly _feels_ wrong.
Also added a few test labels which helped when debugging.
🦋 Changeset detectedLatest commit: 1952dd2 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 |
|
| ); | ||
|
|
||
| if (node.metadata.expression.has_blockers()) { | ||
| if (node.metadata.expression.has_blockers() || node.metadata.expression.has_await) { |
There was a problem hiding this comment.
is this change necessary? AFAICT it just results in unnecessary $.async(...) wrappers in the {#await await ...} case
There was a problem hiding this comment.
Just checked again - it is necessary, if you e.g. have two consecutive awaits it fails with a hydration error:
{#await await 1 then result}{result}{/await}
{#await await 1 then result}{result}{/await}There was a problem hiding this comment.
any idea how we can add a regression test for this? i tried just now but it's curiously difficult to assert that a hydration mismatch occurs, unless i'm doing something daft
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.55.9 ### Patch Changes - fix: don't unset batch when calling `{#await ...}` promise ([#18243](#18243)) - fix: promise-ify `{#await await ...}` expressions on the server and correctly hydrate them on the client ([#18243](#18243)) - fix: deduplicate dependencies that are added outside the init/update cycle ([#18243](#18243)) - fix: avoid false-positive batch invariant error ([#18246](#18246)) - fix: inline primitive constants in attribute values during SSR ([#18232](#18232)) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This started out as an investigation to get rid of the runtime code for
{#await ...}that deactivated a batch prior to reading the promise function. That can result in a new batch being created if the promise invocation happens to write a source.Through that I discovered two other bugs:
{#await await ...}was flawed around SSR/hydration: On the server it would await the expression (which it should not;{#await await ...}is kind of a weird special case here) and during hydration it did not produce matching nodes, leading to hydration fails.remove_reactionlater runs. Conside this: You havedeps = [count, unrelated, count]. Now you doremove_reactions(deps, 1), i.e. "remove all reactions after the first one". That means the "disconnect these from each other" logic runs forcount, too, because it's also in the third position, but that is wrong because it is also in the first position, i.e. the connection should be kept.