Skip to content

Commit 964004a

Browse files
committed
preserve context
1 parent b788ec0 commit 964004a

File tree

5 files changed

+65
-32
lines changed

5 files changed

+65
-32
lines changed

packages/svelte/src/compiler/phases/3-transform/client/visitors/AwaitExpression.js

+9-4
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,15 @@ import * as b from '../../../../utils/builders.js';
77
* @param {ComponentContext} context
88
*/
99
export function AwaitExpression(node, context) {
10-
return b.await(
11-
b.call(
12-
'$.preserve_context',
13-
node.argument && /** @type {Expression} */ (context.visit(node.argument))
10+
return b.call(
11+
b.member(
12+
b.await(
13+
b.call(
14+
'$.preserve_context',
15+
node.argument && /** @type {Expression} */ (context.visit(node.argument))
16+
)
17+
),
18+
'read'
1419
)
1520
);
1621
}

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

+2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ export const INSPECT_EFFECT = 1 << 18;
2121
export const HEAD_EFFECT = 1 << 19;
2222
export const EFFECT_HAS_DERIVED = 1 << 20;
2323

24+
export const REACTION_IS_UPDATING = 1 << 21;
25+
2426
export const STATE_SYMBOL = Symbol('$state');
2527
export const STATE_SYMBOL_METADATA = Symbol('$state metadata');
2628
export const LEGACY_PROPS = Symbol('legacy props');

packages/svelte/src/internal/client/dom/blocks/boundary.js

+15-14
Original file line numberDiff line numberDiff line change
@@ -261,26 +261,27 @@ export function create_suspense() {
261261
/**
262262
* @template T
263263
* @param {Promise<T>} promise
264-
* @returns {Promise<T>}
264+
* @returns {Promise<{ read: () => T }>}
265265
*/
266266
export async function preserve_context(promise) {
267-
if (!active_effect) {
268-
return promise;
269-
}
270-
271267
var previous_effect = active_effect;
272268
var previous_reaction = active_reaction;
273269
var previous_component_context = component_context;
274270

275271
const [suspend, unsuspend] = create_suspense();
276272

277-
try {
278-
suspend();
279-
return await promise;
280-
} finally {
281-
set_active_effect(previous_effect);
282-
set_active_reaction(previous_reaction);
283-
set_component_context(previous_component_context);
284-
unsuspend();
285-
}
273+
suspend();
274+
275+
const value = await promise;
276+
277+
return {
278+
read() {
279+
set_active_effect(previous_effect);
280+
set_active_reaction(previous_reaction);
281+
set_component_context(previous_component_context);
282+
283+
unsuspend();
284+
return value;
285+
}
286+
};
286287
}

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

+38-13
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ import {
2525
ROOT_EFFECT,
2626
LEGACY_DERIVED_PROP,
2727
DISCONNECTED,
28-
BOUNDARY_EFFECT
28+
BOUNDARY_EFFECT,
29+
REACTION_IS_UPDATING
2930
} from './constants.js';
3031
import { flush_tasks } from './dom/task.js';
3132
import { add_owner } from './dev/ownership.js';
@@ -435,6 +436,7 @@ export function update_reaction(reaction) {
435436
read_version++;
436437

437438
try {
439+
reaction.f |= REACTION_IS_UPDATING;
438440
var result = /** @type {Function} */ (0, reaction.fn)();
439441
var deps = reaction.deps;
440442

@@ -488,6 +490,7 @@ export function update_reaction(reaction) {
488490

489491
return result;
490492
} finally {
493+
reaction.f ^= REACTION_IS_UPDATING;
491494
new_deps = previous_deps;
492495
skipped_deps = previous_skipped_deps;
493496
untracked_writes = previous_untracked_writes;
@@ -776,7 +779,7 @@ export function schedule_effect(signal) {
776779
var flags = effect.f;
777780

778781
if ((flags & (ROOT_EFFECT | BRANCH_EFFECT)) !== 0) {
779-
if ((flags & CLEAN) === 0) return
782+
if ((flags & CLEAN) === 0) return;
780783
effect.f ^= CLEAN;
781784
}
782785
}
@@ -938,18 +941,40 @@ export function get(signal) {
938941
if (derived_sources !== null && derived_sources.includes(signal)) {
939942
e.state_unsafe_local_read();
940943
}
944+
941945
var deps = active_reaction.deps;
942-
if (signal.rv < read_version) {
943-
signal.rv = read_version;
944-
// If the signal is accessing the same dependencies in the same
945-
// order as it did last time, increment `skipped_deps`
946-
// rather than updating `new_deps`, which creates GC cost
947-
if (new_deps === null && deps !== null && deps[skipped_deps] === signal) {
948-
skipped_deps++;
949-
} else if (new_deps === null) {
950-
new_deps = [signal];
951-
} else {
952-
new_deps.push(signal);
946+
947+
if ((active_reaction.f & REACTION_IS_UPDATING) !== 0) {
948+
// we're in the effect init/update cycle
949+
if (signal.rv < read_version) {
950+
signal.rv = read_version;
951+
952+
// If the signal is accessing the same dependencies in the same
953+
// order as it did last time, increment `skipped_deps`
954+
// rather than updating `new_deps`, which creates GC cost
955+
if (new_deps === null && deps !== null && deps[skipped_deps] === signal) {
956+
skipped_deps++;
957+
} else if (new_deps === null) {
958+
new_deps = [signal];
959+
} else {
960+
new_deps.push(signal);
961+
}
962+
}
963+
} else {
964+
// we're adding a dependency outside the init/update cycle
965+
// (i.e. after an `await`)
966+
// TODO we probably want to disable this for user effects,
967+
// otherwise it's a breaking change, albeit a desirable one?
968+
if (deps === null) {
969+
deps = [signal];
970+
} else if (!deps.includes(signal)) {
971+
deps.push(signal);
972+
}
973+
974+
if (signal.reactions === null) {
975+
signal.reactions = [active_reaction];
976+
} else if (!signal.reactions.includes(active_reaction)) {
977+
signal.reactions.push(active_reaction);
953978
}
954979
}
955980
} else if (is_derived && /** @type {Derived} */ (signal).deps === null) {

playgrounds/sandbox/vite.config.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export default defineConfig({
1111
inspect(),
1212
svelte({
1313
compilerOptions: {
14-
hmr: true
14+
hmr: false
1515
}
1616
})
1717
],

0 commit comments

Comments
 (0)