fix: prevent onoutroend from firing twice when compilerOptions.hmr is true (#18655)

Fixes #18440

`hmr()` in `packages/svelte/src/internal/client/dev/hmr.js` wrapped a
component in a `block` effect containing a `branch` effect. It forwarded
the inner effect's `nodes` object to the outer block:

This shared the same reference, meaning `outer_block.nodes ===
inner_branch.nodes`. When `pause_children` collected transitions for
unmounting, Each collected transition had `out(check)` called multiple times,
starting multiple animations and firing `outroend` multiple times.

Fix by only copying `start`/`end` (the DOM range info the outer block needs)
without sharing the transitions array:
pull/18680/merge
Siddhesh Kabra 3 weeks ago committed by GitHub
parent a7ba9e85aa
commit faf1e103c5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: prevent onoutroend from firing twice when compilerOptions.hmr is true

@ -57,10 +57,21 @@ export function hmr(fn) {
if (ran) set_should_intro(true);
});
// Forward the nodes from the inner effect to the outer active effect which would
// get them if the HMR wrapper wasn't there. Do this inside the block not outside
// so that HMR updates to the component will also update the nodes on the active effect.
/** @type {Effect} */ (active_effect).nodes = effect.nodes;
// Forward the start/end DOM nodes from the inner effect to the outer active effect
// which would get them if the HMR wrapper wasn't there. Do this inside the block not
// outside so that HMR updates to the component will also update the nodes on the
// active effect. We copy only start/end, not the full nodes object, so that
// pause_children does not collect transitions from both effects and fire outroend twice.
var inner_nodes = effect.nodes;
if (inner_nodes) {
var ae = /** @type {Effect} */ (active_effect);
if (ae.nodes) {
ae.nodes.start = inner_nodes.start;
ae.nodes.end = inner_nodes.end;
} else {
ae.nodes = { start: inner_nodes.start, end: inner_nodes.end, a: null, t: null };
}
}
}, EFFECT_TRANSPARENT);
ran = true;

Loading…
Cancel
Save