Skip to content

Commit 0e75498

Browse files
authored
fix: restore hydration state after await in <script> (#16806)
* WIP fix more hydration stuff * fix * tidy up * changeset * fix * fix
1 parent ded13b8 commit 0e75498

File tree

8 files changed

+99
-7
lines changed

8 files changed

+99
-7
lines changed

.changeset/sweet-doors-brush.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+
fix: restore hydration state after `await` in `<script>`

packages/svelte/src/compiler/phases/3-transform/server/transform-server.js

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,7 @@ import { TitleElement } from './visitors/TitleElement.js';
4040
import { UpdateExpression } from './visitors/UpdateExpression.js';
4141
import { VariableDeclaration } from './visitors/VariableDeclaration.js';
4242
import { SvelteBoundary } from './visitors/SvelteBoundary.js';
43-
import {
44-
create_child_block,
45-
call_component_renderer,
46-
create_async_block
47-
} from './visitors/shared/utils.js';
43+
import { call_component_renderer, create_async_block } from './visitors/shared/utils.js';
4844

4945
/** @type {Visitors} */
5046
const global_visitors = {
@@ -248,7 +244,7 @@ export function server_component(analysis, options) {
248244
]);
249245

250246
if (analysis.instance.has_await) {
251-
component_block = b.block([create_child_block(component_block, true)]);
247+
component_block = b.block([create_async_block(component_block)]);
252248
}
253249

254250
// trick esrap into including comments

packages/svelte/src/internal/client/reactivity/async.js

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ import {
2020
set_from_async_derived
2121
} from './deriveds.js';
2222
import { aborted } from './effects.js';
23+
import {
24+
hydrate_next,
25+
hydrate_node,
26+
hydrating,
27+
set_hydrate_node,
28+
set_hydrating,
29+
skip_nodes
30+
} from '../dom/hydration.js';
2331

2432
/**
2533
*
@@ -40,6 +48,8 @@ export function flatten(sync, async, fn) {
4048

4149
var restore = capture();
4250

51+
var was_hydrating = hydrating;
52+
4353
Promise.all(async.map((expression) => async_derived(expression)))
4454
.then((result) => {
4555
batch?.activate();
@@ -55,6 +65,10 @@ export function flatten(sync, async, fn) {
5565
}
5666
}
5767

68+
if (was_hydrating) {
69+
set_hydrating(false);
70+
}
71+
5872
batch?.deactivate();
5973
unset_context();
6074
})
@@ -74,12 +88,23 @@ function capture() {
7488
var previous_component_context = component_context;
7589
var previous_batch = current_batch;
7690

91+
var was_hydrating = hydrating;
92+
93+
if (was_hydrating) {
94+
var previous_hydrate_node = hydrate_node;
95+
}
96+
7797
return function restore() {
7898
set_active_effect(previous_effect);
7999
set_active_reaction(previous_reaction);
80100
set_component_context(previous_component_context);
81101
previous_batch?.activate();
82102

103+
if (was_hydrating) {
104+
set_hydrating(true);
105+
set_hydrate_node(previous_hydrate_node);
106+
}
107+
83108
if (DEV) {
84109
set_from_async_derived(null);
85110
}
@@ -186,13 +211,34 @@ export async function async_body(fn) {
186211

187212
var active = /** @type {Effect} */ (active_effect);
188213

214+
var was_hydrating = hydrating;
215+
var next_hydrate_node = undefined;
216+
217+
if (was_hydrating) {
218+
hydrate_next();
219+
next_hydrate_node = skip_nodes(false);
220+
}
221+
189222
try {
190-
await fn();
223+
var promise = fn();
224+
} finally {
225+
if (next_hydrate_node) {
226+
set_hydrate_node(next_hydrate_node);
227+
hydrate_next();
228+
}
229+
}
230+
231+
try {
232+
await promise;
191233
} catch (error) {
192234
if (!aborted(active)) {
193235
invoke_error_boundary(error, active);
194236
}
195237
} finally {
238+
if (was_hydrating) {
239+
set_hydrating(false);
240+
}
241+
196242
boundary.update_pending_count(-1);
197243

198244
if (pending) {
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<script lang="ts">
2+
await 1;
3+
</script>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { tick } from 'svelte';
2+
import { test } from '../../test';
3+
4+
export default test({
5+
skip_mode: ['server'],
6+
7+
ssrHtml: '<p>hello</p>',
8+
9+
async test({ assert, target }) {
10+
await tick();
11+
assert.htmlEqual(target.innerHTML, '<p>hello</p>');
12+
}
13+
});
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<script>
2+
import Child from './Child.svelte';
3+
</script>
4+
5+
<Child />
6+
7+
{#if true}
8+
<p>hello</p>
9+
{/if}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { tick } from 'svelte';
2+
import { test } from '../../test';
3+
4+
export default test({
5+
skip_mode: ['server'],
6+
7+
ssrHtml: '<p>hello</p>',
8+
9+
async test({ assert, target }) {
10+
await tick();
11+
assert.htmlEqual(target.innerHTML, '<p>hello</p>');
12+
}
13+
});
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<script lang="ts">
2+
await 1;
3+
</script>
4+
5+
{#if true}
6+
<p>hello</p>
7+
{/if}

0 commit comments

Comments
 (0)