Skip to content

Commit 20b8797

Browse files
trueadmRich-Harris
andauthored
breaking: avoid flushing queued updates on mount/hydrate (#12587)
* breaking: avoid flushing queued updates on mount/hydrat * Fix tests * Update packages/svelte/src/internal/client/render.js Co-authored-by: Rich Harris <[email protected]> * tweak * tweak --------- Co-authored-by: Rich Harris <[email protected]>
1 parent 6037b96 commit 20b8797

File tree

7 files changed

+40
-35
lines changed

7 files changed

+40
-35
lines changed

.changeset/slow-gorillas-yawn.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
breaking: avoid flushing queued updates on mount/hydrate

packages/svelte/src/internal/client/render.js

Lines changed: 24 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,7 @@ export function set_text(text, value) {
7979
*/
8080
export function mount(component, options) {
8181
const anchor = options.anchor ?? options.target.appendChild(empty());
82-
// Don't flush previous effects to ensure order of outer effects stays consistent
83-
return flush_sync(() => _mount(component, { ...options, anchor }), false);
82+
return _mount(component, { ...options, anchor });
8483
}
8584

8685
/**
@@ -113,40 +112,35 @@ export function hydrate(component, options) {
113112
const previous_hydrate_node = hydrate_node;
114113

115114
try {
116-
// Don't flush previous effects to ensure order of outer effects stays consistent
117-
return flush_sync(() => {
118-
var anchor = /** @type {import('#client').TemplateNode} */ (target.firstChild);
119-
while (
120-
anchor &&
121-
(anchor.nodeType !== 8 || /** @type {Comment} */ (anchor).data !== HYDRATION_START)
122-
) {
123-
anchor = /** @type {import('#client').TemplateNode} */ (anchor.nextSibling);
124-
}
115+
var anchor = /** @type {import('#client').TemplateNode} */ (target.firstChild);
116+
while (
117+
anchor &&
118+
(anchor.nodeType !== 8 || /** @type {Comment} */ (anchor).data !== HYDRATION_START)
119+
) {
120+
anchor = /** @type {import('#client').TemplateNode} */ (anchor.nextSibling);
121+
}
125122

126-
if (!anchor) {
127-
throw HYDRATION_ERROR;
128-
}
123+
if (!anchor) {
124+
throw HYDRATION_ERROR;
125+
}
129126

130-
set_hydrating(true);
131-
set_hydrate_node(/** @type {Comment} */ (anchor));
132-
hydrate_next();
127+
set_hydrating(true);
128+
set_hydrate_node(/** @type {Comment} */ (anchor));
129+
hydrate_next();
133130

134-
const instance = _mount(component, { ...options, anchor });
131+
const instance = _mount(component, { ...options, anchor });
135132

136-
if (
137-
hydrate_node.nodeType !== 8 ||
138-
/** @type {Comment} */ (hydrate_node).data !== HYDRATION_END
139-
) {
140-
w.hydration_mismatch();
141-
throw HYDRATION_ERROR;
142-
}
133+
if (
134+
hydrate_node.nodeType !== 8 ||
135+
/** @type {Comment} */ (hydrate_node).data !== HYDRATION_END
136+
) {
137+
w.hydration_mismatch();
138+
throw HYDRATION_ERROR;
139+
}
143140

144-
// flush_sync will run this callback and then synchronously run any pending effects,
145-
// which don't belong to the hydration phase anymore - therefore reset it here
146-
set_hydrating(false);
141+
set_hydrating(false);
147142

148-
return instance;
149-
}, false);
143+
return /** @type {Exports} */ (instance);
150144
} catch (error) {
151145
if (error === HYDRATION_ERROR) {
152146
// TODO it's possible for event listeners to have been added and

packages/svelte/src/internal/client/runtime.js

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -670,10 +670,9 @@ function process_effects(effect, collected_effects) {
670670
* Internal version of `flushSync` with the option to not flush previous effects.
671671
* Returns the result of the passed function, if given.
672672
* @param {() => any} [fn]
673-
* @param {boolean} [flush_previous]
674673
* @returns {any}
675674
*/
676-
export function flush_sync(fn, flush_previous = true) {
675+
export function flush_sync(fn) {
677676
var previous_scheduler_mode = current_scheduler_mode;
678677
var previous_queued_root_effects = current_queued_root_effects;
679678

@@ -687,9 +686,7 @@ export function flush_sync(fn, flush_previous = true) {
687686
current_queued_root_effects = root_effects;
688687
is_micro_task_queued = false;
689688

690-
if (flush_previous) {
691-
flush_queued_root_effects(previous_queued_root_effects);
692-
}
689+
flush_queued_root_effects(previous_queued_root_effects);
693690

694691
var result = fn?.();
695692

packages/svelte/tests/hydration/test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { suite, assert_ok, type BaseTest } from '../suite.js';
88
import { createClassComponent } from 'svelte/legacy';
99
import { render } from 'svelte/server';
1010
import type { CompileOptions } from '#compiler';
11+
import { flushSync } from 'svelte';
1112

1213
interface HydrationTest extends BaseTest {
1314
load_compiled?: boolean;
@@ -114,6 +115,7 @@ const { test, run } = suite<HydrationTest>(async (config, cwd) => {
114115

115116
if (!override) {
116117
const expected = read(`${cwd}/_expected.html`) ?? rendered.html;
118+
flushSync();
117119
assert.equal(target.innerHTML.trim(), expected.trim());
118120
}
119121

packages/svelte/tests/runtime-browser/driver.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import config from '__CONFIG__';
55
// @ts-expect-error
66
import * as assert from 'assert.js';
77
import { createClassComponent } from 'svelte/legacy';
8+
import { flushSync } from 'svelte';
89

910
/** @param {HTMLElement} target */
1011
export default async function (target) {
@@ -45,6 +46,8 @@ export default async function (target) {
4546
} while (new Date().getTime() <= start + ms);
4647
};
4748

49+
flushSync();
50+
4851
if (config.html) {
4952
assert.htmlEqual(target.innerHTML, config.html);
5053
}

packages/svelte/tests/runtime-runes/samples/hydrate-modified-input-group/_config.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { flushSync } from 'svelte';
12
import { test } from '../../test';
23

34
export default test({
@@ -9,6 +10,7 @@ export default test({
910
inputs[1].dispatchEvent(new window.Event('change'));
1011
// Hydration shouldn't reset the value to 1
1112
hydrate();
13+
flushSync();
1214

1315
assert.htmlEqual(
1416
target.innerHTML,

packages/svelte/tests/runtime-runes/samples/hydrate-modified-input/_config.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { flushSync } from 'svelte';
12
import { test } from '../../test';
23

34
export default test({
@@ -9,6 +10,7 @@ export default test({
910
input.dispatchEvent(new window.Event('input'));
1011
// Hydration shouldn't reset the value to empty
1112
hydrate();
13+
flushSync();
1214

1315
assert.htmlEqual(target.innerHTML, '<input type="text">\nfoo');
1416
}

0 commit comments

Comments
 (0)