svelte 5.43.3 → 5.43.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/compiler/index.js +1 -1
- package/package.json +1 -1
- package/src/compiler/phases/2-analyze/visitors/BindDirective.js +13 -2
- package/src/compiler/phases/2-analyze/visitors/StyleDirective.js +4 -3
- package/src/compiler/phases/3-transform/client/visitors/BindDirective.js +6 -3
- package/src/compiler/phases/3-transform/client/visitors/RegularElement.js +2 -17
- package/src/compiler/phases/3-transform/client/visitors/shared/component.js +6 -3
- package/src/compiler/phases/3-transform/client/visitors/shared/element.js +3 -3
- package/src/compiler/phases/3-transform/client/visitors/shared/utils.js +13 -5
- package/src/compiler/phases/3-transform/server/visitors/shared/component.js +3 -0
- package/src/compiler/phases/3-transform/server/visitors/shared/element.js +2 -0
- package/src/compiler/phases/3-transform/server/visitors/shared/utils.js +12 -6
- package/src/compiler/phases/nodes.js +15 -0
- package/src/internal/client/constants.js +7 -2
- package/src/internal/client/dom/template.js +8 -2
- package/src/internal/client/index.js +2 -1
- package/src/internal/client/reactivity/async.js +8 -0
- package/src/internal/client/reactivity/deriveds.js +12 -11
- package/src/internal/client/reactivity/effects.js +7 -7
- package/src/internal/client/reactivity/sources.js +15 -6
- package/src/internal/client/runtime.js +44 -86
- package/src/internal/client/validate.js +27 -23
- package/src/version.js +1 -1
- package/types/index.d.ts.map +1 -1
package/package.json
CHANGED
|
@@ -159,6 +159,16 @@ export function BindDirective(node, context) {
|
|
|
159
159
|
|
|
160
160
|
mark_subtree_dynamic(context.path);
|
|
161
161
|
|
|
162
|
+
const [get, set] = node.expression.expressions;
|
|
163
|
+
// We gotta jump across the getter/setter functions to avoid the expression metadata field being reset to null
|
|
164
|
+
context.visit(get.type === 'ArrowFunctionExpression' ? get.body : get, {
|
|
165
|
+
...context.state,
|
|
166
|
+
expression: node.metadata.expression
|
|
167
|
+
});
|
|
168
|
+
context.visit(set.type === 'ArrowFunctionExpression' ? set.body : set, {
|
|
169
|
+
...context.state,
|
|
170
|
+
expression: node.metadata.expression
|
|
171
|
+
});
|
|
162
172
|
return;
|
|
163
173
|
}
|
|
164
174
|
|
|
@@ -247,7 +257,8 @@ export function BindDirective(node, context) {
|
|
|
247
257
|
|
|
248
258
|
node.metadata = {
|
|
249
259
|
binding_group_name: group_name,
|
|
250
|
-
parent_each_blocks: each_blocks
|
|
260
|
+
parent_each_blocks: each_blocks,
|
|
261
|
+
expression: node.metadata.expression
|
|
251
262
|
};
|
|
252
263
|
}
|
|
253
264
|
|
|
@@ -255,5 +266,5 @@ export function BindDirective(node, context) {
|
|
|
255
266
|
w.bind_invalid_each_rest(binding.node, binding.node.name);
|
|
256
267
|
}
|
|
257
268
|
|
|
258
|
-
context.next();
|
|
269
|
+
context.next({ ...context.state, expression: node.metadata.expression });
|
|
259
270
|
}
|
|
@@ -23,6 +23,9 @@ export function StyleDirective(node, context) {
|
|
|
23
23
|
if (binding.kind !== 'normal') {
|
|
24
24
|
node.metadata.expression.has_state = true;
|
|
25
25
|
}
|
|
26
|
+
if (binding.blocker) {
|
|
27
|
+
node.metadata.expression.dependencies.add(binding);
|
|
28
|
+
}
|
|
26
29
|
}
|
|
27
30
|
} else {
|
|
28
31
|
context.next();
|
|
@@ -30,9 +33,7 @@ export function StyleDirective(node, context) {
|
|
|
30
33
|
for (const chunk of get_attribute_chunks(node.value)) {
|
|
31
34
|
if (chunk.type !== 'ExpressionTag') continue;
|
|
32
35
|
|
|
33
|
-
node.metadata.expression.
|
|
34
|
-
node.metadata.expression.has_call ||= chunk.metadata.expression.has_call;
|
|
35
|
-
node.metadata.expression.has_await ||= chunk.metadata.expression.has_await;
|
|
36
|
+
node.metadata.expression.merge(chunk.metadata.expression);
|
|
36
37
|
}
|
|
37
38
|
}
|
|
38
39
|
}
|
|
@@ -250,10 +250,13 @@ export function BindDirective(node, context) {
|
|
|
250
250
|
|
|
251
251
|
let statement = defer ? b.stmt(b.call('$.effect', b.thunk(call))) : b.stmt(call);
|
|
252
252
|
|
|
253
|
-
|
|
254
|
-
if (node.metadata.binding?.blocker) {
|
|
253
|
+
if (node.metadata.expression.is_async()) {
|
|
255
254
|
statement = b.stmt(
|
|
256
|
-
b.call(
|
|
255
|
+
b.call(
|
|
256
|
+
'$.run_after_blockers',
|
|
257
|
+
node.metadata.expression.blockers(),
|
|
258
|
+
b.thunk(b.block([statement]))
|
|
259
|
+
)
|
|
257
260
|
);
|
|
258
261
|
}
|
|
259
262
|
|
|
@@ -484,21 +484,6 @@ function setup_select_synchronization(value_binding, context) {
|
|
|
484
484
|
);
|
|
485
485
|
}
|
|
486
486
|
|
|
487
|
-
/**
|
|
488
|
-
* @param {ExpressionMetadata} target
|
|
489
|
-
* @param {ExpressionMetadata} source
|
|
490
|
-
*/
|
|
491
|
-
function merge_metadata(target, source) {
|
|
492
|
-
target.has_assignment ||= source.has_assignment;
|
|
493
|
-
target.has_await ||= source.has_await;
|
|
494
|
-
target.has_call ||= source.has_call;
|
|
495
|
-
target.has_member_expression ||= source.has_member_expression;
|
|
496
|
-
target.has_state ||= source.has_state;
|
|
497
|
-
|
|
498
|
-
for (const r of source.references) target.references.add(r);
|
|
499
|
-
for (const b of source.dependencies) target.dependencies.add(b);
|
|
500
|
-
}
|
|
501
|
-
|
|
502
487
|
/**
|
|
503
488
|
* @param {AST.ClassDirective[]} class_directives
|
|
504
489
|
* @param {ComponentContext} context
|
|
@@ -514,7 +499,7 @@ export function build_class_directives_object(
|
|
|
514
499
|
const metadata = new ExpressionMetadata();
|
|
515
500
|
|
|
516
501
|
for (const d of class_directives) {
|
|
517
|
-
|
|
502
|
+
metadata.merge(d.metadata.expression);
|
|
518
503
|
|
|
519
504
|
const expression = /** @type Expression */ (context.visit(d.expression));
|
|
520
505
|
properties.push(b.init(d.name, expression));
|
|
@@ -541,7 +526,7 @@ export function build_style_directives_object(
|
|
|
541
526
|
const metadata = new ExpressionMetadata();
|
|
542
527
|
|
|
543
528
|
for (const d of style_directives) {
|
|
544
|
-
|
|
529
|
+
metadata.merge(d.metadata.expression);
|
|
545
530
|
|
|
546
531
|
const expression =
|
|
547
532
|
d.value === true
|
|
@@ -171,8 +171,6 @@ export function build_component(node, component_name, context) {
|
|
|
171
171
|
attribute.value,
|
|
172
172
|
context,
|
|
173
173
|
(value, metadata) => {
|
|
174
|
-
if (!metadata.has_state && !metadata.has_await) return value;
|
|
175
|
-
|
|
176
174
|
// When we have a non-simple computation, anything other than an Identifier or Member expression,
|
|
177
175
|
// then there's a good chance it needs to be memoized to avoid over-firing when read within the
|
|
178
176
|
// child component (e.g. `active={i === index}`)
|
|
@@ -198,7 +196,12 @@ export function build_component(node, component_name, context) {
|
|
|
198
196
|
push_prop(b.init(attribute.name, value));
|
|
199
197
|
}
|
|
200
198
|
} else if (attribute.type === 'BindDirective') {
|
|
201
|
-
const expression = /** @type {Expression} */ (
|
|
199
|
+
const expression = /** @type {Expression} */ (
|
|
200
|
+
context.visit(attribute.expression, { ...context.state, memoizer })
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
// Bindings are a bit special: we don't want to add them to (async) deriveds but we need to check if they have blockers
|
|
204
|
+
memoizer.check_blockers(attribute.metadata.expression);
|
|
202
205
|
|
|
203
206
|
if (
|
|
204
207
|
dev &&
|
|
@@ -122,7 +122,7 @@ export function build_attribute_value(value, context, memoize = (value) => value
|
|
|
122
122
|
|
|
123
123
|
return {
|
|
124
124
|
value: memoize(expression, chunk.metadata.expression),
|
|
125
|
-
has_state: chunk.metadata.expression.has_state || chunk.metadata.expression.
|
|
125
|
+
has_state: chunk.metadata.expression.has_state || chunk.metadata.expression.is_async()
|
|
126
126
|
};
|
|
127
127
|
}
|
|
128
128
|
|
|
@@ -170,7 +170,7 @@ export function build_set_class(element, node_id, attribute, class_directives, c
|
|
|
170
170
|
if (class_directives.length) {
|
|
171
171
|
next = build_class_directives_object(class_directives, context);
|
|
172
172
|
has_state ||= class_directives.some(
|
|
173
|
-
(d) => d.metadata.expression.has_state || d.metadata.expression.
|
|
173
|
+
(d) => d.metadata.expression.has_state || d.metadata.expression.is_async()
|
|
174
174
|
);
|
|
175
175
|
|
|
176
176
|
if (has_state) {
|
|
@@ -240,7 +240,7 @@ export function build_set_style(node_id, attribute, style_directives, context) {
|
|
|
240
240
|
if (style_directives.length) {
|
|
241
241
|
next = build_style_directives_object(style_directives, context);
|
|
242
242
|
has_state ||= style_directives.some(
|
|
243
|
-
(d) => d.metadata.expression.has_state || d.metadata.expression.
|
|
243
|
+
(d) => d.metadata.expression.has_state || d.metadata.expression.is_async()
|
|
244
244
|
);
|
|
245
245
|
|
|
246
246
|
if (has_state) {
|
|
@@ -31,11 +31,7 @@ export class Memoizer {
|
|
|
31
31
|
* @param {boolean} memoize_if_state
|
|
32
32
|
*/
|
|
33
33
|
add(expression, metadata, memoize_if_state = false) {
|
|
34
|
-
|
|
35
|
-
if (binding.blocker) {
|
|
36
|
-
this.#blockers.add(binding.blocker);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
34
|
+
this.check_blockers(metadata);
|
|
39
35
|
|
|
40
36
|
const should_memoize =
|
|
41
37
|
metadata.has_call || metadata.has_await || (memoize_if_state && metadata.has_state);
|
|
@@ -52,6 +48,17 @@ export class Memoizer {
|
|
|
52
48
|
return id;
|
|
53
49
|
}
|
|
54
50
|
|
|
51
|
+
/**
|
|
52
|
+
* @param {ExpressionMetadata} metadata
|
|
53
|
+
*/
|
|
54
|
+
check_blockers(metadata) {
|
|
55
|
+
for (const binding of metadata.dependencies) {
|
|
56
|
+
if (binding.blocker) {
|
|
57
|
+
this.#blockers.add(binding.blocker);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
55
62
|
apply() {
|
|
56
63
|
return [...this.#sync, ...this.#async].map((memo, i) => {
|
|
57
64
|
memo.id.name = `$${i}`;
|
|
@@ -348,6 +355,7 @@ export function validate_binding(state, binding, expression) {
|
|
|
348
355
|
b.call(
|
|
349
356
|
'$.validate_binding',
|
|
350
357
|
b.literal(state.analysis.source.slice(binding.start, binding.end)),
|
|
358
|
+
binding.metadata.expression.blockers(),
|
|
351
359
|
b.thunk(
|
|
352
360
|
state.store_to_invalidate ? b.sequence([b.call('$.mark_store_binding'), obj]) : obj
|
|
353
361
|
),
|
|
@@ -107,6 +107,9 @@ export function build_inline_component(node, expression, context) {
|
|
|
107
107
|
|
|
108
108
|
push_prop(b.prop('init', b.key(attribute.name), value));
|
|
109
109
|
} else if (attribute.type === 'BindDirective' && attribute.name !== 'this') {
|
|
110
|
+
// Bindings are a bit special: we don't want to add them to (async) deriveds but we need to check if they have blockers
|
|
111
|
+
optimiser.check_blockers(attribute.metadata.expression);
|
|
112
|
+
|
|
110
113
|
if (attribute.expression.type === 'SequenceExpression') {
|
|
111
114
|
const [get, set] = /** @type {SequenceExpression} */ (context.visit(attribute.expression))
|
|
112
115
|
.expressions;
|
|
@@ -121,6 +121,8 @@ export function build_element_attributes(node, context, transform) {
|
|
|
121
121
|
expression = b.call(expression.expressions[0]);
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
+
expression = transform(expression, attribute.metadata.expression);
|
|
125
|
+
|
|
124
126
|
if (is_content_editable_binding(attribute.name)) {
|
|
125
127
|
content = expression;
|
|
126
128
|
} else if (attribute.name === 'value' && node.name === 'textarea') {
|
|
@@ -347,16 +347,11 @@ export class PromiseOptimiser {
|
|
|
347
347
|
#blockers = new Set();
|
|
348
348
|
|
|
349
349
|
/**
|
|
350
|
-
*
|
|
351
350
|
* @param {Expression} expression
|
|
352
351
|
* @param {ExpressionMetadata} metadata
|
|
353
352
|
*/
|
|
354
353
|
transform = (expression, metadata) => {
|
|
355
|
-
|
|
356
|
-
if (binding.blocker) {
|
|
357
|
-
this.#blockers.add(binding.blocker);
|
|
358
|
-
}
|
|
359
|
-
}
|
|
354
|
+
this.check_blockers(metadata);
|
|
360
355
|
|
|
361
356
|
if (metadata.has_await) {
|
|
362
357
|
this.has_await = true;
|
|
@@ -368,6 +363,17 @@ export class PromiseOptimiser {
|
|
|
368
363
|
return expression;
|
|
369
364
|
};
|
|
370
365
|
|
|
366
|
+
/**
|
|
367
|
+
* @param {ExpressionMetadata} metadata
|
|
368
|
+
*/
|
|
369
|
+
check_blockers(metadata) {
|
|
370
|
+
for (const binding of metadata.dependencies) {
|
|
371
|
+
if (binding.blocker) {
|
|
372
|
+
this.#blockers.add(binding.blocker);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
371
377
|
apply() {
|
|
372
378
|
if (this.expressions.length === 0) {
|
|
373
379
|
return b.empty;
|
|
@@ -115,6 +115,21 @@ export class ExpressionMetadata {
|
|
|
115
115
|
is_async() {
|
|
116
116
|
return this.has_await || this.#get_blockers().size > 0;
|
|
117
117
|
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* @param {ExpressionMetadata} source
|
|
121
|
+
*/
|
|
122
|
+
merge(source) {
|
|
123
|
+
this.has_state ||= source.has_state;
|
|
124
|
+
this.has_call ||= source.has_call;
|
|
125
|
+
this.has_await ||= source.has_await;
|
|
126
|
+
this.has_member_expression ||= source.has_member_expression;
|
|
127
|
+
this.has_assignment ||= source.has_assignment;
|
|
128
|
+
this.#blockers = null; // so that blockers are recalculated
|
|
129
|
+
|
|
130
|
+
for (const r of source.references) this.references.add(r);
|
|
131
|
+
for (const b of source.dependencies) this.dependencies.add(b);
|
|
132
|
+
}
|
|
118
133
|
}
|
|
119
134
|
|
|
120
135
|
/**
|
|
@@ -6,6 +6,13 @@ export const BLOCK_EFFECT = 1 << 4;
|
|
|
6
6
|
export const BRANCH_EFFECT = 1 << 5;
|
|
7
7
|
export const ROOT_EFFECT = 1 << 6;
|
|
8
8
|
export const BOUNDARY_EFFECT = 1 << 7;
|
|
9
|
+
/**
|
|
10
|
+
* Indicates that a reaction is connected to an effect root — either it is an effect,
|
|
11
|
+
* or it is a derived that is depended on by at least one effect. If a derived has
|
|
12
|
+
* no dependents, we can disconnect it from the graph, allowing it to either be
|
|
13
|
+
* GC'd or reconnected later if an effect comes to depend on it again
|
|
14
|
+
*/
|
|
15
|
+
export const CONNECTED = 1 << 9;
|
|
9
16
|
export const CLEAN = 1 << 10;
|
|
10
17
|
export const DIRTY = 1 << 11;
|
|
11
18
|
export const MAYBE_DIRTY = 1 << 12;
|
|
@@ -26,8 +33,6 @@ export const EFFECT_PRESERVED = 1 << 19;
|
|
|
26
33
|
export const USER_EFFECT = 1 << 20;
|
|
27
34
|
|
|
28
35
|
// Flags exclusive to deriveds
|
|
29
|
-
export const UNOWNED = 1 << 8;
|
|
30
|
-
export const DISCONNECTED = 1 << 9;
|
|
31
36
|
/**
|
|
32
37
|
* Tells that we marked this derived and its reactions as visited during the "mark as (maybe) dirty"-phase.
|
|
33
38
|
* Will be lifted during execution of the derived and during checking its dirty state (both are necessary
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
TEMPLATE_USE_MATHML,
|
|
21
21
|
TEMPLATE_USE_SVG
|
|
22
22
|
} from '../../../constants.js';
|
|
23
|
-
import { COMMENT_NODE, DOCUMENT_FRAGMENT_NODE, TEXT_NODE } from '#client/constants';
|
|
23
|
+
import { COMMENT_NODE, DOCUMENT_FRAGMENT_NODE, EFFECT_RAN, TEXT_NODE } from '#client/constants';
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
26
|
* @param {TemplateNode} start
|
|
@@ -344,7 +344,13 @@ export function comment() {
|
|
|
344
344
|
*/
|
|
345
345
|
export function append(anchor, dom) {
|
|
346
346
|
if (hydrating) {
|
|
347
|
-
/** @type {Effect} */ (active_effect)
|
|
347
|
+
var effect = /** @type {Effect} */ (active_effect);
|
|
348
|
+
// When hydrating and outer component and an inner component is async, i.e. blocked on a promise,
|
|
349
|
+
// then by the time the inner resolves we have already advanced to the end of the hydrated nodes
|
|
350
|
+
// of the parent component. Check for defined for that reason to avoid rewinding the parent's end marker.
|
|
351
|
+
if ((effect.f & EFFECT_RAN) === 0 || effect.nodes_end === null) {
|
|
352
|
+
effect.nodes_end = hydrate_node;
|
|
353
|
+
}
|
|
348
354
|
hydrate_next();
|
|
349
355
|
return;
|
|
350
356
|
}
|
|
@@ -102,7 +102,8 @@ export {
|
|
|
102
102
|
for_await_track_reactivity_loss,
|
|
103
103
|
run,
|
|
104
104
|
save,
|
|
105
|
-
track_reactivity_loss
|
|
105
|
+
track_reactivity_loss,
|
|
106
|
+
run_after_blockers
|
|
106
107
|
} from './reactivity/async.js';
|
|
107
108
|
export { eager, flushSync as flush } from './reactivity/batch.js';
|
|
108
109
|
export {
|
|
@@ -84,6 +84,14 @@ export function flatten(blockers, sync, async, fn) {
|
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
+
/**
|
|
88
|
+
* @param {Array<Promise<void>>} blockers
|
|
89
|
+
* @param {(values: Value[]) => any} fn
|
|
90
|
+
*/
|
|
91
|
+
export function run_after_blockers(blockers, fn) {
|
|
92
|
+
flatten(blockers, [], [], fn);
|
|
93
|
+
}
|
|
94
|
+
|
|
87
95
|
/**
|
|
88
96
|
* Captures the current effect context so that we can restore it after
|
|
89
97
|
* some asynchronous work has happened (so that e.g. `await a + b`
|
|
@@ -9,15 +9,14 @@ import {
|
|
|
9
9
|
EFFECT_PRESERVED,
|
|
10
10
|
MAYBE_DIRTY,
|
|
11
11
|
STALE_REACTION,
|
|
12
|
-
UNOWNED,
|
|
13
12
|
ASYNC,
|
|
14
|
-
WAS_MARKED
|
|
13
|
+
WAS_MARKED,
|
|
14
|
+
CONNECTED
|
|
15
15
|
} from '#client/constants';
|
|
16
16
|
import {
|
|
17
17
|
active_reaction,
|
|
18
18
|
active_effect,
|
|
19
19
|
set_signal_status,
|
|
20
|
-
skip_reaction,
|
|
21
20
|
update_reaction,
|
|
22
21
|
increment_write_version,
|
|
23
22
|
set_active_effect,
|
|
@@ -27,7 +26,7 @@ import {
|
|
|
27
26
|
import { equals, safe_equals } from './equality.js';
|
|
28
27
|
import * as e from '../errors.js';
|
|
29
28
|
import * as w from '../warnings.js';
|
|
30
|
-
import { async_effect, destroy_effect, teardown } from './effects.js';
|
|
29
|
+
import { async_effect, destroy_effect, effect_tracking, teardown } from './effects.js';
|
|
31
30
|
import { eager_effects, internal_set, set_eager_effects, source } from './sources.js';
|
|
32
31
|
import { get_stack } from '../dev/tracing.js';
|
|
33
32
|
import { async_mode_flag, tracing_mode_flag } from '../../flags/index.js';
|
|
@@ -61,9 +60,7 @@ export function derived(fn) {
|
|
|
61
60
|
? /** @type {Derived} */ (active_reaction)
|
|
62
61
|
: null;
|
|
63
62
|
|
|
64
|
-
if (active_effect
|
|
65
|
-
flags |= UNOWNED;
|
|
66
|
-
} else {
|
|
63
|
+
if (active_effect !== null) {
|
|
67
64
|
// Since deriveds are evaluated lazily, any effects created inside them are
|
|
68
65
|
// created too late to ensure that the parent effect is added to the tree
|
|
69
66
|
active_effect.f |= EFFECT_PRESERVED;
|
|
@@ -368,12 +365,16 @@ export function update_derived(derived) {
|
|
|
368
365
|
return;
|
|
369
366
|
}
|
|
370
367
|
|
|
368
|
+
// During time traveling we don't want to reset the status so that
|
|
369
|
+
// traversal of the graph in the other batches still happens
|
|
371
370
|
if (batch_values !== null) {
|
|
372
|
-
|
|
371
|
+
// only cache the value if we're in a tracking context, otherwise we won't
|
|
372
|
+
// clear the cache in `mark_reactions` when dependencies are updated
|
|
373
|
+
if (effect_tracking()) {
|
|
374
|
+
batch_values.set(derived, derived.v);
|
|
375
|
+
}
|
|
373
376
|
} else {
|
|
374
|
-
var status =
|
|
375
|
-
(skip_reaction || (derived.f & UNOWNED) !== 0) && derived.deps !== null ? MAYBE_DIRTY : CLEAN;
|
|
376
|
-
|
|
377
|
+
var status = (derived.f & CONNECTED) === 0 ? MAYBE_DIRTY : CLEAN;
|
|
377
378
|
set_signal_status(derived, status);
|
|
378
379
|
}
|
|
379
380
|
}
|
|
@@ -25,7 +25,6 @@ import {
|
|
|
25
25
|
ROOT_EFFECT,
|
|
26
26
|
EFFECT_TRANSPARENT,
|
|
27
27
|
DERIVED,
|
|
28
|
-
UNOWNED,
|
|
29
28
|
CLEAN,
|
|
30
29
|
EAGER_EFFECT,
|
|
31
30
|
HEAD_EFFECT,
|
|
@@ -33,7 +32,8 @@ import {
|
|
|
33
32
|
EFFECT_PRESERVED,
|
|
34
33
|
STALE_REACTION,
|
|
35
34
|
USER_EFFECT,
|
|
36
|
-
ASYNC
|
|
35
|
+
ASYNC,
|
|
36
|
+
CONNECTED
|
|
37
37
|
} from '#client/constants';
|
|
38
38
|
import * as e from '../errors.js';
|
|
39
39
|
import { DEV } from 'esm-env';
|
|
@@ -48,11 +48,11 @@ import { without_reactive_context } from '../dom/elements/bindings/shared.js';
|
|
|
48
48
|
* @param {'$effect' | '$effect.pre' | '$inspect'} rune
|
|
49
49
|
*/
|
|
50
50
|
export function validate_effect(rune) {
|
|
51
|
-
if (active_effect === null
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
if (active_effect === null) {
|
|
52
|
+
if (active_reaction === null) {
|
|
53
|
+
e.effect_orphan(rune);
|
|
54
|
+
}
|
|
54
55
|
|
|
55
|
-
if (active_reaction !== null && (active_reaction.f & UNOWNED) !== 0 && active_effect === null) {
|
|
56
56
|
e.effect_in_unowned_derived();
|
|
57
57
|
}
|
|
58
58
|
|
|
@@ -103,7 +103,7 @@ function create_effect(type, fn, sync, push = true) {
|
|
|
103
103
|
deps: null,
|
|
104
104
|
nodes_start: null,
|
|
105
105
|
nodes_end: null,
|
|
106
|
-
f: type | DIRTY,
|
|
106
|
+
f: type | DIRTY | CONNECTED,
|
|
107
107
|
first: null,
|
|
108
108
|
fn,
|
|
109
109
|
last: null,
|
|
@@ -23,18 +23,18 @@ import {
|
|
|
23
23
|
DIRTY,
|
|
24
24
|
BRANCH_EFFECT,
|
|
25
25
|
EAGER_EFFECT,
|
|
26
|
-
UNOWNED,
|
|
27
26
|
MAYBE_DIRTY,
|
|
28
27
|
BLOCK_EFFECT,
|
|
29
28
|
ROOT_EFFECT,
|
|
30
29
|
ASYNC,
|
|
31
|
-
WAS_MARKED
|
|
30
|
+
WAS_MARKED,
|
|
31
|
+
CONNECTED
|
|
32
32
|
} from '#client/constants';
|
|
33
33
|
import * as e from '../errors.js';
|
|
34
34
|
import { legacy_mode_flag, tracing_mode_flag } from '../../flags/index.js';
|
|
35
35
|
import { get_stack, tag_proxy } from '../dev/tracing.js';
|
|
36
36
|
import { component_context, is_runes } from '../context.js';
|
|
37
|
-
import { Batch, eager_block_effects, schedule_effect } from './batch.js';
|
|
37
|
+
import { Batch, batch_values, eager_block_effects, schedule_effect } from './batch.js';
|
|
38
38
|
import { proxy } from '../proxy.js';
|
|
39
39
|
import { execute_derived } from './deriveds.js';
|
|
40
40
|
|
|
@@ -211,7 +211,8 @@ export function internal_set(source, value) {
|
|
|
211
211
|
if ((source.f & DIRTY) !== 0) {
|
|
212
212
|
execute_derived(/** @type {Derived} */ (source));
|
|
213
213
|
}
|
|
214
|
-
|
|
214
|
+
|
|
215
|
+
set_signal_status(source, (source.f & CONNECTED) !== 0 ? CLEAN : MAYBE_DIRTY);
|
|
215
216
|
}
|
|
216
217
|
|
|
217
218
|
source.wv = increment_write_version();
|
|
@@ -333,9 +334,17 @@ function mark_reactions(signal, status) {
|
|
|
333
334
|
}
|
|
334
335
|
|
|
335
336
|
if ((flags & DERIVED) !== 0) {
|
|
337
|
+
var derived = /** @type {Derived} */ (reaction);
|
|
338
|
+
|
|
339
|
+
batch_values?.delete(derived);
|
|
340
|
+
|
|
336
341
|
if ((flags & WAS_MARKED) === 0) {
|
|
337
|
-
|
|
338
|
-
|
|
342
|
+
// Only connected deriveds can be reliably unmarked right away
|
|
343
|
+
if (flags & CONNECTED) {
|
|
344
|
+
reaction.f |= WAS_MARKED;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
mark_reactions(derived, MAYBE_DIRTY);
|
|
339
348
|
}
|
|
340
349
|
} else if (not_dirty) {
|
|
341
350
|
if ((flags & BLOCK_EFFECT) !== 0) {
|