@solidjs/signals 2.0.0-rc.5 → 2.0.0-rc.7
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/dist/dev.js +2467 -1322
- package/dist/node.cjs +2037 -2428
- package/dist/node.dev.cjs +13724 -0
- package/dist/prod/boundaries.js +3 -1
- package/dist/prod/core/async.js +47 -20
- package/dist/prod/core/attribution-hooks.js +3 -0
- package/dist/prod/core/constants.js +9 -1
- package/dist/prod/core/context.js +10 -16
- package/dist/prod/core/core.js +260 -188
- package/dist/prod/core/dev.js +2 -0
- package/dist/prod/core/effect.js +41 -32
- package/dist/prod/core/external.js +2 -2
- package/dist/prod/core/graph.js +35 -31
- package/dist/prod/core/heap.js +34 -40
- package/dist/prod/core/lanes.js +44 -30
- package/dist/prod/core/optimistic.js +55 -45
- package/dist/prod/core/owner.js +35 -35
- package/dist/prod/core/scheduler.js +176 -177
- package/dist/prod/core/verdict.js +53 -52
- package/dist/prod/index.js +0 -2
- package/dist/prod/map.js +104 -94
- package/dist/prod/signals.js +119 -35
- package/dist/prod/store/next/optimistic.js +217 -163
- package/dist/prod/store/next/projection.js +2 -2
- package/dist/prod/store/next/reconcile.js +140 -288
- package/dist/prod/store/next/store.js +338 -252
- package/dist/prod/store/store.js +2 -2
- package/dist/types/core/attribution-hooks.d.ts +75 -0
- package/dist/types/core/attribution.d.ts +313 -9
- package/dist/types/core/constants.d.ts +8 -0
- package/dist/types/core/core.d.ts +12 -3
- package/dist/types/core/dev.d.ts +56 -9
- package/dist/types/core/heap.d.ts +5 -3
- package/dist/types/core/invariants.d.ts +1 -1
- package/dist/types/core/lanes.d.ts +10 -0
- package/dist/types/core/scheduler.d.ts +14 -4
- package/dist/types/signals.d.ts +10 -11
- package/dist/types/store/index.d.ts +3 -6
- package/dist/types/store/next/optimistic.d.ts +4 -2
- package/dist/types/store/next/reconcile.d.ts +5 -12
- package/dist/types/store/next/store.d.ts +3 -9
- package/dist/types/store/next/target.d.ts +30 -46
- package/dist/types/store/store.d.ts +14 -9
- package/dist/types-cjs/core/attribution-hooks.d.cts +75 -0
- package/dist/types-cjs/core/attribution.d.cts +313 -9
- package/dist/types-cjs/core/constants.d.cts +8 -0
- package/dist/types-cjs/core/core.d.cts +12 -3
- package/dist/types-cjs/core/dev.d.cts +56 -9
- package/dist/types-cjs/core/heap.d.cts +5 -3
- package/dist/types-cjs/core/invariants.d.cts +1 -1
- package/dist/types-cjs/core/lanes.d.cts +10 -0
- package/dist/types-cjs/core/scheduler.d.cts +14 -4
- package/dist/types-cjs/signals.d.cts +10 -11
- package/dist/types-cjs/store/index.d.cts +3 -6
- package/dist/types-cjs/store/next/optimistic.d.cts +4 -2
- package/dist/types-cjs/store/next/reconcile.d.cts +5 -12
- package/dist/types-cjs/store/next/store.d.cts +3 -9
- package/dist/types-cjs/store/next/target.d.cts +30 -46
- package/dist/types-cjs/store/store.d.cts +14 -9
- package/package.json +3 -2
- package/dist/prod/store/next/patch-hooks.js +0 -13
- package/dist/prod/store/next/patch.js +0 -614
- package/dist/types/store/next/patch-hooks.d.ts +0 -41
- package/dist/types/store/next/patch.d.ts +0 -91
- package/dist/types-cjs/store/next/patch-hooks.d.cts +0 -41
- package/dist/types-cjs/store/next/patch.d.cts +0 -91
package/dist/prod/signals.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { TimeoutError } from "./core/error.js";
|
|
2
2
|
|
|
3
|
-
import { computed, optimisticComputed, setSignal, optimisticSignal, runWithOwner, setMemo, signal,
|
|
3
|
+
import { computed, optimisticComputed, setSignal, optimisticSignal, runWithOwner, setMemo, signal, installAuthoritativeRead, markRefresh, read, untrack } from "./core/core.js";
|
|
4
4
|
|
|
5
5
|
import { cleanup, createRoot, getOwner, dispose, getObserver } from "./core/owner.js";
|
|
6
6
|
|
|
@@ -78,7 +78,74 @@ function createMemo(e, t) {
|
|
|
78
78
|
return accessor(computed(e, t));
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
|
|
81
|
+
/**
|
|
82
|
+
* Creates a reactive effect with **separate compute and effect phases**.
|
|
83
|
+
*
|
|
84
|
+
* - `compute(prev)` runs reactively — *put all reactive reads here*. The
|
|
85
|
+
* returned value is passed to `effect` and is also the new "previous" value
|
|
86
|
+
* for the next run.
|
|
87
|
+
* - `effect(next, prev?)` runs imperatively (untracked) after the queue
|
|
88
|
+
* flushes. *Put DOM writes / fetch / logging / subscriptions here.* It may
|
|
89
|
+
* return a cleanup function which runs before the next effect or on
|
|
90
|
+
* disposal.
|
|
91
|
+
*
|
|
92
|
+
* Reactive reads inside `effect` will *not* re-trigger this effect — that's
|
|
93
|
+
* intentional. If you need a single-phase tracked effect, use
|
|
94
|
+
* `createTrackedEffect` (with the tradeoffs noted there).
|
|
95
|
+
*
|
|
96
|
+
* Pass an `EffectBundle` (`{ effect, error }`) instead of a plain function to
|
|
97
|
+
* intercept **compute-phase** errors — errors thrown by `compute` or arriving
|
|
98
|
+
* from upstream reactive sources (including async rejections), which your own
|
|
99
|
+
* code has no frame to `try/catch`. The `error` handler is the error arm of
|
|
100
|
+
* the effect phase: it runs on the same schedule and in the same imperative,
|
|
101
|
+
* writable scope as `effect` (setting error state via signals is fine), and
|
|
102
|
+
* only for *settled* errors — a transient error that recovers before the
|
|
103
|
+
* effect phase runs `effect` with the recovered value instead, and a held
|
|
104
|
+
* transition defers it exactly as it defers `effect`. Without an `error`
|
|
105
|
+
* handler a compute-phase error is logged and the effect simply skips that
|
|
106
|
+
* run — a non-render effect's reactivity failing does not crash the app.
|
|
107
|
+
* Rethrowing from `error` escalates it to the nearest error boundary
|
|
108
|
+
* (halting the system if none exists).
|
|
109
|
+
*
|
|
110
|
+
* The **effect phase is different**: it is your own imperative code, so handle
|
|
111
|
+
* failures with `try/catch` where they occur. An uncaught effect-phase throw
|
|
112
|
+
* is treated as an unhandled application error — caught by the nearest
|
|
113
|
+
* `createErrorBoundary`/`<Errored>`, and permanently halting the reactive
|
|
114
|
+
* system if there is none. It is *not* routed to the bundle's `error` handler.
|
|
115
|
+
*
|
|
116
|
+
* ```typescript
|
|
117
|
+
* createEffect<T>(compute, effectFn | { effect, error }, options?: EffectOptions);
|
|
118
|
+
* ```
|
|
119
|
+
* @param compute a function that receives its previous value and returns a new value used to react on a computation
|
|
120
|
+
* @param effectFn a function that receives the new value and is used to perform side effects (return a cleanup function), or an `EffectBundle` with `effect` and `error` handlers
|
|
121
|
+
* @param options `EffectOptions` -- name, defer, schedule, transparent
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* ```ts
|
|
125
|
+
* const [count, setCount] = createSignal(0);
|
|
126
|
+
*
|
|
127
|
+
* createEffect(
|
|
128
|
+
* () => count(), // compute: tracks `count`
|
|
129
|
+
* value => console.log(value) // effect: side effect
|
|
130
|
+
* );
|
|
131
|
+
*
|
|
132
|
+
* setCount(1); // logs 1 after the next flush
|
|
133
|
+
* ```
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* ```ts
|
|
137
|
+
* createEffect(
|
|
138
|
+
* () => userId(),
|
|
139
|
+
* id => {
|
|
140
|
+
* const ctrl = new AbortController();
|
|
141
|
+
* fetch(`/users/${id}`, { signal: ctrl.signal });
|
|
142
|
+
* return () => ctrl.abort(); // cleanup before next run / disposal
|
|
143
|
+
* }
|
|
144
|
+
* );
|
|
145
|
+
* ```
|
|
146
|
+
*
|
|
147
|
+
* @description https://docs.solidjs.com/reference/basic-reactivity/create-effect
|
|
148
|
+
*/ function createEffect(e, t, n) {
|
|
82
149
|
effect(e, t.effect || t, t.error, {
|
|
83
150
|
user: true,
|
|
84
151
|
...n
|
|
@@ -121,6 +188,16 @@ function createEffect(e, t, n) {
|
|
|
121
188
|
* Creates a tracked reactive effect where dependency tracking and side effects happen
|
|
122
189
|
* in the same scope.
|
|
123
190
|
*
|
|
191
|
+
* @deprecated Do not use in new code. For a side effect that follows reactive
|
|
192
|
+
* state, use `createEffect(compute, effect)` — it separates tracking from the
|
|
193
|
+
* side effect, knows its dependencies before it runs, and participates in
|
|
194
|
+
* async and transitions. For one-time DOM work after render (measuring,
|
|
195
|
+
* attaching third-party widgets to a ref), use `onSettled`. Tracking from
|
|
196
|
+
* inside the effect phase — the only thing this primitive adds — is retained
|
|
197
|
+
* solely to ease 1.x migration: it runs beside user-effect callbacks after
|
|
198
|
+
* values commit, never holds a transition, and cannot observe a write staged
|
|
199
|
+
* earlier in the same flush by a signal it has not read yet.
|
|
200
|
+
*
|
|
124
201
|
* WARNING: Because tracking and effects happen in the same scope, this primitive
|
|
125
202
|
* may run multiple times for a single change or show tearing (reading inconsistent
|
|
126
203
|
* state). Use only when dynamic subscription patterns require same-scope tracking.
|
|
@@ -189,15 +266,15 @@ function createEffect(e, t, n) {
|
|
|
189
266
|
// sources stayed live (firing the callback for replaced dependencies), each
|
|
190
267
|
// accumulated arm delivered its own fire, and un-fired arms leaked as live
|
|
191
268
|
// effect nodes until the owner disposed (#2861).
|
|
192
|
-
let
|
|
193
|
-
return
|
|
194
|
-
if (
|
|
195
|
-
dispose(
|
|
196
|
-
|
|
269
|
+
let i;
|
|
270
|
+
return o => {
|
|
271
|
+
if (i) {
|
|
272
|
+
dispose(i);
|
|
273
|
+
i = undefined;
|
|
197
274
|
}
|
|
198
275
|
runWithOwner(r, () => {
|
|
199
|
-
effect(() => (
|
|
200
|
-
|
|
276
|
+
effect(() => (o(), i = getOwner()), t => {
|
|
277
|
+
i = undefined;
|
|
201
278
|
n?.();
|
|
202
279
|
const r = (e.effect || e)?.();
|
|
203
280
|
if (false && r !== undefined && typeof r !== "function") ;
|
|
@@ -251,11 +328,11 @@ function createEffect(e, t, n) {
|
|
|
251
328
|
// still runs in place (under the transaction's view when created inside
|
|
252
329
|
// an action step), and status/boundary notifications keep their normal
|
|
253
330
|
// route through the inherited queue.
|
|
254
|
-
const
|
|
255
|
-
const
|
|
256
|
-
|
|
331
|
+
const i = getOwner();
|
|
332
|
+
const o = new MicrotaskQueue;
|
|
333
|
+
o.Le = i.C;
|
|
257
334
|
// notify() forwards up the normal chain
|
|
258
|
-
|
|
335
|
+
i.C = o;
|
|
259
336
|
// A user effect rather than a bare computed: computeds are pull-based and
|
|
260
337
|
// are only re-enqueued when a pending source *resolves* — a rejection just
|
|
261
338
|
// marks them errored, so nothing would re-run and the promise would never
|
|
@@ -275,7 +352,7 @@ function createEffect(e, t, n) {
|
|
|
275
352
|
// stale mainline value and resolves with old data.
|
|
276
353
|
{
|
|
277
354
|
user: true,
|
|
278
|
-
|
|
355
|
+
At: CONFIG_DIRECT_COMMIT
|
|
279
356
|
});
|
|
280
357
|
});
|
|
281
358
|
});
|
|
@@ -343,7 +420,14 @@ function createEffect(e, t, n) {
|
|
|
343
420
|
// own eager compute is untouched: created after a refresh it still settles
|
|
344
421
|
// stale-while-revalidate (#2930) — its contract is "first settled value",
|
|
345
422
|
// not "next quiescent state".
|
|
346
|
-
|
|
423
|
+
|
|
424
|
+
// An authoritative reader is woken through a late-bound hook when the truth
|
|
425
|
+
// lands EQUAL to a standing override (the A17-silent path). Every setter of
|
|
426
|
+
// that reader bit must install it — until() does, and this waiter is the
|
|
427
|
+
// other one (#3303: refresh of an optimistic in an app that never called
|
|
428
|
+
// until() dereferenced the null hook).
|
|
429
|
+
installAuthoritativeRead();
|
|
430
|
+
markRefresh(t);
|
|
347
431
|
const n = new Promise((n, r) => {
|
|
348
432
|
queueMicrotask(() => {
|
|
349
433
|
// No createRoot: the microtask has no ambient owner, so the effect is
|
|
@@ -356,24 +440,24 @@ function createEffect(e, t, n) {
|
|
|
356
440
|
// Typed as the effect node, not Owner: the capture runs inside the
|
|
357
441
|
// effect's own compute, where the ambient owner IS the effect —
|
|
358
442
|
// exactly what dispose() takes.
|
|
359
|
-
let
|
|
443
|
+
let i = null;
|
|
360
444
|
const make = () => effect(() => {
|
|
361
|
-
if (
|
|
362
|
-
|
|
445
|
+
if (i === null) {
|
|
446
|
+
i = getOwner();
|
|
363
447
|
const e = new MicrotaskQueue;
|
|
364
|
-
e.
|
|
365
|
-
|
|
448
|
+
e.Le = i.C;
|
|
449
|
+
i.C = e;
|
|
366
450
|
}
|
|
367
451
|
return read(t);
|
|
368
452
|
}, t => {
|
|
369
453
|
n(typeof e === "function" ? t : e);
|
|
370
|
-
dispose(
|
|
454
|
+
dispose(i);
|
|
371
455
|
}, e => {
|
|
372
456
|
r(e);
|
|
373
|
-
dispose(
|
|
457
|
+
dispose(i);
|
|
374
458
|
}, {
|
|
375
459
|
user: true,
|
|
376
|
-
|
|
460
|
+
At: CONFIG_DIRECT_COMMIT | CONFIG_AUTHORITATIVE_READ | CONFIG_FRESH_READ
|
|
377
461
|
});
|
|
378
462
|
make();
|
|
379
463
|
});
|
|
@@ -448,9 +532,9 @@ function createEffect(e, t, n) {
|
|
|
448
532
|
// write flips it truthy, that transition merges here and reveals at the
|
|
449
533
|
// joint settle instead of painting the confirmation under live optimism.
|
|
450
534
|
const n = activeTransition;
|
|
451
|
-
return new Promise((r,
|
|
452
|
-
const
|
|
453
|
-
if (
|
|
535
|
+
return new Promise((r, i) => {
|
|
536
|
+
const o = t?.signal;
|
|
537
|
+
if (o?.aborted) return i(o.reason);
|
|
454
538
|
createRoot(c => {
|
|
455
539
|
// Same delivery contract as resolve() (#2930): effect applies ride a
|
|
456
540
|
// microtask so the promise can settle while the transaction the caller
|
|
@@ -458,13 +542,13 @@ function createEffect(e, t, n) {
|
|
|
458
542
|
// entire point of the hold.
|
|
459
543
|
const s = getOwner();
|
|
460
544
|
const u = new MicrotaskQueue;
|
|
461
|
-
u.
|
|
545
|
+
u.Le = s.C;
|
|
462
546
|
s.C = u;
|
|
463
547
|
let f;
|
|
464
548
|
let a;
|
|
465
549
|
const settle = e => {
|
|
466
550
|
if (f !== undefined) clearTimeout(f);
|
|
467
|
-
if (a !== undefined)
|
|
551
|
+
if (a !== undefined) o.removeEventListener("abort", a);
|
|
468
552
|
e();
|
|
469
553
|
c();
|
|
470
554
|
};
|
|
@@ -480,7 +564,7 @@ function createEffect(e, t, n) {
|
|
|
480
564
|
// Falsy is "not yet": keep the subscription live and wait for the
|
|
481
565
|
// next evaluation. Only a truthy settled value resolves.
|
|
482
566
|
if (e) settle(() => r(e));
|
|
483
|
-
}, e => settle(() =>
|
|
567
|
+
}, e => settle(() => i(e)),
|
|
484
568
|
// AUTHORITATIVE_READ: overrides invisible to the predicate.
|
|
485
569
|
// DIRECT_COMMIT: truth that stages into the held transaction (a
|
|
486
570
|
// refresh the action issued) must flow through to the microtask
|
|
@@ -488,12 +572,12 @@ function createEffect(e, t, n) {
|
|
|
488
572
|
// the hold itself is keeping uncommitted.
|
|
489
573
|
{
|
|
490
574
|
user: true,
|
|
491
|
-
|
|
575
|
+
At: CONFIG_AUTHORITATIVE_READ | CONFIG_DIRECT_COMMIT
|
|
492
576
|
});
|
|
493
|
-
if (t?.timeout !== undefined) f = setTimeout(() => settle(() =>
|
|
494
|
-
if (
|
|
495
|
-
a = () => settle(() => o
|
|
496
|
-
|
|
577
|
+
if (t?.timeout !== undefined) f = setTimeout(() => settle(() => i(new TimeoutError)), t.timeout);
|
|
578
|
+
if (o !== undefined) {
|
|
579
|
+
a = () => settle(() => i(o.reason));
|
|
580
|
+
o.addEventListener("abort", a, {
|
|
497
581
|
once: true
|
|
498
582
|
});
|
|
499
583
|
}
|
|
@@ -610,7 +694,7 @@ function createOptimistic(e, t) {
|
|
|
610
694
|
* on owner disposal
|
|
611
695
|
*/ function onSettled(e) {
|
|
612
696
|
const t = getOwner();
|
|
613
|
-
t && !(t.T & CONFIG_CHILDREN_FORBIDDEN) ?
|
|
697
|
+
t && !(t.T & CONFIG_CHILDREN_FORBIDDEN) ? trackedEffect(() => untrack(e), undefined) : globalQueue.enqueue(EFFECT_USER, () => {
|
|
614
698
|
// Unowned, out-of-band fire (no owner, or a children-forbidden one this
|
|
615
699
|
// one-shot must not bind to): a returned cleanup has no lifecycle to
|
|
616
700
|
// attach to. Reject it in dev; in production the return is simply
|