Rich Harris 2 days ago committed by GitHub
commit 77c112e19f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: reinstate reactivity loss tracking

@ -19,10 +19,10 @@ import {
import { Batch, current_batch } from './batch.js';
import {
async_derived,
current_async_effect,
reactivity_loss_tracker,
derived,
derived_safe_equal,
set_from_async_derived
set_reactivity_loss_tracker
} from './deriveds.js';
import { aborted } from './effects.js';
@ -120,7 +120,7 @@ export function capture() {
if (activate_batch) previous_batch?.activate();
if (DEV) {
set_from_async_derived(null);
set_reactivity_loss_tracker(null);
set_dev_stack(previous_dev_stack);
}
};
@ -152,11 +152,11 @@ export async function save(promise) {
* @returns {Promise<() => T>}
*/
export async function track_reactivity_loss(promise) {
var previous_async_effect = current_async_effect;
var previous_async_effect = reactivity_loss_tracker;
var value = await promise;
return () => {
set_from_async_derived(previous_async_effect);
set_reactivity_loss_tracker(previous_async_effect);
return value;
};
}
@ -213,7 +213,7 @@ export function unset_context(deactivate_batch = true) {
if (deactivate_batch) current_batch?.deactivate();
if (DEV) {
set_from_async_derived(null);
set_reactivity_loss_tracker(null);
set_dev_stack(null);
}
}

@ -36,7 +36,6 @@ import {
import { eager_effects, internal_set, set_eager_effects, source } from './sources.js';
import { get_error } from '../../shared/dev.js';
import { async_mode_flag, tracing_mode_flag } from '../../flags/index.js';
import { Boundary } from '../dom/blocks/boundary.js';
import { component_context } from '../context.js';
import { UNINITIALIZED } from '../../../constants.js';
import { batch_values, current_batch } from './batch.js';
@ -44,12 +43,16 @@ import { increment_pending, unset_context } from './async.js';
import { deferred, includes, noop } from '../../shared/utils.js';
import { set_signal_status, update_derived_status } from './status.js';
/** @type {Effect | null} */
export let current_async_effect = null;
/**
* This allows us to track 'reactivity loss' that occurs when signals
* are read after a non-context-restoring `await`. Dev-only
* @type {{ effect: Effect, warned: boolean } | null}
*/
export let reactivity_loss_tracker = null;
/** @param {Effect | null} v */
export function set_from_async_derived(v) {
current_async_effect = v;
/** @param {{ effect: Effect, warned: boolean } | null} v */
export function set_reactivity_loss_tracker(v) {
reactivity_loss_tracker = v;
}
export const recent_async_deriveds = new Set();
@ -123,7 +126,12 @@ export function async_derived(fn, label, location) {
var deferreds = new Map();
async_effect(() => {
if (DEV) current_async_effect = active_effect;
if (DEV) {
reactivity_loss_tracker = {
effect: /** @type {Effect} */ (active_effect),
warned: false
};
}
/** @type {ReturnType<typeof deferred<V>>} */
var d = deferred();
@ -139,7 +147,9 @@ export function async_derived(fn, label, location) {
unset_context();
}
if (DEV) current_async_effect = null;
if (DEV) {
reactivity_loss_tracker = null;
}
var batch = /** @type {Batch} */ (current_batch);
@ -156,7 +166,9 @@ export function async_derived(fn, label, location) {
* @param {unknown} error
*/
const handler = (value, error = undefined) => {
current_async_effect = null;
if (DEV) {
reactivity_loss_tracker = null;
}
batch.activate();

@ -27,7 +27,7 @@ import {
} from './constants.js';
import { old_values } from './reactivity/sources.js';
import {
destroy_derived_effects,
reactivity_loss_tracker,
execute_derived,
freeze_derived_effects,
recent_async_deriveds,
@ -58,6 +58,7 @@ import { UNINITIALIZED } from '../../constants.js';
import { captured_signals } from './legacy.js';
import { without_reactive_context } from './dom/elements/bindings/shared.js';
import { set_signal_status, update_derived_status } from './reactivity/status.js';
import * as w from './warnings.js';
let is_updating_effect = false;
@ -568,19 +569,20 @@ export function get(signal) {
}
if (DEV) {
// TODO reinstate this, but make it actually work
// if (current_async_effect) {
// var tracking = (current_async_effect.f & REACTION_IS_UPDATING) !== 0;
// var was_read = current_async_effect.deps?.includes(signal);
if (
!untracking &&
reactivity_loss_tracker &&
!reactivity_loss_tracker.warned &&
(reactivity_loss_tracker.effect.f & REACTION_IS_UPDATING) === 0
) {
reactivity_loss_tracker.warned = true;
// if (!tracking && !untracking && !was_read) {
// w.await_reactivity_loss(/** @type {string} */ (signal.label));
w.await_reactivity_loss(/** @type {string} */ (signal.label));
// var trace = get_error('traced at');
// // eslint-disable-next-line no-console
// if (trace) console.warn(trace);
// }
// }
var trace = get_error('traced at');
// eslint-disable-next-line no-console
if (trace) console.warn(trace);
}
recent_async_deriveds.delete(signal);
@ -595,7 +597,7 @@ export function get(signal) {
if (signal.trace) {
signal.trace();
} else {
var trace = get_error('traced at');
trace = get_error('traced at');
if (trace) {
var entry = tracing_expressions.entries.get(signal);

@ -1,10 +1,8 @@
import { tick } from 'svelte';
import { test } from '../../test';
import { normalise_trace_logs } from '../../../helpers.js';
export default test({
// TODO reinstate
skip: true,
compileOptions: {
dev: true
},
@ -15,13 +13,10 @@ export default test({
await tick();
assert.htmlEqual(target.innerHTML, '<button>a</button><button>b</button><h1>3</h1>');
assert.equal(
warnings[0],
'Detected reactivity loss when reading `values[1]`. This happens when state is read in an async function after an earlier `await`'
);
assert.equal(warnings[1].name, 'traced at');
assert.equal(warnings.length, 2);
assert.deepEqual(normalise_trace_logs(warnings), [
{
log: 'Detected reactivity loss when reading `values.length`. This happens when state is read in an async function after an earlier `await`'
}
]);
}
});

@ -2,9 +2,6 @@ import { tick } from 'svelte';
import { test } from '../../test';
export default test({
// TODO reinstate this
skip: true,
compileOptions: {
dev: true
},

Loading…
Cancel
Save