fix: restore hydration state after `await` in `<script>` (#16806)

* WIP fix more hydration stuff

* fix

* tidy up

* changeset

* fix

* fix
pull/16807/head
Rich Harris 2 days ago committed by GitHub
parent ded13b825d
commit 0e75498c21
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: restore hydration state after `await` in `<script>`

@ -40,11 +40,7 @@ import { TitleElement } from './visitors/TitleElement.js';
import { UpdateExpression } from './visitors/UpdateExpression.js'; import { UpdateExpression } from './visitors/UpdateExpression.js';
import { VariableDeclaration } from './visitors/VariableDeclaration.js'; import { VariableDeclaration } from './visitors/VariableDeclaration.js';
import { SvelteBoundary } from './visitors/SvelteBoundary.js'; import { SvelteBoundary } from './visitors/SvelteBoundary.js';
import { import { call_component_renderer, create_async_block } from './visitors/shared/utils.js';
create_child_block,
call_component_renderer,
create_async_block
} from './visitors/shared/utils.js';
/** @type {Visitors} */ /** @type {Visitors} */
const global_visitors = { const global_visitors = {
@ -248,7 +244,7 @@ export function server_component(analysis, options) {
]); ]);
if (analysis.instance.has_await) { if (analysis.instance.has_await) {
component_block = b.block([create_child_block(component_block, true)]); component_block = b.block([create_async_block(component_block)]);
} }
// trick esrap into including comments // trick esrap into including comments

@ -20,6 +20,14 @@ import {
set_from_async_derived set_from_async_derived
} from './deriveds.js'; } from './deriveds.js';
import { aborted } from './effects.js'; import { aborted } from './effects.js';
import {
hydrate_next,
hydrate_node,
hydrating,
set_hydrate_node,
set_hydrating,
skip_nodes
} from '../dom/hydration.js';
/** /**
* *
@ -40,6 +48,8 @@ export function flatten(sync, async, fn) {
var restore = capture(); var restore = capture();
var was_hydrating = hydrating;
Promise.all(async.map((expression) => async_derived(expression))) Promise.all(async.map((expression) => async_derived(expression)))
.then((result) => { .then((result) => {
batch?.activate(); batch?.activate();
@ -55,6 +65,10 @@ export function flatten(sync, async, fn) {
} }
} }
if (was_hydrating) {
set_hydrating(false);
}
batch?.deactivate(); batch?.deactivate();
unset_context(); unset_context();
}) })
@ -74,12 +88,23 @@ function capture() {
var previous_component_context = component_context; var previous_component_context = component_context;
var previous_batch = current_batch; var previous_batch = current_batch;
var was_hydrating = hydrating;
if (was_hydrating) {
var previous_hydrate_node = hydrate_node;
}
return function restore() { return function restore() {
set_active_effect(previous_effect); set_active_effect(previous_effect);
set_active_reaction(previous_reaction); set_active_reaction(previous_reaction);
set_component_context(previous_component_context); set_component_context(previous_component_context);
previous_batch?.activate(); previous_batch?.activate();
if (was_hydrating) {
set_hydrating(true);
set_hydrate_node(previous_hydrate_node);
}
if (DEV) { if (DEV) {
set_from_async_derived(null); set_from_async_derived(null);
} }
@ -186,13 +211,34 @@ export async function async_body(fn) {
var active = /** @type {Effect} */ (active_effect); var active = /** @type {Effect} */ (active_effect);
var was_hydrating = hydrating;
var next_hydrate_node = undefined;
if (was_hydrating) {
hydrate_next();
next_hydrate_node = skip_nodes(false);
}
try { try {
await fn(); var promise = fn();
} finally {
if (next_hydrate_node) {
set_hydrate_node(next_hydrate_node);
hydrate_next();
}
}
try {
await promise;
} catch (error) { } catch (error) {
if (!aborted(active)) { if (!aborted(active)) {
invoke_error_boundary(error, active); invoke_error_boundary(error, active);
} }
} finally { } finally {
if (was_hydrating) {
set_hydrating(false);
}
boundary.update_pending_count(-1); boundary.update_pending_count(-1);
if (pending) { if (pending) {

@ -0,0 +1,13 @@
import { tick } from 'svelte';
import { test } from '../../test';
export default test({
skip_mode: ['server'],
ssrHtml: '<p>hello</p>',
async test({ assert, target }) {
await tick();
assert.htmlEqual(target.innerHTML, '<p>hello</p>');
}
});

@ -0,0 +1,9 @@
<script>
import Child from './Child.svelte';
</script>
<Child />
{#if true}
<p>hello</p>
{/if}

@ -0,0 +1,13 @@
import { tick } from 'svelte';
import { test } from '../../test';
export default test({
skip_mode: ['server'],
ssrHtml: '<p>hello</p>',
async test({ assert, target }) {
await tick();
assert.htmlEqual(target.innerHTML, '<p>hello</p>');
}
});

@ -0,0 +1,7 @@
<script lang="ts">
await 1;
</script>
{#if true}
<p>hello</p>
{/if}
Loading…
Cancel
Save