Merge branch 'main' into svelte-custom-renderer

pull/18505/head
Paolo Ricciuti 2 months ago committed by GitHub
commit f915aa39cf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: properly track effect end node for async sibling component

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: prevent false-positive reactivity loss warning

@ -0,0 +1,5 @@
---
'svelte': patch
---
chore: bump esrap dependency

@ -188,7 +188,7 @@
"clsx": "^2.1.1",
"devalue": "^5.8.1",
"esm-env": "^1.2.1",
"esrap": "^2.2.9",
"esrap": "^2.2.11",
"is-reference": "^3.0.3",
"locate-character": "^3.0.0",
"magic-string": "^0.30.11",

@ -9,6 +9,7 @@ import {
set_hydrating,
skip_nodes
} from '../hydration.js';
import { assign_nodes } from '../template.js';
/**
* @param {TemplateNode} node
@ -23,6 +24,7 @@ export function async(node, blockers = [], expressions = [], fn) {
if (was_hydrating) {
hydrate_next();
end = skip_nodes(false);
assign_nodes(node, end); // Necessary if this wraps the sole child of a block, else end marker can be wrong
}
if (expressions.length === 0 && blockers.every((b) => b.settled)) {

@ -185,10 +185,10 @@ export async function save(promise) {
* @returns {Promise<() => T>}
*/
export async function track_reactivity_loss(promise) {
var previous_async_effect = reactivity_loss_tracker;
var previous_reactivity_loss_tracker = reactivity_loss_tracker;
// Ensure that unrelated reads after an async operation is kicked off don't cause false positives
queueMicrotask(() => {
if (reactivity_loss_tracker === previous_async_effect) {
if (reactivity_loss_tracker === previous_reactivity_loss_tracker) {
set_reactivity_loss_tracker(null);
}
});
@ -196,12 +196,12 @@ export async function track_reactivity_loss(promise) {
var value = await promise;
return () => {
set_reactivity_loss_tracker(previous_async_effect);
set_reactivity_loss_tracker(previous_reactivity_loss_tracker);
// While this can result in false negatives it also guards against the more important
// false positives that would occur if this is the last in a chain of async operations,
// and the reactivity_loss_tracker would then stay around until the next async operation happens.
queueMicrotask(() => {
if (reactivity_loss_tracker === previous_async_effect) {
if (reactivity_loss_tracker === previous_reactivity_loss_tracker) {
set_reactivity_loss_tracker(null);
}
});

@ -51,6 +51,7 @@ import {
batch_values,
current_batch,
flushSync,
previous_batch,
schedule_effect
} from './reactivity/batch.js';
import { handle_error } from './error-handling.js';
@ -586,6 +587,11 @@ export function get(signal) {
if (
!untracking &&
reactivity_loss_tracker &&
// By checking that current/previous batch are null we filter out false positives.
// reactivity_loss_tracker is only reset after a microtask, so if a flush happens
// before that, we get warnings for things we shouldn't warn on.
current_batch === null &&
previous_batch === null &&
!reactivity_loss_tracker.warned &&
(reactivity_loss_tracker.effect.f & REACTION_IS_UPDATING) === 0 &&
!reactivity_loss_tracker.effect_deps.has(signal)

@ -72,7 +72,7 @@ const { test, run } = suite<HydrationTest>(async (config, cwd) => {
const target = window.document.body;
const head = window.document.head;
const rendered = render((await import(`${cwd}/_output/server/main.svelte.js`)).default, {
const rendered = await render((await import(`${cwd}/_output/server/main.svelte.js`)).default, {
props: config.server_props ?? config.props ?? {},
idPrefix: config?.id_prefix
});
@ -80,8 +80,8 @@ const { test, run } = suite<HydrationTest>(async (config, cwd) => {
const override = read(`${cwd}/_override.html`);
const override_head = read(`${cwd}/_override_head.html`);
fs.writeFileSync(`${cwd}/_output/body.html`, rendered.html + '\n');
target.innerHTML = override ?? rendered.html;
fs.writeFileSync(`${cwd}/_output/body.html`, rendered.body + '\n');
target.innerHTML = override ?? rendered.body;
if (rendered.head) {
fs.writeFileSync(`${cwd}/_output/head.html`, rendered.head + '\n');
@ -145,7 +145,7 @@ const { test, run } = suite<HydrationTest>(async (config, cwd) => {
flushSync();
const expected = read(`${cwd}/_expected.html`) ?? rendered.html;
const expected = read(`${cwd}/_expected.html`) ?? rendered.body;
assert_html_equal(target.innerHTML, expected);
if (rendered.head) {

@ -0,0 +1,15 @@
import { tick } from 'svelte';
import { test } from '../../test';
export default test({
compileOptions: { dev: true },
async test({ assert, target, warnings }) {
await tick();
const [increment] = target.querySelectorAll('button');
increment.click();
await new Promise((resolve) => setTimeout(resolve, 10));
assert.htmlEqual(target.innerHTML, '<button>increment</button> 1 1');
assert.deepEqual(warnings, []);
}
});

@ -0,0 +1,16 @@
<script>
let x = $state(0);
let y = $state(0);
</script>
<button
onclick={() => {
x++;
queueMicrotask(() => queueMicrotask(() => y++));
}}
>
increment
</button>
{await x}
{y}

@ -0,0 +1,7 @@
<script>
import Header from './Header.svelte';
import Footer from './Footer.svelte';
</script>
<Header />
<Footer />

@ -0,0 +1,38 @@
import { tick } from 'svelte';
import { test } from '../../test';
export default test({
async test({ assert, target }) {
await tick();
const [toggle] = target.querySelectorAll('button');
assert.htmlEqual(
target.innerHTML,
`
<button>toggle</button>
<header>header</header>
<footer>footer</footer>
`
);
toggle.click();
await tick();
assert.htmlEqual(
target.innerHTML,
`
<button>toggle</button>
`
);
toggle.click();
await tick();
assert.htmlEqual(
target.innerHTML,
`
<button>toggle</button>
<header>header</header>
<footer>footer</footer>
`
);
}
});

@ -0,0 +1,11 @@
<script>
import Child from './Child.svelte';
let show = $state(true);
</script>
<button onclick={() => (show = !show)}>toggle</button>
{#if show}
<Child gate={await Promise.resolve(true)} />
{/if}

@ -102,8 +102,8 @@ importers:
specifier: ^1.2.1
version: 1.2.1
esrap:
specifier: ^2.2.9
version: 2.2.9(@typescript-eslint/types@8.59.4)
specifier: ^2.2.11
version: 2.2.11(@typescript-eslint/types@8.59.4)
is-reference:
specifier: ^3.0.3
version: 3.0.3
@ -1412,8 +1412,8 @@ packages:
resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==}
engines: {node: '>=0.10'}
esrap@2.2.9:
resolution: {integrity: sha512-4KijP+NxCWthMCUC3qHbE6n4vCjqgJS1uAYKhuT/GWfFTf1Qyive2TgOjep+gzbSzRfnNyaN/UU9YmdOt8Eg0A==}
esrap@2.2.11:
resolution: {integrity: sha512-gPdx+I+BjYEinNMQaBXFjbaJVyoPMU4ZODg5mE+M4DqVG9VusAVHHjcBX+zqyITlI0DIARwDMMzZwAWj36dRoQ==}
peerDependencies:
'@typescript-eslint/types': ^8.2.0
peerDependenciesMeta:
@ -3683,9 +3683,9 @@ snapshots:
dependencies:
estraverse: 5.3.0
esrap@2.2.9(@typescript-eslint/types@8.59.4):
esrap@2.2.11(@typescript-eslint/types@8.59.4):
dependencies:
'@jridgewell/sourcemap-codec': 1.5.0
'@jridgewell/sourcemap-codec': 1.5.5
optionalDependencies:
'@typescript-eslint/types': 8.59.4

Loading…
Cancel
Save