ripple 0.3.25 → 1.0.1
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/CHANGELOG.md +26 -0
- package/package.json +5 -5
- package/src/runtime/index-client.js +4 -0
- package/src/runtime/internal/client/hmr.js +1 -1
- package/src/runtime/internal/client/hydration.js +14 -0
- package/src/runtime/internal/client/runtime.js +127 -31
- package/src/runtime/internal/client/types.d.ts +3 -33
- package/src/runtime/internal/server/blocks.js +21 -1
- package/src/runtime/internal/server/index.js +299 -34
- package/src/runtime/internal/server/types.d.ts +3 -31
- package/src/runtime/reactive-value.js +1 -0
- package/src/utils/escaping.js +11 -0
- package/src/utils/track-async-serialization.js +9 -0
- package/tests/client/async-suspend.test.tsrx +11 -1
- package/tests/client/compiler/compiler.basic.test.tsrx +18 -3
- package/tests/client/track-async-hydration.test.tsrx +54 -0
- package/tests/hydration/compiled/client/basic.js +1 -1
- package/tests/hydration/compiled/client/events.js +8 -8
- package/tests/hydration/compiled/client/for.js +22 -24
- package/tests/hydration/compiled/client/head.js +6 -6
- package/tests/hydration/compiled/client/hmr.js +1 -1
- package/tests/hydration/compiled/client/html.js +1 -1
- package/tests/hydration/compiled/client/if-children.js +7 -7
- package/tests/hydration/compiled/client/if.js +5 -5
- package/tests/hydration/compiled/client/mixed-control-flow.js +4 -4
- package/tests/hydration/compiled/client/portal.js +1 -1
- package/tests/hydration/compiled/client/reactivity.js +9 -9
- package/tests/hydration/compiled/client/return.js +23 -23
- package/tests/hydration/compiled/client/switch.js +4 -4
- package/tests/hydration/compiled/client/track-async-serialization.js +390 -0
- package/tests/hydration/compiled/client/try.js +2 -2
- package/tests/hydration/compiled/server/basic.js +1 -1
- package/tests/hydration/compiled/server/events.js +8 -8
- package/tests/hydration/compiled/server/for.js +34 -28
- package/tests/hydration/compiled/server/head.js +6 -6
- package/tests/hydration/compiled/server/hmr.js +1 -1
- package/tests/hydration/compiled/server/html.js +1 -1
- package/tests/hydration/compiled/server/if-children.js +7 -7
- package/tests/hydration/compiled/server/if.js +5 -5
- package/tests/hydration/compiled/server/mixed-control-flow.js +4 -4
- package/tests/hydration/compiled/server/portal.js +1 -1
- package/tests/hydration/compiled/server/reactivity.js +9 -9
- package/tests/hydration/compiled/server/return.js +11 -11
- package/tests/hydration/compiled/server/switch.js +4 -4
- package/tests/hydration/compiled/server/track-async-serialization.js +502 -0
- package/tests/hydration/compiled/server/try.js +2 -2
- package/tests/hydration/components/track-async-serialization.tsrx +116 -0
- package/tests/hydration/track-async-serialization.test.js +127 -0
- package/tests/server/track-async-serialization.test.tsrx +185 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
# ripple
|
|
2
2
|
|
|
3
|
+
## 1.0.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#886](https://github.com/Ripple-TS/ripple/pull/886)
|
|
8
|
+
[`316cba1`](https://github.com/Ripple-TS/ripple/commit/316cba18614e5ef59dce15e0de6e720eb922955f)
|
|
9
|
+
Thanks [@leonidaz](https://github.com/leonidaz)! - Add SSR-to-client
|
|
10
|
+
serialization/hydration for trackAsync by emitting per-call JSON <script>
|
|
11
|
+
envelopes (resolved payload + direct dependency hashes, or sanitized error
|
|
12
|
+
message) and consuming/removing them during client hydration to avoid re-running
|
|
13
|
+
the user async function. Add proper error handling routing to catch blocks with
|
|
14
|
+
actual error messages in DEV and safe production error messages, all with
|
|
15
|
+
correct hydration support
|
|
16
|
+
- Updated dependencies
|
|
17
|
+
[[`316cba1`](https://github.com/Ripple-TS/ripple/commit/316cba18614e5ef59dce15e0de6e720eb922955f)]:
|
|
18
|
+
- ripple@1.0.1
|
|
19
|
+
- @tsrx/ripple@0.0.8
|
|
20
|
+
|
|
21
|
+
## 1.0.0
|
|
22
|
+
|
|
23
|
+
### Patch Changes
|
|
24
|
+
|
|
25
|
+
- Updated dependencies []:
|
|
26
|
+
- ripple@1.0.0
|
|
27
|
+
- @tsrx/ripple@0.0.7
|
|
28
|
+
|
|
3
29
|
## 0.3.25
|
|
4
30
|
|
|
5
31
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "Ripple is an elegant TypeScript UI framework",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Dominic Gannaway",
|
|
6
|
-
"version": "0.
|
|
6
|
+
"version": "1.0.1",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"module": "src/runtime/index-client.js",
|
|
9
9
|
"main": "src/runtime/index-client.js",
|
|
@@ -72,11 +72,11 @@
|
|
|
72
72
|
},
|
|
73
73
|
"dependencies": {
|
|
74
74
|
"clsx": "^2.1.1",
|
|
75
|
-
"devalue": "^5.
|
|
75
|
+
"devalue": "^5.7.1",
|
|
76
76
|
"esm-env": "^1.2.2",
|
|
77
77
|
"@types/estree": "^1.0.8",
|
|
78
78
|
"@types/estree-jsx": "^1.0.5",
|
|
79
|
-
"@tsrx/ripple": "0.0.
|
|
79
|
+
"@tsrx/ripple": "0.0.8"
|
|
80
80
|
},
|
|
81
81
|
"devDependencies": {
|
|
82
82
|
"@types/node": "^24.3.0",
|
|
@@ -84,9 +84,9 @@
|
|
|
84
84
|
"typescript": "^5.9.3",
|
|
85
85
|
"@volar/language-core": "~2.4.28",
|
|
86
86
|
"vscode-languageserver-types": "^3.17.5",
|
|
87
|
-
"@tsrx/core": "0.0.
|
|
87
|
+
"@tsrx/core": "0.0.6"
|
|
88
88
|
},
|
|
89
89
|
"peerDependencies": {
|
|
90
|
-
"ripple": "0.
|
|
90
|
+
"ripple": "1.0.1"
|
|
91
91
|
}
|
|
92
92
|
}
|
|
@@ -11,6 +11,7 @@ import { active_block } from './internal/client/runtime.js';
|
|
|
11
11
|
import { create_anchor } from './internal/client/utils.js';
|
|
12
12
|
import { remove_ssr_css } from './internal/client/css.js';
|
|
13
13
|
import {
|
|
14
|
+
clear_track_hash_reference,
|
|
14
15
|
hydrate_next,
|
|
15
16
|
hydrate_node,
|
|
16
17
|
hydrating,
|
|
@@ -108,6 +109,9 @@ export function hydrate(component, options) {
|
|
|
108
109
|
} finally {
|
|
109
110
|
set_hydrating(was_hydrating);
|
|
110
111
|
set_hydrate_node(previous_hydrate_node, true);
|
|
112
|
+
if (!was_hydrating) {
|
|
113
|
+
clear_track_hash_reference();
|
|
114
|
+
}
|
|
111
115
|
}
|
|
112
116
|
|
|
113
117
|
return () => {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
/** @import { Derived, Tracked } from '#client' */
|
|
2
|
+
|
|
1
3
|
import {
|
|
2
4
|
COMMENT_NODE,
|
|
3
5
|
HYDRATION_END,
|
|
@@ -11,6 +13,18 @@ export let hydrating = false;
|
|
|
11
13
|
/** @type {Node | null} */
|
|
12
14
|
export let hydrate_node = null;
|
|
13
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Map of hash -> Tracked/Derived registered during hydration. Allows a
|
|
18
|
+
* hydrating trackAsync to look up its serialized dependencies by hash and
|
|
19
|
+
* wire up reactivity without re-running the user's async fn.
|
|
20
|
+
* @type {Map<string, Tracked | Derived>}
|
|
21
|
+
*/
|
|
22
|
+
export const track_hash_reference = new Map();
|
|
23
|
+
|
|
24
|
+
export function clear_track_hash_reference() {
|
|
25
|
+
track_hash_reference.clear();
|
|
26
|
+
}
|
|
27
|
+
|
|
14
28
|
/**
|
|
15
29
|
* @param {boolean} value
|
|
16
30
|
*/
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
/** @import { Block, Component, Dependency,
|
|
1
|
+
/** @import { Block, Component, Dependency, BlockWithTryBoundaryAndCatch, DeferredTrackedEntry } from '#client' */
|
|
2
2
|
/** @import { NAMESPACE_URI } from './constants.js' */
|
|
3
|
+
/** @typedef {TrackedValue} Tracked */
|
|
4
|
+
/** @typedef {DerivedValue} Derived */
|
|
3
5
|
|
|
4
6
|
import { DEV } from 'esm-env';
|
|
5
7
|
import {
|
|
@@ -51,6 +53,9 @@ import {
|
|
|
51
53
|
object_keys,
|
|
52
54
|
} from './utils.js';
|
|
53
55
|
import { get_async_track_result } from '../../../utils/async.js';
|
|
56
|
+
import { get_track_async_script_id } from '../../../utils/track-async-serialization.js';
|
|
57
|
+
import * as devalue from 'devalue';
|
|
58
|
+
import { hydrating, track_hash_reference } from './hydration.js';
|
|
54
59
|
|
|
55
60
|
const FLUSH_MICROTASK = 0;
|
|
56
61
|
const FLUSH_SYNC = 1;
|
|
@@ -383,31 +388,42 @@ function complete_deferred_boundaries(t, show_resolved = true) {
|
|
|
383
388
|
}
|
|
384
389
|
}
|
|
385
390
|
|
|
386
|
-
/** @type {Tracked} */
|
|
387
391
|
class TrackedValue {
|
|
388
392
|
/**
|
|
389
393
|
* @param {any} v
|
|
390
394
|
* @param {Block} block
|
|
391
395
|
* @param {{ get?: Function; set?: Function }} a
|
|
396
|
+
* @param {string} [hash]
|
|
392
397
|
*/
|
|
393
|
-
constructor(v, block, a) {
|
|
398
|
+
constructor(v, block, a, hash) {
|
|
399
|
+
/** @type {{ get?: Function; set?: Function }} */
|
|
394
400
|
this.a = a;
|
|
401
|
+
/** @type {Block} */
|
|
395
402
|
this.b = block;
|
|
403
|
+
/** @type {number} */
|
|
396
404
|
this.c = 0;
|
|
397
405
|
/** @type {DeferredTrackedEntry[] | null} */
|
|
398
406
|
this.d = null;
|
|
407
|
+
/** @type {number} */
|
|
399
408
|
this.f = TRACKED;
|
|
409
|
+
/** @type {string | undefined} */
|
|
410
|
+
this.h = hash;
|
|
411
|
+
/** @type {any} */
|
|
400
412
|
this.__v = v;
|
|
401
413
|
}
|
|
414
|
+
/** @returns {any} */
|
|
402
415
|
get [0]() {
|
|
403
416
|
return get_tracked(this);
|
|
404
417
|
}
|
|
418
|
+
/** @param {any} v */
|
|
405
419
|
set [0](v) {
|
|
406
420
|
set(this, v);
|
|
407
421
|
}
|
|
422
|
+
/** @returns {Tracked} */
|
|
408
423
|
get [1]() {
|
|
409
|
-
return this;
|
|
424
|
+
return /** @type {Tracked} */ (this);
|
|
410
425
|
}
|
|
426
|
+
/** @returns {any} */
|
|
411
427
|
get value() {
|
|
412
428
|
return get_tracked(this);
|
|
413
429
|
}
|
|
@@ -419,41 +435,55 @@ class TrackedValue {
|
|
|
419
435
|
get length() {
|
|
420
436
|
return 2;
|
|
421
437
|
}
|
|
438
|
+
/** @returns {Iterator<any | Tracked>} */
|
|
422
439
|
*[Symbol.iterator]() {
|
|
423
440
|
yield get_tracked(this);
|
|
424
441
|
yield this;
|
|
425
442
|
}
|
|
426
443
|
}
|
|
427
444
|
|
|
428
|
-
/** @type {Derived} */
|
|
429
445
|
class DerivedValue {
|
|
430
446
|
/**
|
|
431
447
|
* @param {Function} fn
|
|
432
448
|
* @param {Block} block
|
|
433
449
|
* @param {{ get?: Function; set?: Function }} a
|
|
450
|
+
* @param {string} [hash]
|
|
434
451
|
*/
|
|
435
|
-
constructor(fn, block, a) {
|
|
452
|
+
constructor(fn, block, a, hash) {
|
|
453
|
+
/** @type {{ get?: Function; set?: Function }} */
|
|
436
454
|
this.a = a;
|
|
455
|
+
/** @type {Block} */
|
|
437
456
|
this.b = block;
|
|
438
|
-
/** @type {
|
|
457
|
+
/** @type {Block[] | null} */
|
|
439
458
|
this.blocks = null;
|
|
459
|
+
/** @type {number} */
|
|
440
460
|
this.c = 0;
|
|
461
|
+
/** @type {Component | null} */
|
|
441
462
|
this.co = active_component;
|
|
442
|
-
/** @type {
|
|
463
|
+
/** @type {Dependency | null} */
|
|
443
464
|
this.d = null;
|
|
465
|
+
/** @type {number} */
|
|
444
466
|
this.f = DERIVED;
|
|
467
|
+
/** @type {Function} */
|
|
445
468
|
this.fn = fn;
|
|
469
|
+
/** @type {string | undefined} */
|
|
470
|
+
this.h = hash;
|
|
471
|
+
/** @type {any} */
|
|
446
472
|
this.__v = UNINITIALIZED;
|
|
447
473
|
}
|
|
474
|
+
/** @returns {any} */
|
|
448
475
|
get [0]() {
|
|
449
476
|
return get_derived(this);
|
|
450
477
|
}
|
|
478
|
+
/** @param {any} v */
|
|
451
479
|
set [0](v) {
|
|
452
480
|
set(this, v);
|
|
453
481
|
}
|
|
482
|
+
/** @returns {Derived} */
|
|
454
483
|
get [1]() {
|
|
455
|
-
return this;
|
|
484
|
+
return /** @type {Derived} */ (this);
|
|
456
485
|
}
|
|
486
|
+
/** @returns {any} */
|
|
457
487
|
get value() {
|
|
458
488
|
return get_derived(this);
|
|
459
489
|
}
|
|
@@ -465,6 +495,7 @@ class DerivedValue {
|
|
|
465
495
|
get length() {
|
|
466
496
|
return 2;
|
|
467
497
|
}
|
|
498
|
+
/** @returns {Iterator<any | Derived>} */
|
|
468
499
|
*[Symbol.iterator]() {
|
|
469
500
|
yield get_derived(this);
|
|
470
501
|
yield this;
|
|
@@ -480,37 +511,48 @@ if (DEV) {
|
|
|
480
511
|
*
|
|
481
512
|
* @param {any} v
|
|
482
513
|
* @param {Block} block
|
|
514
|
+
* @param {string} [hash]
|
|
483
515
|
* @param {(value: any) => any} [get]
|
|
484
516
|
* @param {(next: any, prev: any) => any} [set]
|
|
485
517
|
* @returns {Tracked}
|
|
486
518
|
*/
|
|
487
|
-
export function tracked(v, block, get, set) {
|
|
488
|
-
|
|
489
|
-
new TrackedValue(v, block || active_block, get || set ? { get, set } : empty_get_set)
|
|
519
|
+
export function tracked(v, block, hash, get, set) {
|
|
520
|
+
var t = /** @type {Tracked} */ (
|
|
521
|
+
new TrackedValue(v, block || active_block, get || set ? { get, set } : empty_get_set, hash)
|
|
490
522
|
);
|
|
523
|
+
if (hydrating && hash !== undefined) {
|
|
524
|
+
track_hash_reference.set(hash, t);
|
|
525
|
+
}
|
|
526
|
+
return t;
|
|
491
527
|
}
|
|
492
528
|
|
|
493
529
|
/**
|
|
494
530
|
* @param {any} fn
|
|
495
|
-
* @param {
|
|
531
|
+
* @param {Block} block
|
|
532
|
+
* @param {string} [hash]
|
|
496
533
|
* @param {(value: any) => any} [get]
|
|
497
534
|
* @param {(next: any, prev: any) => any} [set]
|
|
498
535
|
* @returns {Derived}
|
|
499
536
|
*/
|
|
500
|
-
export function derived(fn, block, get, set) {
|
|
501
|
-
|
|
502
|
-
new DerivedValue(fn, block || active_block, get || set ? { get, set } : empty_get_set)
|
|
537
|
+
export function derived(fn, block, hash, get, set) {
|
|
538
|
+
var d = /** @type {Derived} */ (
|
|
539
|
+
new DerivedValue(fn, block || active_block, get || set ? { get, set } : empty_get_set, hash)
|
|
503
540
|
);
|
|
541
|
+
if (hydrating && hash !== undefined) {
|
|
542
|
+
track_hash_reference.set(hash, d);
|
|
543
|
+
}
|
|
544
|
+
return d;
|
|
504
545
|
}
|
|
505
546
|
|
|
506
547
|
/**
|
|
507
548
|
* @param {any} v
|
|
508
|
-
* @param {(value: any) => any | undefined} get
|
|
509
|
-
* @param {(next: any, prev: any) => any | undefined} set
|
|
510
549
|
* @param {Block} b
|
|
550
|
+
* @param {string} [hash]
|
|
551
|
+
* @param {(value: any) => any} [get]
|
|
552
|
+
* @param {(next: any, prev: any) => any} [set]
|
|
511
553
|
* @returns {Tracked | Derived}
|
|
512
554
|
*/
|
|
513
|
-
export function track(v, get, set
|
|
555
|
+
export function track(v, b, hash, get, set) {
|
|
514
556
|
if (is_ripple_object(v)) {
|
|
515
557
|
return v;
|
|
516
558
|
}
|
|
@@ -519,17 +561,18 @@ export function track(v, get, set, b) {
|
|
|
519
561
|
}
|
|
520
562
|
|
|
521
563
|
if (typeof v === 'function') {
|
|
522
|
-
return derived(v, b, get, set);
|
|
564
|
+
return derived(v, b, hash, get, set);
|
|
523
565
|
}
|
|
524
|
-
return tracked(v, b, get, set);
|
|
566
|
+
return tracked(v, b, hash, get, set);
|
|
525
567
|
}
|
|
526
568
|
|
|
527
569
|
/**
|
|
528
570
|
* @param {any} fn
|
|
529
571
|
* @param {Block} b
|
|
572
|
+
* @param {string} hash - Unique hash for SSR serialization/hydration
|
|
530
573
|
* @returns {Tracked | void}
|
|
531
574
|
*/
|
|
532
|
-
export function track_async(fn, b) {
|
|
575
|
+
export function track_async(fn, b, hash) {
|
|
533
576
|
if (is_ripple_object(fn)) {
|
|
534
577
|
return fn;
|
|
535
578
|
}
|
|
@@ -545,7 +588,31 @@ export function track_async(fn, b) {
|
|
|
545
588
|
);
|
|
546
589
|
}
|
|
547
590
|
|
|
548
|
-
|
|
591
|
+
// During hydration, attempt to read serialized data from SSR
|
|
592
|
+
var had_hydration_data = false;
|
|
593
|
+
var hydration_value;
|
|
594
|
+
/** @type {string[] | undefined} */
|
|
595
|
+
var hydration_deps;
|
|
596
|
+
|
|
597
|
+
if (hydrating) {
|
|
598
|
+
var script_id = get_track_async_script_id(hash);
|
|
599
|
+
var script_el = document.getElementById(script_id);
|
|
600
|
+
if (script_el) {
|
|
601
|
+
var envelope = JSON.parse(/** @type {string} */ (script_el.textContent));
|
|
602
|
+
script_el.remove();
|
|
603
|
+
|
|
604
|
+
if (envelope.ok) {
|
|
605
|
+
had_hydration_data = true;
|
|
606
|
+
hydration_value = devalue.parse(envelope.payload);
|
|
607
|
+
hydration_deps = envelope.deps;
|
|
608
|
+
} else {
|
|
609
|
+
// trigger the catch block
|
|
610
|
+
throw new Error(envelope.error?.message ?? 'Unknown server error');
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
var t = tracked(had_hydration_data ? hydration_value : SUSPENSE_PENDING, target_block, hash);
|
|
549
616
|
|
|
550
617
|
// Capture the call-site block for boundary lookups. target_block is the
|
|
551
618
|
// component's block (passed by compiler), but the actual try/pending/catch
|
|
@@ -559,15 +626,44 @@ export function track_async(fn, b) {
|
|
|
559
626
|
/** @type {Block | null} */
|
|
560
627
|
var boundary = null;
|
|
561
628
|
|
|
629
|
+
// TODO: decide if instead of insisting on pending, we create our own boundary
|
|
630
|
+
// we currently require a pending block upstream but we could also
|
|
631
|
+
// create a try/pending/catch boundary at mount and hydration like
|
|
632
|
+
// we do on the server so that there is always a boundary present.
|
|
633
|
+
// It can handle global pending when none were provided.
|
|
634
|
+
// Not sure about the catch boundary because if none were provided,
|
|
635
|
+
// the whole app for any error will be unmounted with the catch block rendered
|
|
636
|
+
|
|
562
637
|
// Find boundary from the call-site block.
|
|
563
638
|
boundary = get_pending_boundary(active_block);
|
|
564
639
|
if (boundary === null) {
|
|
565
640
|
throw new Error('Missing parent `try { ... } pending { ... }` statement');
|
|
566
641
|
}
|
|
567
642
|
|
|
568
|
-
|
|
643
|
+
// If we hydrated with resolved data, the SSR already completed this request.
|
|
644
|
+
// Otherwise mark a pending request on the boundary for the client-side run.
|
|
645
|
+
if (!had_hydration_data) {
|
|
646
|
+
request_id = begin_boundary_request(boundary);
|
|
647
|
+
}
|
|
569
648
|
|
|
570
649
|
pre_effect(() => {
|
|
650
|
+
if (had_hydration_data) {
|
|
651
|
+
// First run after hydration: skip fn() entirely (the SSR already
|
|
652
|
+
// produced the resolved value) and instead register the direct
|
|
653
|
+
// dependencies from the serialized deps list so future dep changes
|
|
654
|
+
// trigger a re-run via the normal async path.
|
|
655
|
+
had_hydration_data = false;
|
|
656
|
+
if (hydration_deps !== undefined) {
|
|
657
|
+
for (var i = 0; i < hydration_deps.length; i++) {
|
|
658
|
+
var dep_ref = track_hash_reference.get(hydration_deps[i]);
|
|
659
|
+
if (dep_ref !== undefined) {
|
|
660
|
+
get(dep_ref);
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
return;
|
|
665
|
+
}
|
|
666
|
+
|
|
571
667
|
var current_version = ++version;
|
|
572
668
|
|
|
573
669
|
// Abort previous in-flight request
|
|
@@ -583,7 +679,7 @@ export function track_async(fn, b) {
|
|
|
583
679
|
request_id = begin_boundary_request(boundary);
|
|
584
680
|
}
|
|
585
681
|
|
|
586
|
-
// Set to pending before calling fn() in case it's sync
|
|
682
|
+
// Set to pending before calling fn() in case it's sync.
|
|
587
683
|
if (t.__v !== SUSPENSE_PENDING) {
|
|
588
684
|
update_tracked_value_clock(t, SUSPENSE_PENDING);
|
|
589
685
|
schedule_update(t.b);
|
|
@@ -712,15 +808,15 @@ export function track_async(fn, b) {
|
|
|
712
808
|
}
|
|
713
809
|
|
|
714
810
|
/**
|
|
715
|
-
* @param {(Derived | Tracked) | (() => any)}
|
|
811
|
+
* @param {(Derived | Tracked) | (() => any)} t
|
|
716
812
|
* @returns {boolean}
|
|
717
813
|
*/
|
|
718
|
-
export function is_tracked_pending(
|
|
814
|
+
export function is_tracked_pending(t) {
|
|
719
815
|
try {
|
|
720
|
-
if (typeof
|
|
721
|
-
|
|
816
|
+
if (typeof t === 'function') {
|
|
817
|
+
t();
|
|
722
818
|
} else {
|
|
723
|
-
get(
|
|
819
|
+
get(t);
|
|
724
820
|
}
|
|
725
821
|
return false;
|
|
726
822
|
} catch (error) {
|
|
@@ -1225,7 +1321,7 @@ export function spread_props(fn) {
|
|
|
1225
1321
|
* @returns {Object}
|
|
1226
1322
|
*/
|
|
1227
1323
|
export function proxy_props(fn) {
|
|
1228
|
-
const memo = derived(fn, active_block);
|
|
1324
|
+
const memo = derived(fn, /** @type {Block} */ (active_block));
|
|
1229
1325
|
|
|
1230
1326
|
return new Proxy(
|
|
1231
1327
|
{},
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import type { Tracked, Derived } from './runtime.js';
|
|
1
2
|
import type { Context } from './context.js';
|
|
2
3
|
|
|
4
|
+
export { Tracked, Derived };
|
|
5
|
+
|
|
3
6
|
export type Component = {
|
|
4
7
|
b: null | Block;
|
|
5
8
|
c: null | Map<Context<any>, any>;
|
|
@@ -18,44 +21,11 @@ export type Dependency = {
|
|
|
18
21
|
n: null | Dependency;
|
|
19
22
|
};
|
|
20
23
|
|
|
21
|
-
export type Tracked<V = any> = {
|
|
22
|
-
DO_NOT_ACCESS_THIS_OBJECT_DIRECTLY?: true;
|
|
23
|
-
a: { get?: Function; set?: Function };
|
|
24
|
-
b: Block;
|
|
25
|
-
c: number;
|
|
26
|
-
d: null | DeferredTrackedEntry[];
|
|
27
|
-
f: number;
|
|
28
|
-
__v: V;
|
|
29
|
-
readonly [0]: V;
|
|
30
|
-
[1]: Tracked<V>;
|
|
31
|
-
value: V;
|
|
32
|
-
readonly length: 2;
|
|
33
|
-
[Symbol.iterator](): Iterator<V | Tracked<V>>;
|
|
34
|
-
};
|
|
35
|
-
|
|
36
24
|
export type DeferredTrackedEntry = {
|
|
37
25
|
b: Block; // boundary block
|
|
38
26
|
r: number; // request version id
|
|
39
27
|
};
|
|
40
28
|
|
|
41
|
-
export type Derived = {
|
|
42
|
-
DO_NOT_ACCESS_THIS_OBJECT_DIRECTLY?: true;
|
|
43
|
-
a: { get?: Function; set?: Function };
|
|
44
|
-
b: Block;
|
|
45
|
-
blocks: null | Block[];
|
|
46
|
-
c: number;
|
|
47
|
-
co: null | Component;
|
|
48
|
-
d: null | Dependency;
|
|
49
|
-
f: number;
|
|
50
|
-
fn: Function;
|
|
51
|
-
__v: any;
|
|
52
|
-
readonly [0]: any;
|
|
53
|
-
[1]: Derived;
|
|
54
|
-
value: any;
|
|
55
|
-
readonly length: 2;
|
|
56
|
-
[Symbol.iterator](): Iterator<any | Derived>;
|
|
57
|
-
};
|
|
58
|
-
|
|
59
29
|
export type Block = {
|
|
60
30
|
co: null | Component;
|
|
61
31
|
d: null | Dependency;
|
|
@@ -18,7 +18,16 @@ import {
|
|
|
18
18
|
ROOT_BLOCK,
|
|
19
19
|
CAUGHT_ERROR,
|
|
20
20
|
} from './constants.js';
|
|
21
|
-
import {
|
|
21
|
+
import {
|
|
22
|
+
run_block,
|
|
23
|
+
active_block,
|
|
24
|
+
active_component,
|
|
25
|
+
Output,
|
|
26
|
+
set_active_block,
|
|
27
|
+
TrackAsyncRunError,
|
|
28
|
+
create_public_track_async_error,
|
|
29
|
+
serialize_track_async_error,
|
|
30
|
+
} from './index.js';
|
|
22
31
|
|
|
23
32
|
/**
|
|
24
33
|
* @param {number} flags
|
|
@@ -90,6 +99,17 @@ export function try_block(try_fn, catch_fn = null, pending_fn = null) {
|
|
|
90
99
|
if (created_block.f & TRY_CATCH_BLOCK) {
|
|
91
100
|
created_block.o.clear();
|
|
92
101
|
cancel_async_operations(created_block);
|
|
102
|
+
|
|
103
|
+
// make sure to serialize trackAsync error so the client can hydrate them properly
|
|
104
|
+
// needs to happen after clearing output
|
|
105
|
+
if (error instanceof TrackAsyncRunError) {
|
|
106
|
+
var { tracked: t, cause } = /** @type {InstanceType<typeof TrackAsyncRunError>} */ (error);
|
|
107
|
+
var public_error = create_public_track_async_error(cause);
|
|
108
|
+
catch_fn?.(public_error);
|
|
109
|
+
serialize_track_async_error(t.h, public_error);
|
|
110
|
+
return created_block;
|
|
111
|
+
}
|
|
112
|
+
|
|
93
113
|
// render the catch
|
|
94
114
|
catch_fn?.(/** @type {SSRError} */ (error));
|
|
95
115
|
} else {
|