@qwik.dev/core 2.0.0-beta.8 → 2.0.0-beta.9
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/bindings/qwik.darwin-arm64.node +0 -0
- package/bindings/qwik.darwin-x64.node +0 -0
- package/bindings/qwik.linux-x64-gnu.node +0 -0
- package/bindings/qwik.win32-x64-msvc.node +0 -0
- package/bindings/qwik_wasm_bg.wasm +0 -0
- package/dist/backpatch/index.cjs +6 -0
- package/dist/backpatch/index.d.ts +2 -0
- package/dist/backpatch/index.mjs +5 -0
- package/dist/backpatch/package.json +8 -0
- package/dist/backpatch-executor.debug.js +34 -0
- package/dist/backpatch-executor.js +1 -0
- package/dist/build/package.json +1 -1
- package/dist/cli.cjs +2 -2
- package/dist/core-internal.d.ts +105 -55
- package/dist/core.cjs +976 -456
- package/dist/core.cjs.map +1 -1
- package/dist/core.min.mjs +1 -1
- package/dist/core.mjs +974 -456
- package/dist/core.mjs.map +1 -1
- package/dist/core.prod.cjs +638 -351
- package/dist/core.prod.mjs +709 -362
- package/dist/loader/package.json +1 -1
- package/dist/optimizer.cjs +75 -73
- package/dist/optimizer.mjs +75 -75
- package/dist/server.cjs +143 -42
- package/dist/server.d.ts +9 -0
- package/dist/server.mjs +140 -42
- package/dist/testing/index.cjs +3749 -927
- package/dist/testing/index.d.ts +972 -1
- package/dist/testing/index.mjs +3735 -921
- package/dist/testing/package.json +1 -1
- package/package.json +4 -2
package/dist/core.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @license
|
|
3
|
-
* @qwik.dev/core 2.0.0-beta.
|
|
3
|
+
* @qwik.dev/core 2.0.0-beta.9-dev+6b582c7
|
|
4
4
|
* Copyright QwikDev. All Rights Reserved.
|
|
5
5
|
* Use of this source code is governed by an MIT-style license that can be
|
|
6
6
|
* found in the LICENSE file at https://github.com/QwikDev/qwik/blob/main/LICENSE
|
|
@@ -9,6 +9,13 @@ import { isDev, isServer, isBrowser } from '@qwik.dev/core/build';
|
|
|
9
9
|
export { isBrowser, isDev, isServer } from '@qwik.dev/core/build';
|
|
10
10
|
import { p } from '@qwik.dev/core/preloader';
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* QWIK_VERSION
|
|
14
|
+
*
|
|
15
|
+
* @public
|
|
16
|
+
*/
|
|
17
|
+
const version = "2.0.0-beta.9-dev+6b582c7";
|
|
18
|
+
|
|
12
19
|
// same as isDev but separate so we can test
|
|
13
20
|
const qDev = globalThis.qDev !== false;
|
|
14
21
|
const qInspector = globalThis.qInspector === true;
|
|
@@ -86,6 +93,9 @@ const isArray = (v) => {
|
|
|
86
93
|
const isString = (v) => {
|
|
87
94
|
return typeof v === 'string';
|
|
88
95
|
};
|
|
96
|
+
const isNumber$1 = (v) => {
|
|
97
|
+
return typeof v === 'number';
|
|
98
|
+
};
|
|
89
99
|
const isFunction = (v) => {
|
|
90
100
|
return typeof v === 'function';
|
|
91
101
|
};
|
|
@@ -288,13 +298,6 @@ const createPlatform = () => {
|
|
|
288
298
|
});
|
|
289
299
|
});
|
|
290
300
|
},
|
|
291
|
-
nextTick: (fn) => {
|
|
292
|
-
return new Promise((resolve) => {
|
|
293
|
-
setTimeout(() => {
|
|
294
|
-
resolve(fn());
|
|
295
|
-
});
|
|
296
|
-
});
|
|
297
|
-
},
|
|
298
301
|
chunkForSymbol(symbolName, chunk) {
|
|
299
302
|
return [symbolName, chunk ?? '_'];
|
|
300
303
|
},
|
|
@@ -552,6 +555,13 @@ class SignalImpl {
|
|
|
552
555
|
this.$container$ = container;
|
|
553
556
|
this.$untrackedValue$ = value;
|
|
554
557
|
}
|
|
558
|
+
/**
|
|
559
|
+
* Use this to force running subscribers, for example when the calculated value has mutated but
|
|
560
|
+
* remained the same object
|
|
561
|
+
*/
|
|
562
|
+
force() {
|
|
563
|
+
this.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */, null, this, this.$effects$);
|
|
564
|
+
}
|
|
555
565
|
get untrackedValue() {
|
|
556
566
|
return this.$untrackedValue$;
|
|
557
567
|
}
|
|
@@ -565,14 +575,7 @@ class SignalImpl {
|
|
|
565
575
|
set value(value) {
|
|
566
576
|
if (value !== this.$untrackedValue$) {
|
|
567
577
|
this.$untrackedValue$ = value;
|
|
568
|
-
|
|
569
|
-
triggerEffects(this.$container$, this, this.$effects$);
|
|
570
|
-
// this.$container$?.$scheduler$(
|
|
571
|
-
// ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS,
|
|
572
|
-
// null,
|
|
573
|
-
// this,
|
|
574
|
-
// this.$effects$
|
|
575
|
-
// );
|
|
578
|
+
this.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */, null, this, this.$effects$);
|
|
576
579
|
}
|
|
577
580
|
}
|
|
578
581
|
// prevent accidental use as value
|
|
@@ -634,12 +637,11 @@ class WrappedSignalImpl extends SignalImpl {
|
|
|
634
637
|
$funcStr$;
|
|
635
638
|
$flags$;
|
|
636
639
|
$hostElement$ = null;
|
|
637
|
-
$forceRunEffects$ = false;
|
|
638
640
|
[_EFFECT_BACK_REF] = null;
|
|
639
641
|
constructor(container, fn, args, fnStr,
|
|
640
642
|
// We need a separate flag to know when the computation needs running because
|
|
641
643
|
// we need the old value to know if effects need running after computation
|
|
642
|
-
flags = 1 /* SignalFlags.INVALID */ |
|
|
644
|
+
flags = 1 /* SignalFlags.INVALID */ | 4 /* WrappedSignalFlags.UNWRAP */) {
|
|
643
645
|
super(container, NEEDS_COMPUTATION);
|
|
644
646
|
this.$args$ = args;
|
|
645
647
|
this.$func$ = fn;
|
|
@@ -648,7 +650,6 @@ class WrappedSignalImpl extends SignalImpl {
|
|
|
648
650
|
}
|
|
649
651
|
invalidate() {
|
|
650
652
|
this.$flags$ |= 1 /* SignalFlags.INVALID */;
|
|
651
|
-
this.$forceRunEffects$ = false;
|
|
652
653
|
this.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */, this.$hostElement$, this, this.$effects$);
|
|
653
654
|
}
|
|
654
655
|
/**
|
|
@@ -656,29 +657,26 @@ class WrappedSignalImpl extends SignalImpl {
|
|
|
656
657
|
* remained the same object.
|
|
657
658
|
*/
|
|
658
659
|
force() {
|
|
659
|
-
this.$
|
|
660
|
+
this.$flags$ |= 2 /* SignalFlags.RUN_EFFECTS */;
|
|
660
661
|
this.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */, this.$hostElement$, this, this.$effects$);
|
|
661
662
|
}
|
|
662
663
|
get untrackedValue() {
|
|
663
|
-
|
|
664
|
-
if (didChange) {
|
|
665
|
-
this.$forceRunEffects$ = didChange;
|
|
666
|
-
}
|
|
664
|
+
this.$computeIfNeeded$();
|
|
667
665
|
assertFalse(this.$untrackedValue$ === NEEDS_COMPUTATION, 'Invalid state');
|
|
668
666
|
return this.$untrackedValue$;
|
|
669
667
|
}
|
|
670
668
|
$computeIfNeeded$() {
|
|
671
669
|
if (!(this.$flags$ & 1 /* SignalFlags.INVALID */)) {
|
|
672
|
-
return
|
|
670
|
+
return;
|
|
673
671
|
}
|
|
674
672
|
const untrackedValue = trackSignal(() => this.$func$(...this.$args$), this, "." /* EffectProperty.VNODE */, this.$container$);
|
|
675
|
-
// TODO: we should remove invalid flag here
|
|
673
|
+
// TODO: we should remove invalid flag here, but some tests are failing
|
|
676
674
|
// this.$flags$ &= ~SignalFlags.INVALID;
|
|
677
675
|
const didChange = untrackedValue !== this.$untrackedValue$;
|
|
678
676
|
if (didChange) {
|
|
677
|
+
this.$flags$ |= 2 /* SignalFlags.RUN_EFFECTS */;
|
|
679
678
|
this.$untrackedValue$ = untrackedValue;
|
|
680
679
|
}
|
|
681
|
-
return didChange;
|
|
682
680
|
}
|
|
683
681
|
// Make this signal read-only
|
|
684
682
|
set value(_) {
|
|
@@ -873,12 +871,26 @@ const _jsxBranch = (input) => {
|
|
|
873
871
|
};
|
|
874
872
|
/** @internal */
|
|
875
873
|
const _waitUntilRendered = (elm) => {
|
|
876
|
-
const
|
|
877
|
-
if (!
|
|
874
|
+
const container = _getQContainerElement(elm)?.qContainer;
|
|
875
|
+
if (!container) {
|
|
878
876
|
return Promise.resolve();
|
|
879
877
|
}
|
|
880
|
-
|
|
881
|
-
|
|
878
|
+
// Multi-cycle idle: loop WAIT_FOR_QUEUE until the flush epoch stays stable
|
|
879
|
+
// across an extra microtask, which signals that no new work re-scheduled.
|
|
880
|
+
return (async () => {
|
|
881
|
+
for (;;) {
|
|
882
|
+
await container.$scheduler$(255 /* ChoreType.WAIT_FOR_QUEUE */).$returnValue$;
|
|
883
|
+
const firstEpoch = container.$flushEpoch$ || 0;
|
|
884
|
+
// Give a microtask for any immediate follow-up scheduling to enqueue
|
|
885
|
+
await Promise.resolve();
|
|
886
|
+
const secondEpoch = container.$flushEpoch$ || 0;
|
|
887
|
+
// If no epoch change occurred during and after WAIT_FOR_QUEUE, we are idle.
|
|
888
|
+
if (firstEpoch === secondEpoch) {
|
|
889
|
+
return;
|
|
890
|
+
}
|
|
891
|
+
// Continue loop if epoch advanced, meaning more work flushed.
|
|
892
|
+
}
|
|
893
|
+
})();
|
|
882
894
|
};
|
|
883
895
|
|
|
884
896
|
/**
|
|
@@ -956,7 +968,7 @@ function jsxEventToHtmlAttribute(jsxEvent) {
|
|
|
956
968
|
}
|
|
957
969
|
return null; // Return null if not matching expected format
|
|
958
970
|
}
|
|
959
|
-
function eventNameToJsxEvent(eventName, prefix
|
|
971
|
+
function eventNameToJsxEvent(eventName, prefix) {
|
|
960
972
|
eventName = eventName.charAt(0).toUpperCase() + eventName.substring(1);
|
|
961
973
|
return prefix + eventName + EVENT_SUFFIX;
|
|
962
974
|
}
|
|
@@ -1245,13 +1257,6 @@ const isRecoverable = (err) => {
|
|
|
1245
1257
|
return true;
|
|
1246
1258
|
};
|
|
1247
1259
|
|
|
1248
|
-
/**
|
|
1249
|
-
* QWIK_VERSION
|
|
1250
|
-
*
|
|
1251
|
-
* @public
|
|
1252
|
-
*/
|
|
1253
|
-
const version = "2.0.0-beta.8-dev+434cd18";
|
|
1254
|
-
|
|
1255
1260
|
/** @internal */
|
|
1256
1261
|
const EMPTY_ARRAY = [];
|
|
1257
1262
|
const EMPTY_OBJ = {};
|
|
@@ -1392,7 +1397,7 @@ const useLexicalScope = () => {
|
|
|
1392
1397
|
*
|
|
1393
1398
|
* @internal
|
|
1394
1399
|
*/
|
|
1395
|
-
const
|
|
1400
|
+
const _run = (...args) => {
|
|
1396
1401
|
// This will already check container
|
|
1397
1402
|
const [runQrl] = useLexicalScope();
|
|
1398
1403
|
const context = getInvokeContext();
|
|
@@ -1406,7 +1411,9 @@ const queueQRL = (...args) => {
|
|
|
1406
1411
|
if (!scheduler) {
|
|
1407
1412
|
throw qError(1 /* QError.schedulerNotFound */);
|
|
1408
1413
|
}
|
|
1409
|
-
return
|
|
1414
|
+
// We don't return anything, the scheduler is in charge now
|
|
1415
|
+
const chore = scheduler(2 /* ChoreType.RUN_QRL */, hostElement, runQrl, args);
|
|
1416
|
+
return getChorePromise(chore);
|
|
1410
1417
|
};
|
|
1411
1418
|
|
|
1412
1419
|
/** @internal */
|
|
@@ -1530,13 +1537,12 @@ class ComputedSignalImpl extends SignalImpl {
|
|
|
1530
1537
|
*/
|
|
1531
1538
|
$computeQrl$;
|
|
1532
1539
|
$flags$;
|
|
1533
|
-
$forceRunEffects$ = false;
|
|
1534
1540
|
[_EFFECT_BACK_REF] = null;
|
|
1535
1541
|
constructor(container, fn,
|
|
1536
1542
|
// We need a separate flag to know when the computation needs running because
|
|
1537
1543
|
// we need the old value to know if effects need running after computation
|
|
1538
1544
|
flags = 1 /* SignalFlags.INVALID */ |
|
|
1539
|
-
|
|
1545
|
+
32 /* SerializationSignalFlags.SERIALIZATION_STRATEGY_ALWAYS */) {
|
|
1540
1546
|
// The value is used for comparison when signals trigger, which can only happen
|
|
1541
1547
|
// when it was calculated before. Therefore we can pass whatever we like.
|
|
1542
1548
|
super(container, NEEDS_COMPUTATION);
|
|
@@ -1545,7 +1551,6 @@ class ComputedSignalImpl extends SignalImpl {
|
|
|
1545
1551
|
}
|
|
1546
1552
|
invalidate() {
|
|
1547
1553
|
this.$flags$ |= 1 /* SignalFlags.INVALID */;
|
|
1548
|
-
this.$forceRunEffects$ = false;
|
|
1549
1554
|
this.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */, null, this, this.$effects$);
|
|
1550
1555
|
}
|
|
1551
1556
|
/**
|
|
@@ -1553,20 +1558,17 @@ class ComputedSignalImpl extends SignalImpl {
|
|
|
1553
1558
|
* remained the same object
|
|
1554
1559
|
*/
|
|
1555
1560
|
force() {
|
|
1556
|
-
this.$
|
|
1557
|
-
|
|
1561
|
+
this.$flags$ |= 2 /* SignalFlags.RUN_EFFECTS */;
|
|
1562
|
+
super.force();
|
|
1558
1563
|
}
|
|
1559
1564
|
get untrackedValue() {
|
|
1560
|
-
|
|
1561
|
-
if (didChange) {
|
|
1562
|
-
this.$forceRunEffects$ = didChange;
|
|
1563
|
-
}
|
|
1565
|
+
this.$computeIfNeeded$();
|
|
1564
1566
|
assertFalse(this.$untrackedValue$ === NEEDS_COMPUTATION, 'Invalid state');
|
|
1565
1567
|
return this.$untrackedValue$;
|
|
1566
1568
|
}
|
|
1567
1569
|
$computeIfNeeded$() {
|
|
1568
1570
|
if (!(this.$flags$ & 1 /* SignalFlags.INVALID */)) {
|
|
1569
|
-
return
|
|
1571
|
+
return;
|
|
1570
1572
|
}
|
|
1571
1573
|
const computeQrl = this.$computeQrl$;
|
|
1572
1574
|
throwIfQRLNotResolved(computeQrl);
|
|
@@ -1585,9 +1587,12 @@ class ComputedSignalImpl extends SignalImpl {
|
|
|
1585
1587
|
this.$flags$ &= ~1 /* SignalFlags.INVALID */;
|
|
1586
1588
|
const didChange = untrackedValue !== this.$untrackedValue$;
|
|
1587
1589
|
if (didChange) {
|
|
1590
|
+
// skip first computation when value is not changed
|
|
1591
|
+
if (this.$untrackedValue$ !== NEEDS_COMPUTATION) {
|
|
1592
|
+
this.$flags$ |= 2 /* SignalFlags.RUN_EFFECTS */;
|
|
1593
|
+
}
|
|
1588
1594
|
this.$untrackedValue$ = untrackedValue;
|
|
1589
1595
|
}
|
|
1590
|
-
return didChange;
|
|
1591
1596
|
}
|
|
1592
1597
|
finally {
|
|
1593
1598
|
if (ctx) {
|
|
@@ -1613,12 +1618,12 @@ class ComputedSignalImpl extends SignalImpl {
|
|
|
1613
1618
|
*/
|
|
1614
1619
|
class SerializerSignalImpl extends ComputedSignalImpl {
|
|
1615
1620
|
constructor(container, argQrl) {
|
|
1616
|
-
super(container, argQrl, 1 /* SignalFlags.INVALID */ |
|
|
1621
|
+
super(container, argQrl, 1 /* SignalFlags.INVALID */ | 32 /* SerializationSignalFlags.SERIALIZATION_STRATEGY_ALWAYS */);
|
|
1617
1622
|
}
|
|
1618
1623
|
$didInitialize$ = false;
|
|
1619
1624
|
$computeIfNeeded$() {
|
|
1620
1625
|
if (!(this.$flags$ & 1 /* SignalFlags.INVALID */)) {
|
|
1621
|
-
return
|
|
1626
|
+
return;
|
|
1622
1627
|
}
|
|
1623
1628
|
throwIfQRLNotResolved(this.$computeQrl$);
|
|
1624
1629
|
let arg = this.$computeQrl$.resolved;
|
|
@@ -1636,9 +1641,9 @@ class SerializerSignalImpl extends ComputedSignalImpl {
|
|
|
1636
1641
|
this.$flags$ &= -2 /* SignalFlags.INVALID */;
|
|
1637
1642
|
this.$didInitialize$ = true;
|
|
1638
1643
|
if (didChange) {
|
|
1644
|
+
this.$flags$ |= 2 /* SignalFlags.RUN_EFFECTS */;
|
|
1639
1645
|
this.$untrackedValue$ = untrackedValue;
|
|
1640
1646
|
}
|
|
1641
|
-
return didChange;
|
|
1642
1647
|
}
|
|
1643
1648
|
}
|
|
1644
1649
|
|
|
@@ -1648,6 +1653,28 @@ const getStoreHandler = (value) => {
|
|
|
1648
1653
|
const getStoreTarget = (value) => {
|
|
1649
1654
|
return value?.[STORE_TARGET] || null;
|
|
1650
1655
|
};
|
|
1656
|
+
/**
|
|
1657
|
+
* Force a store to recompute and schedule effects.
|
|
1658
|
+
*
|
|
1659
|
+
* @public
|
|
1660
|
+
*/
|
|
1661
|
+
const forceStoreEffects = (value, prop) => {
|
|
1662
|
+
const handler = getStoreHandler(value);
|
|
1663
|
+
if (handler) {
|
|
1664
|
+
handler.force(prop);
|
|
1665
|
+
}
|
|
1666
|
+
};
|
|
1667
|
+
/**
|
|
1668
|
+
* @returns True if the store has effects for the given prop
|
|
1669
|
+
* @internal
|
|
1670
|
+
*/
|
|
1671
|
+
const _hasStoreEffects = (value, prop) => {
|
|
1672
|
+
const handler = getStoreHandler(value);
|
|
1673
|
+
if (handler) {
|
|
1674
|
+
return (handler.$effects$?.get(prop)?.size ?? 0) > 0;
|
|
1675
|
+
}
|
|
1676
|
+
return false;
|
|
1677
|
+
};
|
|
1651
1678
|
/**
|
|
1652
1679
|
* Get the original object that was wrapped by the store. Useful if you want to clone a store
|
|
1653
1680
|
* (structuredClone, IndexedDB,...)
|
|
@@ -1686,7 +1713,12 @@ class StoreHandler {
|
|
|
1686
1713
|
toString() {
|
|
1687
1714
|
return '[Store]';
|
|
1688
1715
|
}
|
|
1716
|
+
force(prop) {
|
|
1717
|
+
const target = getStoreTarget(this);
|
|
1718
|
+
this.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */, null, this, getEffects(target, prop, this.$effects$));
|
|
1719
|
+
}
|
|
1689
1720
|
get(target, prop) {
|
|
1721
|
+
// TODO(perf): handle better `slice` calls
|
|
1690
1722
|
if (typeof prop === 'symbol') {
|
|
1691
1723
|
if (prop === STORE_TARGET) {
|
|
1692
1724
|
return target;
|
|
@@ -1749,7 +1781,11 @@ class StoreHandler {
|
|
|
1749
1781
|
if (typeof prop != 'string' || !delete target[prop]) {
|
|
1750
1782
|
return false;
|
|
1751
1783
|
}
|
|
1752
|
-
|
|
1784
|
+
if (!Array.isArray(target)) {
|
|
1785
|
+
// If the target is an array, we don't need to trigger effects.
|
|
1786
|
+
// Changing the length property will trigger effects.
|
|
1787
|
+
this.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */, null, this, getEffects(target, prop, this.$effects$));
|
|
1788
|
+
}
|
|
1753
1789
|
return true;
|
|
1754
1790
|
}
|
|
1755
1791
|
has(target, prop) {
|
|
@@ -1808,8 +1844,10 @@ function addStoreEffect(target, prop, store, effectSubscription) {
|
|
|
1808
1844
|
}
|
|
1809
1845
|
function setNewValueAndTriggerEffects(prop, value, target, currentStore) {
|
|
1810
1846
|
target[prop] = value;
|
|
1811
|
-
|
|
1812
|
-
|
|
1847
|
+
const effects = getEffects(target, prop, currentStore.$effects$);
|
|
1848
|
+
if (effects) {
|
|
1849
|
+
currentStore.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */, null, currentStore, effects);
|
|
1850
|
+
}
|
|
1813
1851
|
}
|
|
1814
1852
|
function getEffects(target, prop, storeEffects) {
|
|
1815
1853
|
let effectsToTrigger;
|
|
@@ -1937,7 +1975,7 @@ class AsyncComputedSignalImpl extends ComputedSignalImpl {
|
|
|
1937
1975
|
}
|
|
1938
1976
|
$computeIfNeeded$() {
|
|
1939
1977
|
if (!(this.$flags$ & 1 /* SignalFlags.INVALID */)) {
|
|
1940
|
-
return
|
|
1978
|
+
return;
|
|
1941
1979
|
}
|
|
1942
1980
|
const computeQrl = this.$computeQrl$;
|
|
1943
1981
|
throwIfQRLNotResolved(computeQrl);
|
|
@@ -1967,6 +2005,7 @@ class AsyncComputedSignalImpl extends ComputedSignalImpl {
|
|
|
1967
2005
|
this.$flags$ &= -2 /* SignalFlags.INVALID */;
|
|
1968
2006
|
const didChange = untrackedValue !== this.$untrackedValue$;
|
|
1969
2007
|
if (didChange) {
|
|
2008
|
+
this.$flags$ |= 2 /* SignalFlags.RUN_EFFECTS */;
|
|
1970
2009
|
this.$untrackedValue$ = untrackedValue;
|
|
1971
2010
|
}
|
|
1972
2011
|
return didChange;
|
|
@@ -2054,7 +2093,7 @@ const _wrapProp = (...args) => {
|
|
|
2054
2093
|
if (!(obj instanceof AsyncComputedSignalImpl)) {
|
|
2055
2094
|
assertEqual(prop, 'value', 'Left side is a signal, prop must be value');
|
|
2056
2095
|
}
|
|
2057
|
-
if (obj instanceof WrappedSignalImpl && obj.flags &
|
|
2096
|
+
if (obj instanceof WrappedSignalImpl && obj.flags & 4 /* WrappedSignalFlags.UNWRAP */) {
|
|
2058
2097
|
return obj;
|
|
2059
2098
|
}
|
|
2060
2099
|
return getWrapped(args);
|
|
@@ -2115,7 +2154,7 @@ function isSlotProp(prop) {
|
|
|
2115
2154
|
return !prop.startsWith('q:') && !prop.startsWith(NON_SERIALIZABLE_MARKER_PREFIX);
|
|
2116
2155
|
}
|
|
2117
2156
|
/** @internal */
|
|
2118
|
-
const _restProps = (props, omit, target = {}) => {
|
|
2157
|
+
const _restProps = (props, omit = [], target = {}) => {
|
|
2119
2158
|
let constPropsTarget = null;
|
|
2120
2159
|
const constProps = props[_CONST_PROPS];
|
|
2121
2160
|
if (constProps) {
|
|
@@ -2570,12 +2609,12 @@ function addUseOnEvents(jsx, useOnEvents) {
|
|
|
2570
2609
|
}
|
|
2571
2610
|
if (targetElement) {
|
|
2572
2611
|
if (targetElement.type === 'script' && key === qVisibleEvent) {
|
|
2573
|
-
eventKey = 'document:
|
|
2612
|
+
eventKey = 'document:onQInit$';
|
|
2574
2613
|
logWarn('You are trying to add an event "' +
|
|
2575
2614
|
key +
|
|
2576
2615
|
'" using `useVisibleTask$` hook, ' +
|
|
2577
2616
|
'but a node to which you can add an event is not found. ' +
|
|
2578
|
-
'Using document:
|
|
2617
|
+
'Using document:onQInit$ instead.');
|
|
2579
2618
|
}
|
|
2580
2619
|
addUseOnEvent(targetElement, eventKey, useOnEvents[key]);
|
|
2581
2620
|
}
|
|
@@ -2698,13 +2737,13 @@ const applyQwikComponentBody = (ssr, jsx, component) => {
|
|
|
2698
2737
|
if (srcProps && srcProps.children) {
|
|
2699
2738
|
delete srcProps.children;
|
|
2700
2739
|
}
|
|
2701
|
-
const scheduler = ssr.$scheduler$;
|
|
2702
2740
|
host.setProp(OnRenderProp, componentQrl);
|
|
2703
2741
|
host.setProp(ELEMENT_PROPS, srcProps);
|
|
2704
2742
|
if (jsx.key !== null) {
|
|
2705
2743
|
host.setProp(ELEMENT_KEY, jsx.key);
|
|
2706
2744
|
}
|
|
2707
|
-
|
|
2745
|
+
const componentChore = ssr.$scheduler$(6 /* ChoreType.COMPONENT */, host, componentQrl, srcProps);
|
|
2746
|
+
return getChorePromise(componentChore);
|
|
2708
2747
|
};
|
|
2709
2748
|
|
|
2710
2749
|
class ParentComponentData {
|
|
@@ -2812,7 +2851,14 @@ function processJSXNode(ssr, enqueue, value, options) {
|
|
|
2812
2851
|
appendQwikInspectorAttribute(jsx, qwikInspectorAttrValue);
|
|
2813
2852
|
}
|
|
2814
2853
|
}
|
|
2815
|
-
const innerHTML = ssr.openElement(type, varPropsToSsrAttrs(jsx.varProps, jsx.constProps,
|
|
2854
|
+
const innerHTML = ssr.openElement(type, varPropsToSsrAttrs(jsx.varProps, jsx.constProps, {
|
|
2855
|
+
serializationCtx: ssr.serializationCtx,
|
|
2856
|
+
styleScopedId: options.styleScoped,
|
|
2857
|
+
key: jsx.key,
|
|
2858
|
+
}), constPropsToSsrAttrs(jsx.constProps, jsx.varProps, {
|
|
2859
|
+
serializationCtx: ssr.serializationCtx,
|
|
2860
|
+
styleScopedId: options.styleScoped,
|
|
2861
|
+
}), qwikInspectorAttrValue);
|
|
2816
2862
|
if (innerHTML) {
|
|
2817
2863
|
ssr.htmlNode(innerHTML);
|
|
2818
2864
|
}
|
|
@@ -2928,16 +2974,17 @@ function processJSXNode(ssr, enqueue, value, options) {
|
|
|
2928
2974
|
}
|
|
2929
2975
|
}
|
|
2930
2976
|
}
|
|
2931
|
-
function varPropsToSsrAttrs(varProps, constProps,
|
|
2932
|
-
return toSsrAttrs(varProps, constProps,
|
|
2977
|
+
function varPropsToSsrAttrs(varProps, constProps, options) {
|
|
2978
|
+
return toSsrAttrs(varProps, constProps, false, options);
|
|
2933
2979
|
}
|
|
2934
|
-
function constPropsToSsrAttrs(constProps, varProps,
|
|
2935
|
-
return toSsrAttrs(constProps, varProps,
|
|
2980
|
+
function constPropsToSsrAttrs(constProps, varProps, options) {
|
|
2981
|
+
return toSsrAttrs(constProps, varProps, true, options);
|
|
2936
2982
|
}
|
|
2937
|
-
function toSsrAttrs(record, anotherRecord,
|
|
2983
|
+
function toSsrAttrs(record, anotherRecord, isConst, options) {
|
|
2938
2984
|
if (record == null) {
|
|
2939
2985
|
return null;
|
|
2940
2986
|
}
|
|
2987
|
+
const pushMergedEventProps = !isConst;
|
|
2941
2988
|
const ssrAttrs = [];
|
|
2942
2989
|
for (const key in record) {
|
|
2943
2990
|
let value = record[key];
|
|
@@ -2974,7 +3021,7 @@ function toSsrAttrs(record, anotherRecord, serializationCtx, pushMergedEventProp
|
|
|
2974
3021
|
}
|
|
2975
3022
|
}
|
|
2976
3023
|
}
|
|
2977
|
-
const eventValue = setEvent(serializationCtx, key, value);
|
|
3024
|
+
const eventValue = setEvent(options.serializationCtx, key, value);
|
|
2978
3025
|
if (eventValue) {
|
|
2979
3026
|
ssrAttrs.push(jsxEventToHtmlAttribute(key), eventValue);
|
|
2980
3027
|
}
|
|
@@ -2984,7 +3031,7 @@ function toSsrAttrs(record, anotherRecord, serializationCtx, pushMergedEventProp
|
|
|
2984
3031
|
// write signal as is. We will track this signal inside `writeAttrs`
|
|
2985
3032
|
if (isClassAttr(key)) {
|
|
2986
3033
|
// additionally append styleScopedId for class attr
|
|
2987
|
-
ssrAttrs.push(key, [value, styleScopedId]);
|
|
3034
|
+
ssrAttrs.push(key, [value, options.styleScopedId]);
|
|
2988
3035
|
}
|
|
2989
3036
|
else {
|
|
2990
3037
|
ssrAttrs.push(key, value);
|
|
@@ -2992,13 +3039,13 @@ function toSsrAttrs(record, anotherRecord, serializationCtx, pushMergedEventProp
|
|
|
2992
3039
|
continue;
|
|
2993
3040
|
}
|
|
2994
3041
|
if (isPreventDefault(key)) {
|
|
2995
|
-
addPreventDefaultEventToSerializationContext(serializationCtx, key);
|
|
3042
|
+
addPreventDefaultEventToSerializationContext(options.serializationCtx, key);
|
|
2996
3043
|
}
|
|
2997
|
-
value = serializeAttribute(key, value, styleScopedId);
|
|
3044
|
+
value = serializeAttribute(key, value, options.styleScopedId);
|
|
2998
3045
|
ssrAttrs.push(key, value);
|
|
2999
3046
|
}
|
|
3000
|
-
if (key != null) {
|
|
3001
|
-
ssrAttrs.push(ELEMENT_KEY, key);
|
|
3047
|
+
if (options.key != null) {
|
|
3048
|
+
ssrAttrs.push(ELEMENT_KEY, options.key);
|
|
3002
3049
|
}
|
|
3003
3050
|
return ssrAttrs;
|
|
3004
3051
|
}
|
|
@@ -3047,7 +3094,7 @@ function setEvent(serializationCtx, key, rawValue) {
|
|
|
3047
3094
|
* For internal qrls (starting with `_`) we assume that they do the right thing.
|
|
3048
3095
|
*/
|
|
3049
3096
|
if (!qrl.$symbol$.startsWith('_') && (qrl.$captureRef$ || qrl.$capture$)) {
|
|
3050
|
-
qrl = createQRL(null, '_run',
|
|
3097
|
+
qrl = createQRL(null, '_run', _run, null, null, [qrl]);
|
|
3051
3098
|
}
|
|
3052
3099
|
return qrlToString(serializationCtx, qrl);
|
|
3053
3100
|
};
|
|
@@ -3127,10 +3174,9 @@ const useTaskQrl = (qrl) => {
|
|
|
3127
3174
|
// deleted and we need to be able to release the task subscriptions.
|
|
3128
3175
|
set(task);
|
|
3129
3176
|
const container = iCtx.$container$;
|
|
3130
|
-
const
|
|
3131
|
-
if (isPromise(
|
|
3132
|
-
|
|
3133
|
-
promise.catch(() => { });
|
|
3177
|
+
const result = runTask(task, container, iCtx.$hostElement$);
|
|
3178
|
+
if (isPromise(result)) {
|
|
3179
|
+
throw result;
|
|
3134
3180
|
}
|
|
3135
3181
|
};
|
|
3136
3182
|
const runTask = (task, container, host) => {
|
|
@@ -3142,7 +3188,7 @@ const runTask = (task, container, host) => {
|
|
|
3142
3188
|
const track = trackFn(task, container);
|
|
3143
3189
|
const [cleanup] = cleanupFn(task, (reason) => container.handleError(reason, host));
|
|
3144
3190
|
const taskApi = { track, cleanup };
|
|
3145
|
-
|
|
3191
|
+
return safeCall(() => taskFn(taskApi), cleanup, (err) => {
|
|
3146
3192
|
// If a Promise is thrown, that means we need to re-run the task.
|
|
3147
3193
|
if (isPromise(err)) {
|
|
3148
3194
|
return err.then(() => runTask(task, container, host));
|
|
@@ -3151,7 +3197,6 @@ const runTask = (task, container, host) => {
|
|
|
3151
3197
|
throw err;
|
|
3152
3198
|
}
|
|
3153
3199
|
});
|
|
3154
|
-
return result;
|
|
3155
3200
|
};
|
|
3156
3201
|
const cleanupTask = (task) => {
|
|
3157
3202
|
const destroy = task.$destroy$;
|
|
@@ -3193,7 +3238,7 @@ const isTask = (value) => {
|
|
|
3193
3238
|
*/
|
|
3194
3239
|
const scheduleTask = (_event, element) => {
|
|
3195
3240
|
const [task] = useLexicalScope();
|
|
3196
|
-
const type = task.$flags$ & 1 /* TaskFlags.VISIBLE_TASK */ ?
|
|
3241
|
+
const type = task.$flags$ & 1 /* TaskFlags.VISIBLE_TASK */ ? 16 /* ChoreType.VISIBLE */ : 3 /* ChoreType.TASK */;
|
|
3197
3242
|
const container = getDomContainer(element);
|
|
3198
3243
|
container.$scheduler$(type, task);
|
|
3199
3244
|
};
|
|
@@ -3445,7 +3490,7 @@ class PropsProxyHandler {
|
|
|
3445
3490
|
? this.$constProps$[prop]
|
|
3446
3491
|
: this.$varProps$[prop];
|
|
3447
3492
|
// a proxied value that the optimizer made
|
|
3448
|
-
return value instanceof WrappedSignalImpl && value.$flags$ &
|
|
3493
|
+
return value instanceof WrappedSignalImpl && value.$flags$ & 4 /* WrappedSignalFlags.UNWRAP */
|
|
3449
3494
|
? value.value
|
|
3450
3495
|
: value;
|
|
3451
3496
|
}
|
|
@@ -3859,6 +3904,10 @@ const vnode_diff = (container, jsxNode, vStartNode, scopedStyleIdPrefix) => {
|
|
|
3859
3904
|
vNewNode = null;
|
|
3860
3905
|
vCurrent = vnode_getFirstChild(vStartNode);
|
|
3861
3906
|
stackPush(jsxNode, true);
|
|
3907
|
+
if (vParent[0 /* VNodeProps.flags */] & 32 /* VNodeFlags.Deleted */) {
|
|
3908
|
+
// Ignore diff if the parent is deleted.
|
|
3909
|
+
return;
|
|
3910
|
+
}
|
|
3862
3911
|
while (stack.length) {
|
|
3863
3912
|
while (jsxIdx < jsxCount) {
|
|
3864
3913
|
assertFalse(vParent === vCurrent, "Parent and current can't be the same");
|
|
@@ -4391,8 +4440,13 @@ const vnode_diff = (container, jsxNode, vStartNode, scopedStyleIdPrefix) => {
|
|
|
4391
4440
|
let returnValue = false;
|
|
4392
4441
|
qrls.flat(2).forEach((qrl) => {
|
|
4393
4442
|
if (qrl) {
|
|
4394
|
-
|
|
4395
|
-
|
|
4443
|
+
if (isSyncQrl(qrl)) {
|
|
4444
|
+
qrl(event, element);
|
|
4445
|
+
}
|
|
4446
|
+
else {
|
|
4447
|
+
const value = container.$scheduler$(2 /* ChoreType.RUN_QRL */, vNode, qrl, [event, element]);
|
|
4448
|
+
returnValue = returnValue || value === true;
|
|
4449
|
+
}
|
|
4396
4450
|
}
|
|
4397
4451
|
});
|
|
4398
4452
|
return returnValue;
|
|
@@ -4894,7 +4948,7 @@ function cleanup(container, vNode) {
|
|
|
4894
4948
|
const task = obj;
|
|
4895
4949
|
clearAllEffects(container, task);
|
|
4896
4950
|
if (task.$flags$ & 1 /* TaskFlags.VISIBLE_TASK */) {
|
|
4897
|
-
container.$scheduler$(
|
|
4951
|
+
container.$scheduler$(32 /* ChoreType.CLEANUP_VISIBLE */, task);
|
|
4898
4952
|
}
|
|
4899
4953
|
else {
|
|
4900
4954
|
cleanupTask(task);
|
|
@@ -4945,7 +4999,16 @@ function cleanup(container, vNode) {
|
|
|
4945
4999
|
*/
|
|
4946
5000
|
const vFirstChild = vnode_getFirstChild(vCursor);
|
|
4947
5001
|
if (vFirstChild) {
|
|
4948
|
-
vnode_walkVNode(vFirstChild)
|
|
5002
|
+
vnode_walkVNode(vFirstChild, (vNode) => {
|
|
5003
|
+
/**
|
|
5004
|
+
* Instead of an ID, we store a direct reference to the VNode. This is necessary to
|
|
5005
|
+
* locate the slot's parent in a detached subtree, as the ID would become invalid.
|
|
5006
|
+
*/
|
|
5007
|
+
if (vNode[0 /* VNodeProps.flags */] & 2 /* VNodeFlags.Virtual */) {
|
|
5008
|
+
// The QSlotParent is used to find the slot parent during scheduling
|
|
5009
|
+
vnode_getProp(vNode, QSlotParent, (id) => vnode_locate(container.rootVNode, id));
|
|
5010
|
+
}
|
|
5011
|
+
});
|
|
4949
5012
|
return;
|
|
4950
5013
|
}
|
|
4951
5014
|
}
|
|
@@ -5022,8 +5085,8 @@ const useResourceQrl = (qrl, opts) => {
|
|
|
5022
5085
|
const resource = createResourceReturn(container, opts);
|
|
5023
5086
|
const el = iCtx.$hostElement$;
|
|
5024
5087
|
const task = new Task(8 /* TaskFlags.DIRTY */ | 4 /* TaskFlags.RESOURCE */, i, el, qrl, resource, null);
|
|
5025
|
-
container.$scheduler$(3 /* ChoreType.TASK */, task);
|
|
5026
5088
|
set(resource);
|
|
5089
|
+
runResource(task, container, el);
|
|
5027
5090
|
return resource;
|
|
5028
5091
|
};
|
|
5029
5092
|
// <docs markdown="../readme.md#useResource">
|
|
@@ -5091,10 +5154,10 @@ const Resource = (props) => {
|
|
|
5091
5154
|
function getResourceValueAsPromise(props) {
|
|
5092
5155
|
const resource = props.value;
|
|
5093
5156
|
if (isResourceReturn(resource)) {
|
|
5157
|
+
// create a subscription for the resource._state changes
|
|
5158
|
+
const state = resource._state;
|
|
5094
5159
|
const isBrowser = !isServerPlatform();
|
|
5095
5160
|
if (isBrowser) {
|
|
5096
|
-
// create a subscription for the resource._state changes
|
|
5097
|
-
const state = resource._state;
|
|
5098
5161
|
if (state === 'pending' && props.onPending) {
|
|
5099
5162
|
return Promise.resolve().then(useBindInvokeContext(props.onPending));
|
|
5100
5163
|
}
|
|
@@ -5109,14 +5172,7 @@ function getResourceValueAsPromise(props) {
|
|
|
5109
5172
|
}
|
|
5110
5173
|
}
|
|
5111
5174
|
}
|
|
5112
|
-
|
|
5113
|
-
if (value) {
|
|
5114
|
-
return value.then(useBindInvokeContext(props.onResolved), useBindInvokeContext(props.onRejected));
|
|
5115
|
-
}
|
|
5116
|
-
else {
|
|
5117
|
-
// this is temporary value until the `runResource` is executed and promise is assigned to the value
|
|
5118
|
-
return Promise.resolve(undefined);
|
|
5119
|
-
}
|
|
5175
|
+
return untrack(() => resource.value).then(useBindInvokeContext(props.onResolved), useBindInvokeContext(props.onRejected));
|
|
5120
5176
|
}
|
|
5121
5177
|
else if (isPromise(resource)) {
|
|
5122
5178
|
return resource.then(useBindInvokeContext(props.onResolved), useBindInvokeContext(props.onRejected));
|
|
@@ -5134,7 +5190,7 @@ const _createResourceReturn = (opts) => {
|
|
|
5134
5190
|
const resource = {
|
|
5135
5191
|
__brand: 'resource',
|
|
5136
5192
|
value: undefined,
|
|
5137
|
-
loading: isServerPlatform()
|
|
5193
|
+
loading: !isServerPlatform(),
|
|
5138
5194
|
_resolved: undefined,
|
|
5139
5195
|
_error: undefined,
|
|
5140
5196
|
_state: 'pending',
|
|
@@ -5185,19 +5241,22 @@ const runResource = (task, container, host) => {
|
|
|
5185
5241
|
done = true;
|
|
5186
5242
|
if (resolved) {
|
|
5187
5243
|
done = true;
|
|
5188
|
-
|
|
5189
|
-
|
|
5190
|
-
|
|
5191
|
-
|
|
5244
|
+
resourceTarget.loading = false;
|
|
5245
|
+
resourceTarget._state = 'resolved';
|
|
5246
|
+
resourceTarget._resolved = value;
|
|
5247
|
+
resourceTarget._error = undefined;
|
|
5192
5248
|
resolve(value);
|
|
5193
5249
|
}
|
|
5194
5250
|
else {
|
|
5195
5251
|
done = true;
|
|
5196
|
-
|
|
5197
|
-
|
|
5198
|
-
|
|
5252
|
+
resourceTarget.loading = false;
|
|
5253
|
+
resourceTarget._state = 'rejected';
|
|
5254
|
+
resourceTarget._error = value;
|
|
5199
5255
|
reject(value);
|
|
5200
5256
|
}
|
|
5257
|
+
if (!isServerPlatform()) {
|
|
5258
|
+
forceStoreEffects(resource, '_state');
|
|
5259
|
+
}
|
|
5201
5260
|
return true;
|
|
5202
5261
|
}
|
|
5203
5262
|
return false;
|
|
@@ -5213,17 +5272,17 @@ const runResource = (task, container, host) => {
|
|
|
5213
5272
|
}
|
|
5214
5273
|
});
|
|
5215
5274
|
// Execute mutation inside empty invocation
|
|
5275
|
+
// TODO: is it right? why we need to invoke inside context and trigger effects?
|
|
5216
5276
|
invoke(iCtx, () => {
|
|
5217
5277
|
// console.log('RESOURCE.pending: ');
|
|
5218
5278
|
resource._state = 'pending';
|
|
5219
5279
|
resource.loading = !isServerPlatform();
|
|
5220
|
-
|
|
5280
|
+
resource.value = new Promise((r, re) => {
|
|
5221
5281
|
resolve = r;
|
|
5222
5282
|
reject = re;
|
|
5223
|
-
})
|
|
5224
|
-
promise.catch(ignoreErrorToPreventNodeFromCrashing);
|
|
5283
|
+
});
|
|
5225
5284
|
});
|
|
5226
|
-
const promise = safeCall(() =>
|
|
5285
|
+
const promise = safeCall(() => taskFn(opts), (value) => {
|
|
5227
5286
|
setState(true, value);
|
|
5228
5287
|
}, (err) => {
|
|
5229
5288
|
if (isPromise(err)) {
|
|
@@ -5246,10 +5305,6 @@ const runResource = (task, container, host) => {
|
|
|
5246
5305
|
}
|
|
5247
5306
|
return promise;
|
|
5248
5307
|
};
|
|
5249
|
-
const ignoreErrorToPreventNodeFromCrashing = (err) => {
|
|
5250
|
-
// ignore error to prevent node from crashing
|
|
5251
|
-
// node will crash in promise is rejected and no one is listening to the rejection.
|
|
5252
|
-
};
|
|
5253
5308
|
|
|
5254
5309
|
/// These global variables are used to avoid creating new arrays for each call to `vnode_documentPosition`.
|
|
5255
5310
|
const aVNodePath = [];
|
|
@@ -5332,11 +5387,11 @@ const ssrNodeDocumentPosition = (a, b) => {
|
|
|
5332
5387
|
let bDepth = -1;
|
|
5333
5388
|
while (a) {
|
|
5334
5389
|
const ssrNode = (aSsrNodePath[++aDepth] = a);
|
|
5335
|
-
a = ssrNode.
|
|
5390
|
+
a = ssrNode.parentComponent;
|
|
5336
5391
|
}
|
|
5337
5392
|
while (b) {
|
|
5338
5393
|
const ssrNode = (bSsrNodePath[++bDepth] = b);
|
|
5339
|
-
b = ssrNode.
|
|
5394
|
+
b = ssrNode.parentComponent;
|
|
5340
5395
|
}
|
|
5341
5396
|
while (aDepth >= 0 && bDepth >= 0) {
|
|
5342
5397
|
a = aSsrNodePath[aDepth];
|
|
@@ -5353,6 +5408,210 @@ const ssrNodeDocumentPosition = (a, b) => {
|
|
|
5353
5408
|
return aDepth < bDepth ? -1 : 1;
|
|
5354
5409
|
};
|
|
5355
5410
|
|
|
5411
|
+
/**
|
|
5412
|
+
* Rules for determining if a chore is blocked by another chore. Some chores can block other chores.
|
|
5413
|
+
* They cannot run until the blocking chore has completed.
|
|
5414
|
+
*
|
|
5415
|
+
* The match function is used to determine if the blocked chore is blocked by the blocking chore.
|
|
5416
|
+
* The match function is called with the blocked chore, the blocking chore, and the container.
|
|
5417
|
+
*/
|
|
5418
|
+
const VISIBLE_BLOCKING_RULES = [
|
|
5419
|
+
// NODE_DIFF blocks VISIBLE on same host,
|
|
5420
|
+
// if the blocked chore is a child of the blocking chore
|
|
5421
|
+
// or the blocked chore is a sibling of the blocking chore
|
|
5422
|
+
{
|
|
5423
|
+
blockedType: 16 /* ChoreType.VISIBLE */,
|
|
5424
|
+
blockingType: 4 /* ChoreType.NODE_DIFF */,
|
|
5425
|
+
match: (blocked, blocking, container) => isDescendant(blocked, blocking, container) || isDescendant(blocking, blocked, container),
|
|
5426
|
+
},
|
|
5427
|
+
// COMPONENT blocks VISIBLE on same host
|
|
5428
|
+
// if the blocked chore is a child of the blocking chore
|
|
5429
|
+
// or the blocked chore is a sibling of the blocking chore
|
|
5430
|
+
{
|
|
5431
|
+
blockedType: 16 /* ChoreType.VISIBLE */,
|
|
5432
|
+
blockingType: 6 /* ChoreType.COMPONENT */,
|
|
5433
|
+
match: (blocked, blocking, container) => isDescendant(blocked, blocking, container) || isDescendant(blocking, blocked, container),
|
|
5434
|
+
},
|
|
5435
|
+
];
|
|
5436
|
+
const BLOCKING_RULES = [
|
|
5437
|
+
// QRL_RESOLVE blocks RUN_QRL, TASK, VISIBLE on same host
|
|
5438
|
+
{
|
|
5439
|
+
blockedType: 2 /* ChoreType.RUN_QRL */,
|
|
5440
|
+
blockingType: 1 /* ChoreType.QRL_RESOLVE */,
|
|
5441
|
+
match: (blocked, blocking) => {
|
|
5442
|
+
const blockedQrl = blocked.$target$;
|
|
5443
|
+
const blockingQrl = blocking.$target$;
|
|
5444
|
+
return isSameHost(blocked, blocking) && isSameQrl(blockedQrl, blockingQrl);
|
|
5445
|
+
},
|
|
5446
|
+
},
|
|
5447
|
+
{
|
|
5448
|
+
blockedType: 3 /* ChoreType.TASK */,
|
|
5449
|
+
blockingType: 1 /* ChoreType.QRL_RESOLVE */,
|
|
5450
|
+
match: (blocked, blocking) => {
|
|
5451
|
+
const blockedTask = blocked.$payload$;
|
|
5452
|
+
const blockingQrl = blocking.$target$;
|
|
5453
|
+
return isSameHost(blocked, blocking) && isSameQrl(blockedTask.$qrl$, blockingQrl);
|
|
5454
|
+
},
|
|
5455
|
+
},
|
|
5456
|
+
{
|
|
5457
|
+
blockedType: 16 /* ChoreType.VISIBLE */,
|
|
5458
|
+
blockingType: 1 /* ChoreType.QRL_RESOLVE */,
|
|
5459
|
+
match: (blocked, blocking) => {
|
|
5460
|
+
const blockedTask = blocked.$payload$;
|
|
5461
|
+
const blockingQrl = blocking.$target$;
|
|
5462
|
+
return isSameHost(blocked, blocking) && isSameQrl(blockedTask.$qrl$, blockingQrl);
|
|
5463
|
+
},
|
|
5464
|
+
},
|
|
5465
|
+
// COMPONENT blocks NODE_DIFF, NODE_PROP on same host
|
|
5466
|
+
{
|
|
5467
|
+
blockedType: 4 /* ChoreType.NODE_DIFF */,
|
|
5468
|
+
blockingType: 6 /* ChoreType.COMPONENT */,
|
|
5469
|
+
match: (blocked, blocking) => blocked.$host$ === blocking.$host$,
|
|
5470
|
+
},
|
|
5471
|
+
{
|
|
5472
|
+
blockedType: 5 /* ChoreType.NODE_PROP */,
|
|
5473
|
+
blockingType: 6 /* ChoreType.COMPONENT */,
|
|
5474
|
+
match: (blocked, blocking) => blocked.$host$ === blocking.$host$,
|
|
5475
|
+
},
|
|
5476
|
+
...VISIBLE_BLOCKING_RULES,
|
|
5477
|
+
// TASK blocks subsequent TASKs in the same component
|
|
5478
|
+
{
|
|
5479
|
+
blockedType: 3 /* ChoreType.TASK */,
|
|
5480
|
+
blockingType: 3 /* ChoreType.TASK */,
|
|
5481
|
+
match: (blocked, blocking, container) => {
|
|
5482
|
+
if (blocked.$host$ !== blocking.$host$) {
|
|
5483
|
+
return false;
|
|
5484
|
+
}
|
|
5485
|
+
const blockedIdx = blocked.$idx$;
|
|
5486
|
+
if (!isNumber$1(blockedIdx) || blockedIdx <= 0) {
|
|
5487
|
+
return false;
|
|
5488
|
+
}
|
|
5489
|
+
const previousTask = findPreviousTaskInComponent(blocked.$host$, blockedIdx, container);
|
|
5490
|
+
return previousTask === blocking.$payload$;
|
|
5491
|
+
},
|
|
5492
|
+
},
|
|
5493
|
+
];
|
|
5494
|
+
function isDescendant(descendantChore, ancestorChore, container) {
|
|
5495
|
+
const descendantHost = descendantChore.$host$;
|
|
5496
|
+
const ancestorHost = ancestorChore.$host$;
|
|
5497
|
+
if (!vnode_isVNode(descendantHost) || !vnode_isVNode(ancestorHost)) {
|
|
5498
|
+
return false;
|
|
5499
|
+
}
|
|
5500
|
+
return vnode_isDescendantOf(descendantHost, ancestorHost, container.rootVNode);
|
|
5501
|
+
}
|
|
5502
|
+
function isSameHost(a, b) {
|
|
5503
|
+
return a.$host$ === b.$host$;
|
|
5504
|
+
}
|
|
5505
|
+
function isSameQrl(a, b) {
|
|
5506
|
+
return a.$symbol$ === b.$symbol$;
|
|
5507
|
+
}
|
|
5508
|
+
function findBlockingChoreInQueue(chore, choreQueue, container) {
|
|
5509
|
+
for (const candidate of choreQueue) {
|
|
5510
|
+
// everything after VISIBLE is not blocking. Visible task, task and resource should not block anything in this rule.
|
|
5511
|
+
if (candidate.$type$ >= 16 /* ChoreType.VISIBLE */ || candidate.$type$ === 3 /* ChoreType.TASK */) {
|
|
5512
|
+
continue;
|
|
5513
|
+
}
|
|
5514
|
+
if (isDescendant(chore, candidate, container)) {
|
|
5515
|
+
return candidate;
|
|
5516
|
+
}
|
|
5517
|
+
}
|
|
5518
|
+
return null;
|
|
5519
|
+
}
|
|
5520
|
+
function findBlockingChore(chore, choreQueue, blockedChores, runningChores, container) {
|
|
5521
|
+
const blockingChoreInChoreQueue = findBlockingChoreInQueue(chore, choreQueue, container);
|
|
5522
|
+
if (blockingChoreInChoreQueue) {
|
|
5523
|
+
return blockingChoreInChoreQueue;
|
|
5524
|
+
}
|
|
5525
|
+
const blockingChoreInBlockedChores = findBlockingChoreInQueue(chore, Array.from(blockedChores), container);
|
|
5526
|
+
if (blockingChoreInBlockedChores) {
|
|
5527
|
+
return blockingChoreInBlockedChores;
|
|
5528
|
+
}
|
|
5529
|
+
const blockingChoreInRunningChores = findBlockingChoreInQueue(chore, Array.from(runningChores), container);
|
|
5530
|
+
if (blockingChoreInRunningChores) {
|
|
5531
|
+
return blockingChoreInRunningChores;
|
|
5532
|
+
}
|
|
5533
|
+
for (const rule of BLOCKING_RULES) {
|
|
5534
|
+
if (chore.$type$ !== rule.blockedType) {
|
|
5535
|
+
continue;
|
|
5536
|
+
}
|
|
5537
|
+
// Check in choreQueue
|
|
5538
|
+
// TODO(perf): better to iterate in reverse order?
|
|
5539
|
+
for (const candidate of choreQueue) {
|
|
5540
|
+
if (candidate.$type$ === rule.blockingType && rule.match(chore, candidate, container)) {
|
|
5541
|
+
return candidate;
|
|
5542
|
+
}
|
|
5543
|
+
}
|
|
5544
|
+
// Check in blockedChores
|
|
5545
|
+
for (const candidate of blockedChores) {
|
|
5546
|
+
if (candidate.$type$ === rule.blockingType && rule.match(chore, candidate, container)) {
|
|
5547
|
+
return candidate;
|
|
5548
|
+
}
|
|
5549
|
+
}
|
|
5550
|
+
// Check in runningChores
|
|
5551
|
+
for (const candidate of runningChores) {
|
|
5552
|
+
if (candidate.$type$ === rule.blockingType && rule.match(chore, candidate, container)) {
|
|
5553
|
+
return candidate;
|
|
5554
|
+
}
|
|
5555
|
+
}
|
|
5556
|
+
}
|
|
5557
|
+
return null;
|
|
5558
|
+
}
|
|
5559
|
+
function findPreviousTaskInComponent(host, currentTaskIdx, container) {
|
|
5560
|
+
const elementSeq = container.getHostProp(host, ELEMENT_SEQ);
|
|
5561
|
+
if (!elementSeq || elementSeq.length <= currentTaskIdx) {
|
|
5562
|
+
return null;
|
|
5563
|
+
}
|
|
5564
|
+
for (let i = currentTaskIdx - 1; i >= 0; i--) {
|
|
5565
|
+
const candidate = elementSeq[i];
|
|
5566
|
+
if (candidate instanceof Task && candidate.$flags$ & 2 /* TaskFlags.TASK */) {
|
|
5567
|
+
return candidate;
|
|
5568
|
+
}
|
|
5569
|
+
}
|
|
5570
|
+
return null;
|
|
5571
|
+
}
|
|
5572
|
+
function findBlockingChoreForVisible(chore, runningChores, container) {
|
|
5573
|
+
for (const rule of VISIBLE_BLOCKING_RULES) {
|
|
5574
|
+
if (chore.$type$ !== rule.blockedType) {
|
|
5575
|
+
continue;
|
|
5576
|
+
}
|
|
5577
|
+
for (const candidate of runningChores) {
|
|
5578
|
+
if (candidate.$type$ === rule.blockingType && rule.match(chore, candidate, container)) {
|
|
5579
|
+
return candidate;
|
|
5580
|
+
}
|
|
5581
|
+
}
|
|
5582
|
+
}
|
|
5583
|
+
return null;
|
|
5584
|
+
}
|
|
5585
|
+
|
|
5586
|
+
// This can't be in platform.ts because it uses MessageChannel which cannot post messages with functions
|
|
5587
|
+
// TODO: move this to platform.ts somehow
|
|
5588
|
+
const createNextTick = (fn) => {
|
|
5589
|
+
let nextTick;
|
|
5590
|
+
// according to the https://developer.mozilla.org/en-US/docs/Web/API/Window/setImmediate#notes
|
|
5591
|
+
if (typeof setImmediate === 'function') {
|
|
5592
|
+
// setImmediate is the fastest way to schedule a task, but works only in node.js
|
|
5593
|
+
nextTick = () => {
|
|
5594
|
+
setImmediate(fn);
|
|
5595
|
+
};
|
|
5596
|
+
}
|
|
5597
|
+
else if (typeof MessageChannel !== 'undefined') {
|
|
5598
|
+
const channel = new MessageChannel();
|
|
5599
|
+
channel.port1.onmessage = () => {
|
|
5600
|
+
fn();
|
|
5601
|
+
};
|
|
5602
|
+
nextTick = () => {
|
|
5603
|
+
channel.port2.postMessage(null);
|
|
5604
|
+
};
|
|
5605
|
+
}
|
|
5606
|
+
else {
|
|
5607
|
+
// setTimeout is a fallback, creates 4ms delay
|
|
5608
|
+
nextTick = () => {
|
|
5609
|
+
setTimeout(fn);
|
|
5610
|
+
};
|
|
5611
|
+
}
|
|
5612
|
+
return nextTick;
|
|
5613
|
+
};
|
|
5614
|
+
|
|
5356
5615
|
/**
|
|
5357
5616
|
* Scheduler is responsible for running application code in predictable order.
|
|
5358
5617
|
*
|
|
@@ -5436,29 +5695,43 @@ const ssrNodeDocumentPosition = (a, b) => {
|
|
|
5436
5695
|
*/
|
|
5437
5696
|
// Turn this on to get debug output of what the scheduler is doing.
|
|
5438
5697
|
const DEBUG = false;
|
|
5439
|
-
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
|
|
5698
|
+
var ChoreState;
|
|
5699
|
+
(function (ChoreState) {
|
|
5700
|
+
ChoreState[ChoreState["NONE"] = 0] = "NONE";
|
|
5701
|
+
ChoreState[ChoreState["RUNNING"] = 1] = "RUNNING";
|
|
5702
|
+
ChoreState[ChoreState["FAILED"] = 2] = "FAILED";
|
|
5703
|
+
ChoreState[ChoreState["DONE"] = 3] = "DONE";
|
|
5704
|
+
})(ChoreState || (ChoreState = {}));
|
|
5705
|
+
const getChorePromise = (chore) => chore.$state$ === ChoreState.NONE
|
|
5706
|
+
? (chore.$returnValue$ ||= new Promise((resolve, reject) => {
|
|
5707
|
+
chore.$resolve$ = resolve;
|
|
5708
|
+
chore.$reject$ = reject;
|
|
5709
|
+
}))
|
|
5710
|
+
: chore.$returnValue$;
|
|
5711
|
+
const createScheduler = (container, journalFlush, choreQueue = [], blockedChores = new Set(), runningChores = new Set()) => {
|
|
5712
|
+
let drainChore = null;
|
|
5446
5713
|
let drainScheduled = false;
|
|
5714
|
+
let isDraining = false;
|
|
5715
|
+
let isJournalFlushRunning = false;
|
|
5716
|
+
let flushBudgetStart = 0;
|
|
5717
|
+
let currentTime = performance.now();
|
|
5718
|
+
const nextTick = createNextTick(drainChoreQueue);
|
|
5719
|
+
function drainInNextTick() {
|
|
5720
|
+
if (!drainScheduled) {
|
|
5721
|
+
drainScheduled = true;
|
|
5722
|
+
nextTick();
|
|
5723
|
+
}
|
|
5724
|
+
}
|
|
5725
|
+
// Drain for ~16.67ms, then apply journal flush for ~16.67ms, then repeat
|
|
5726
|
+
// We divide by 60 because we want to run at 60fps
|
|
5727
|
+
const FREQUENCY_MS = Math.floor(1000 / 60);
|
|
5447
5728
|
return schedule;
|
|
5448
5729
|
///// IMPLEMENTATION /////
|
|
5449
5730
|
function schedule(type, hostOrTask = null, targetOrQrl = null, payload = null) {
|
|
5450
|
-
|
|
5451
|
-
|
|
5452
|
-
const runLater = type !== 255 /* ChoreType.WAIT_FOR_ALL */ && !isComponentSsr && type !== 2 /* ChoreType.RUN_QRL */;
|
|
5453
|
-
const isTask = type === 3 /* ChoreType.TASK */ || type === 32 /* ChoreType.VISIBLE */ || type === 48 /* ChoreType.CLEANUP_VISIBLE */;
|
|
5454
|
-
const isClientOnly = type === 16 /* ChoreType.JOURNAL_FLUSH */ ||
|
|
5455
|
-
type === 4 /* ChoreType.NODE_DIFF */ ||
|
|
5456
|
-
type === 5 /* ChoreType.NODE_PROP */ ||
|
|
5457
|
-
type === 1 /* ChoreType.QRL_RESOLVE */ ||
|
|
5458
|
-
type === 7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */;
|
|
5459
|
-
if (isServer && isClientOnly) {
|
|
5460
|
-
return;
|
|
5731
|
+
if (type === 255 /* ChoreType.WAIT_FOR_QUEUE */ && drainChore) {
|
|
5732
|
+
return drainChore;
|
|
5461
5733
|
}
|
|
5734
|
+
const isTask = type === 3 /* ChoreType.TASK */ || type === 16 /* ChoreType.VISIBLE */ || type === 32 /* ChoreType.CLEANUP_VISIBLE */;
|
|
5462
5735
|
if (isTask) {
|
|
5463
5736
|
hostOrTask.$flags$ |= 8 /* TaskFlags.DIRTY */;
|
|
5464
5737
|
}
|
|
@@ -5472,167 +5745,310 @@ const createScheduler = (container, scheduleDrain, journalFlush) => {
|
|
|
5472
5745
|
$host$: isTask ? hostOrTask.$el$ : hostOrTask,
|
|
5473
5746
|
$target$: targetOrQrl,
|
|
5474
5747
|
$payload$: isTask ? hostOrTask : payload,
|
|
5475
|
-
$
|
|
5476
|
-
$
|
|
5748
|
+
$state$: ChoreState.NONE,
|
|
5749
|
+
$blockedChores$: null,
|
|
5750
|
+
$startTime$: undefined,
|
|
5751
|
+
$endTime$: undefined,
|
|
5752
|
+
$resolve$: undefined,
|
|
5753
|
+
$reject$: undefined,
|
|
5477
5754
|
$returnValue$: null,
|
|
5478
|
-
$executed$: false,
|
|
5479
5755
|
};
|
|
5480
|
-
|
|
5481
|
-
|
|
5482
|
-
|
|
5483
|
-
|
|
5484
|
-
|
|
5485
|
-
|
|
5486
|
-
|
|
5756
|
+
if (type === 255 /* ChoreType.WAIT_FOR_QUEUE */) {
|
|
5757
|
+
getChorePromise(chore);
|
|
5758
|
+
drainChore = chore;
|
|
5759
|
+
drainInNextTick();
|
|
5760
|
+
return chore;
|
|
5761
|
+
}
|
|
5762
|
+
const isServer = isServerPlatform();
|
|
5763
|
+
const isClientOnly = type === 4 /* ChoreType.NODE_DIFF */ || type === 1 /* ChoreType.QRL_RESOLVE */;
|
|
5764
|
+
if (isServer && isClientOnly) {
|
|
5765
|
+
// Mark skipped client-only chores as completed on the server
|
|
5766
|
+
finishChore(chore, undefined);
|
|
5767
|
+
return chore;
|
|
5768
|
+
}
|
|
5769
|
+
if (isServer && chore.$host$ && isSsrNode(chore.$host$)) {
|
|
5770
|
+
const isUpdatable = !!(chore.$host$.flags & 1 /* SsrNodeFlags.Updatable */);
|
|
5771
|
+
if (!isUpdatable) {
|
|
5772
|
+
if (
|
|
5773
|
+
// backpatching exceptions:
|
|
5774
|
+
// - node prop is allowed because it is used to update the node property
|
|
5775
|
+
// - recompute and schedule effects because it triggers effects (so node prop too)
|
|
5776
|
+
chore.$type$ !== 5 /* ChoreType.NODE_PROP */ &&
|
|
5777
|
+
chore.$type$ !== 7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */) {
|
|
5778
|
+
// We are running on the server.
|
|
5779
|
+
// On server we can't schedule task for a different host!
|
|
5780
|
+
// Server is SSR, and therefore scheduling for anything but the current host
|
|
5781
|
+
// implies that things need to be re-run and that is not supported because of streaming.
|
|
5782
|
+
const warningMessage = `A '${choreTypeToName(chore.$type$)}' chore was scheduled on a host element that has already been streamed to the client.
|
|
5783
|
+
This can lead to inconsistencies between Server-Side Rendering (SSR) and Client-Side Rendering (CSR).
|
|
5784
|
+
|
|
5785
|
+
Problematic chore:
|
|
5786
|
+
- Type: ${choreTypeToName(chore.$type$)}
|
|
5787
|
+
- Host: ${chore.$host$.toString()}
|
|
5788
|
+
- Nearest element location: ${chore.$host$.currentFile}
|
|
5789
|
+
|
|
5790
|
+
This is often caused by modifying a signal in an already rendered component during SSR.`;
|
|
5791
|
+
logWarn(warningMessage);
|
|
5792
|
+
return chore;
|
|
5793
|
+
}
|
|
5794
|
+
}
|
|
5795
|
+
}
|
|
5796
|
+
const blockingChore = findBlockingChore(chore, choreQueue, blockedChores, runningChores, container);
|
|
5797
|
+
if (blockingChore) {
|
|
5798
|
+
addBlockedChore(chore, blockingChore, blockedChores);
|
|
5799
|
+
return chore;
|
|
5487
5800
|
}
|
|
5488
|
-
|
|
5489
|
-
|
|
5490
|
-
|
|
5801
|
+
chore = sortedInsert(choreQueue, chore, container.rootVNode || null);
|
|
5802
|
+
const runImmediately = (isServer && type === 6 /* ChoreType.COMPONENT */) || type === 2 /* ChoreType.RUN_QRL */;
|
|
5803
|
+
if (runImmediately && !isDraining) {
|
|
5804
|
+
immediateDrain();
|
|
5491
5805
|
}
|
|
5492
5806
|
else {
|
|
5493
|
-
|
|
5494
|
-
}
|
|
5495
|
-
|
|
5496
|
-
|
|
5497
|
-
function
|
|
5498
|
-
|
|
5499
|
-
|
|
5500
|
-
|
|
5501
|
-
|
|
5502
|
-
|
|
5503
|
-
|
|
5504
|
-
|
|
5505
|
-
|
|
5506
|
-
|
|
5507
|
-
|
|
5508
|
-
|
|
5509
|
-
|
|
5807
|
+
drainInNextTick();
|
|
5808
|
+
}
|
|
5809
|
+
return chore;
|
|
5810
|
+
}
|
|
5811
|
+
function immediateDrain() {
|
|
5812
|
+
drainScheduled = true;
|
|
5813
|
+
drainChoreQueue();
|
|
5814
|
+
}
|
|
5815
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
5816
|
+
// Drain queue helpers
|
|
5817
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
5818
|
+
function applyJournalFlush() {
|
|
5819
|
+
if (!isJournalFlushRunning) {
|
|
5820
|
+
// prevent multiple journal flushes from running at the same time
|
|
5821
|
+
isJournalFlushRunning = true;
|
|
5822
|
+
journalFlush();
|
|
5823
|
+
isJournalFlushRunning = false;
|
|
5824
|
+
flushBudgetStart = performance.now();
|
|
5825
|
+
}
|
|
5826
|
+
}
|
|
5827
|
+
function shouldApplyJournalFlush(isServer) {
|
|
5828
|
+
return !isServer && currentTime - flushBudgetStart >= FREQUENCY_MS;
|
|
5829
|
+
}
|
|
5830
|
+
function drainChoreQueue() {
|
|
5831
|
+
const isServer = isServerPlatform();
|
|
5832
|
+
drainScheduled = false;
|
|
5833
|
+
if (isDraining) {
|
|
5834
|
+
return;
|
|
5835
|
+
}
|
|
5836
|
+
// early return if the queue is empty
|
|
5837
|
+
if (!choreQueue.length) {
|
|
5838
|
+
applyJournalFlush();
|
|
5839
|
+
if (drainChore && !runningChores.size) {
|
|
5840
|
+
// resolve drainChore only if there are no running chores, because
|
|
5841
|
+
// we are sure that we are done
|
|
5842
|
+
drainChore.$resolve$(null);
|
|
5843
|
+
drainChore = null;
|
|
5510
5844
|
}
|
|
5511
|
-
|
|
5512
|
-
|
|
5513
|
-
|
|
5514
|
-
|
|
5515
|
-
|
|
5845
|
+
return;
|
|
5846
|
+
}
|
|
5847
|
+
isDraining = true;
|
|
5848
|
+
flushBudgetStart = performance.now();
|
|
5849
|
+
const maybeFinishDrain = () => {
|
|
5850
|
+
if (choreQueue.length) {
|
|
5851
|
+
drainInNextTick();
|
|
5852
|
+
return false;
|
|
5853
|
+
}
|
|
5854
|
+
if (drainChore && runningChores.size) {
|
|
5855
|
+
if (shouldApplyJournalFlush(isServer)) {
|
|
5856
|
+
// apply journal flush even if we are not finished draining the queue
|
|
5857
|
+
applyJournalFlush();
|
|
5516
5858
|
}
|
|
5517
|
-
|
|
5859
|
+
return false;
|
|
5518
5860
|
}
|
|
5519
|
-
|
|
5520
|
-
|
|
5521
|
-
|
|
5522
|
-
|
|
5523
|
-
|
|
5861
|
+
currentChore = null;
|
|
5862
|
+
applyJournalFlush();
|
|
5863
|
+
drainChore?.$resolve$(null);
|
|
5864
|
+
drainChore = null;
|
|
5865
|
+
return true;
|
|
5866
|
+
};
|
|
5867
|
+
const scheduleBlockedChoresAndDrainIfNeeded = (chore) => {
|
|
5868
|
+
let blockedChoresScheduled = false;
|
|
5869
|
+
if (chore.$blockedChores$) {
|
|
5870
|
+
for (const blockedChore of chore.$blockedChores$) {
|
|
5871
|
+
const blockingChore = findBlockingChore(blockedChore, choreQueue, blockedChores, runningChores, container);
|
|
5872
|
+
if (blockingChore) {
|
|
5873
|
+
addBlockedChore(blockedChore, blockingChore, blockedChores);
|
|
5874
|
+
}
|
|
5875
|
+
else {
|
|
5876
|
+
blockedChores.delete(blockedChore);
|
|
5877
|
+
sortedInsert(choreQueue, blockedChore, container.rootVNode || null);
|
|
5878
|
+
blockedChoresScheduled = true;
|
|
5879
|
+
}
|
|
5880
|
+
}
|
|
5881
|
+
chore.$blockedChores$ = null;
|
|
5524
5882
|
}
|
|
5525
|
-
|
|
5526
|
-
|
|
5527
|
-
|
|
5528
|
-
|
|
5529
|
-
|
|
5530
|
-
const host = chore.$host$;
|
|
5531
|
-
assertEqual(currentChore, null, 'Chore already running.');
|
|
5532
|
-
currentChore = chore;
|
|
5533
|
-
let returnValue = null;
|
|
5883
|
+
if (blockedChoresScheduled && !isDraining) {
|
|
5884
|
+
drainInNextTick();
|
|
5885
|
+
}
|
|
5886
|
+
};
|
|
5887
|
+
let currentChore = null;
|
|
5534
5888
|
try {
|
|
5535
|
-
|
|
5536
|
-
|
|
5537
|
-
|
|
5538
|
-
|
|
5539
|
-
|
|
5540
|
-
|
|
5541
|
-
|
|
5542
|
-
|
|
5543
|
-
|
|
5544
|
-
|
|
5545
|
-
|
|
5546
|
-
|
|
5889
|
+
while (choreQueue.length) {
|
|
5890
|
+
currentTime = performance.now();
|
|
5891
|
+
const chore = (currentChore = choreQueue.shift());
|
|
5892
|
+
if (chore.$state$ !== ChoreState.NONE) {
|
|
5893
|
+
continue;
|
|
5894
|
+
}
|
|
5895
|
+
if (vNodeAlreadyDeleted(chore) &&
|
|
5896
|
+
// we need to process cleanup tasks for deleted nodes
|
|
5897
|
+
chore.$type$ !== 32 /* ChoreType.CLEANUP_VISIBLE */) {
|
|
5898
|
+
// skip deleted chore
|
|
5899
|
+
DEBUG && debugTrace('skip chore', chore, choreQueue, blockedChores);
|
|
5900
|
+
continue;
|
|
5901
|
+
}
|
|
5902
|
+
if (chore.$type$ === 16 /* ChoreType.VISIBLE */) {
|
|
5903
|
+
// ensure that the journal flush is applied before the visible chore is executed
|
|
5904
|
+
// so that the visible chore can see the latest DOM changes
|
|
5905
|
+
applyJournalFlush();
|
|
5906
|
+
const blockingChore = findBlockingChoreForVisible(chore, runningChores, container);
|
|
5907
|
+
if (blockingChore && blockingChore.$state$ === ChoreState.RUNNING) {
|
|
5908
|
+
addBlockedChore(chore, blockingChore, blockedChores);
|
|
5909
|
+
continue;
|
|
5547
5910
|
}
|
|
5548
|
-
|
|
5549
|
-
|
|
5550
|
-
|
|
5551
|
-
|
|
5552
|
-
|
|
5553
|
-
|
|
5911
|
+
}
|
|
5912
|
+
// Note that this never throws
|
|
5913
|
+
chore.$startTime$ = performance.now();
|
|
5914
|
+
const result = executeChore(chore, isServer);
|
|
5915
|
+
chore.$returnValue$ = result;
|
|
5916
|
+
if (isPromise(result)) {
|
|
5917
|
+
runningChores.add(chore);
|
|
5918
|
+
chore.$state$ = ChoreState.RUNNING;
|
|
5919
|
+
result
|
|
5920
|
+
.then((value) => {
|
|
5921
|
+
finishChore(chore, value);
|
|
5922
|
+
})
|
|
5923
|
+
.catch((e) => {
|
|
5924
|
+
if (chore.$state$ !== ChoreState.RUNNING) {
|
|
5925
|
+
// we already handled the error
|
|
5926
|
+
return;
|
|
5927
|
+
}
|
|
5928
|
+
handleError(chore, e);
|
|
5929
|
+
})
|
|
5930
|
+
.finally(() => {
|
|
5931
|
+
runningChores.delete(chore);
|
|
5932
|
+
// Note that we ignore failed chores so the app keeps working
|
|
5933
|
+
// TODO decide if this is ok and document it
|
|
5934
|
+
scheduleBlockedChoresAndDrainIfNeeded(chore);
|
|
5935
|
+
// If drainChore is not null, we are waiting for it to finish.
|
|
5936
|
+
// If there are no running chores, we can finish the drain.
|
|
5937
|
+
if (!runningChores.size) {
|
|
5938
|
+
let finished = false;
|
|
5939
|
+
if (drainChore) {
|
|
5940
|
+
finished = maybeFinishDrain();
|
|
5554
5941
|
}
|
|
5555
|
-
|
|
5556
|
-
|
|
5557
|
-
|
|
5942
|
+
if (!finished && !isDraining) {
|
|
5943
|
+
// if finished, then journal flush is already applied
|
|
5944
|
+
applyJournalFlush();
|
|
5558
5945
|
}
|
|
5559
|
-
}, (err) => container.handleError(err, host));
|
|
5560
|
-
}
|
|
5561
|
-
break;
|
|
5562
|
-
case 2 /* ChoreType.RUN_QRL */:
|
|
5563
|
-
{
|
|
5564
|
-
const fn = chore.$target$.getFn();
|
|
5565
|
-
const result = retryOnPromise(() => fn(...chore.$payload$));
|
|
5566
|
-
if (isPromise(result)) {
|
|
5567
|
-
const handled = result
|
|
5568
|
-
.finally(() => {
|
|
5569
|
-
qrlRuns.splice(qrlRuns.indexOf(handled), 1);
|
|
5570
|
-
})
|
|
5571
|
-
.catch((error) => {
|
|
5572
|
-
container.handleError(error, chore.$host$);
|
|
5573
|
-
});
|
|
5574
|
-
// Don't wait for the promise to resolve
|
|
5575
|
-
// TODO come up with a better solution, we also want concurrent signal handling with tasks but serial tasks
|
|
5576
|
-
qrlRuns.push(handled);
|
|
5577
|
-
DEBUG &&
|
|
5578
|
-
debugTrace('execute.DONE (but still running)', chore, currentChore, choreQueue);
|
|
5579
|
-
chore.$returnValue$ = handled;
|
|
5580
|
-
chore.$resolve$?.(handled);
|
|
5581
|
-
currentChore = null;
|
|
5582
|
-
chore.$executed$ = true;
|
|
5583
|
-
// early out so we don't call after()
|
|
5584
|
-
return;
|
|
5585
5946
|
}
|
|
5586
|
-
|
|
5587
|
-
|
|
5588
|
-
|
|
5589
|
-
|
|
5590
|
-
|
|
5591
|
-
|
|
5592
|
-
|
|
5593
|
-
|
|
5594
|
-
|
|
5595
|
-
|
|
5596
|
-
|
|
5597
|
-
|
|
5598
|
-
|
|
5599
|
-
|
|
5600
|
-
|
|
5601
|
-
|
|
5947
|
+
});
|
|
5948
|
+
}
|
|
5949
|
+
else {
|
|
5950
|
+
finishChore(chore, result);
|
|
5951
|
+
scheduleBlockedChoresAndDrainIfNeeded(chore);
|
|
5952
|
+
}
|
|
5953
|
+
if (shouldApplyJournalFlush(isServer)) {
|
|
5954
|
+
applyJournalFlush();
|
|
5955
|
+
drainInNextTick();
|
|
5956
|
+
return;
|
|
5957
|
+
}
|
|
5958
|
+
}
|
|
5959
|
+
}
|
|
5960
|
+
catch (e) {
|
|
5961
|
+
handleError(currentChore, e);
|
|
5962
|
+
scheduleBlockedChoresAndDrainIfNeeded(currentChore);
|
|
5963
|
+
}
|
|
5964
|
+
finally {
|
|
5965
|
+
isDraining = false;
|
|
5966
|
+
maybeFinishDrain();
|
|
5967
|
+
}
|
|
5968
|
+
}
|
|
5969
|
+
function finishChore(chore, value) {
|
|
5970
|
+
chore.$endTime$ = performance.now();
|
|
5971
|
+
chore.$state$ = ChoreState.DONE;
|
|
5972
|
+
chore.$returnValue$ = value;
|
|
5973
|
+
chore.$resolve$?.(value);
|
|
5974
|
+
}
|
|
5975
|
+
function handleError(chore, e) {
|
|
5976
|
+
chore.$endTime$ = performance.now();
|
|
5977
|
+
chore.$state$ = ChoreState.FAILED;
|
|
5978
|
+
// If we used the result as promise, this won't exist
|
|
5979
|
+
chore.$reject$?.(e);
|
|
5980
|
+
container.handleError(e, chore.$host$);
|
|
5981
|
+
}
|
|
5982
|
+
function executeChore(chore, isServer) {
|
|
5983
|
+
const host = chore.$host$;
|
|
5984
|
+
let returnValue;
|
|
5985
|
+
switch (chore.$type$) {
|
|
5986
|
+
case 6 /* ChoreType.COMPONENT */:
|
|
5987
|
+
{
|
|
5988
|
+
returnValue = safeCall(() => executeComponent(container, host, host, chore.$target$, chore.$payload$), (jsx) => {
|
|
5989
|
+
if (isServer) {
|
|
5990
|
+
return jsx;
|
|
5602
5991
|
}
|
|
5603
5992
|
else {
|
|
5604
|
-
|
|
5993
|
+
const styleScopedId = container.getHostProp(host, QScopedStyle);
|
|
5994
|
+
return retryOnPromise(() => vnode_diff(container, jsx, host, addComponentStylePrefix(styleScopedId)));
|
|
5605
5995
|
}
|
|
5996
|
+
}, (err) => {
|
|
5997
|
+
handleError(chore, err);
|
|
5998
|
+
});
|
|
5999
|
+
}
|
|
6000
|
+
break;
|
|
6001
|
+
case 2 /* ChoreType.RUN_QRL */:
|
|
6002
|
+
{
|
|
6003
|
+
const fn = chore.$target$.getFn();
|
|
6004
|
+
returnValue = retryOnPromise(() => fn(...chore.$payload$));
|
|
6005
|
+
}
|
|
6006
|
+
break;
|
|
6007
|
+
case 3 /* ChoreType.TASK */:
|
|
6008
|
+
case 16 /* ChoreType.VISIBLE */:
|
|
6009
|
+
{
|
|
6010
|
+
const payload = chore.$payload$;
|
|
6011
|
+
if (payload.$flags$ & 4 /* TaskFlags.RESOURCE */) {
|
|
6012
|
+
returnValue = runResource(payload, container, host);
|
|
5606
6013
|
}
|
|
5607
|
-
|
|
5608
|
-
|
|
5609
|
-
{
|
|
5610
|
-
const task = chore.$payload$;
|
|
5611
|
-
cleanupTask(task);
|
|
6014
|
+
else {
|
|
6015
|
+
returnValue = runTask(payload, container, host);
|
|
5612
6016
|
}
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
|
|
5616
|
-
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
|
|
5620
|
-
|
|
5621
|
-
|
|
6017
|
+
}
|
|
6018
|
+
break;
|
|
6019
|
+
case 32 /* ChoreType.CLEANUP_VISIBLE */:
|
|
6020
|
+
{
|
|
6021
|
+
const task = chore.$payload$;
|
|
6022
|
+
cleanupTask(task);
|
|
6023
|
+
}
|
|
6024
|
+
break;
|
|
6025
|
+
case 4 /* ChoreType.NODE_DIFF */:
|
|
6026
|
+
{
|
|
6027
|
+
const parentVirtualNode = chore.$target$;
|
|
6028
|
+
let jsx = chore.$payload$;
|
|
6029
|
+
if (isSignal(jsx)) {
|
|
6030
|
+
jsx = jsx.value;
|
|
5622
6031
|
}
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
|
|
5626
|
-
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
5634
|
-
|
|
5635
|
-
|
|
6032
|
+
returnValue = retryOnPromise(() => vnode_diff(container, jsx, parentVirtualNode, null));
|
|
6033
|
+
}
|
|
6034
|
+
break;
|
|
6035
|
+
case 5 /* ChoreType.NODE_PROP */:
|
|
6036
|
+
{
|
|
6037
|
+
const virtualNode = chore.$host$;
|
|
6038
|
+
const payload = chore.$payload$;
|
|
6039
|
+
let value = payload.$value$;
|
|
6040
|
+
if (isSignal(value)) {
|
|
6041
|
+
value = value.value;
|
|
6042
|
+
}
|
|
6043
|
+
const isConst = payload.$isConst$;
|
|
6044
|
+
const journal = container.$journal$;
|
|
6045
|
+
const property = chore.$idx$;
|
|
6046
|
+
const serializedValue = serializeAttribute(property, value, payload.$scopedStyleIdPrefix$);
|
|
6047
|
+
if (isServer) {
|
|
6048
|
+
container.addBackpatchEntry(chore.$host$.id, property, serializedValue);
|
|
6049
|
+
returnValue = null;
|
|
6050
|
+
}
|
|
6051
|
+
else {
|
|
5636
6052
|
if (isConst) {
|
|
5637
6053
|
const element = virtualNode[6 /* ElementVNodeProps.element */];
|
|
5638
6054
|
journal.push(2 /* VNodeJournalOpCode.SetAttribute */, element, property, serializedValue);
|
|
@@ -5640,64 +6056,49 @@ const createScheduler = (container, scheduleDrain, journalFlush) => {
|
|
|
5640
6056
|
else {
|
|
5641
6057
|
vnode_setAttr(journal, virtualNode, property, serializedValue);
|
|
5642
6058
|
}
|
|
6059
|
+
returnValue = undefined;
|
|
5643
6060
|
}
|
|
5644
|
-
break;
|
|
5645
|
-
case 1 /* ChoreType.QRL_RESOLVE */: {
|
|
5646
|
-
{
|
|
5647
|
-
const target = chore.$target$;
|
|
5648
|
-
returnValue = !target.resolved ? target.resolve() : null;
|
|
5649
|
-
}
|
|
5650
|
-
break;
|
|
5651
6061
|
}
|
|
5652
|
-
|
|
5653
|
-
|
|
5654
|
-
|
|
5655
|
-
|
|
6062
|
+
break;
|
|
6063
|
+
case 1 /* ChoreType.QRL_RESOLVE */: {
|
|
6064
|
+
{
|
|
6065
|
+
const target = chore.$target$;
|
|
6066
|
+
returnValue = (!target.resolved ? target.resolve() : null);
|
|
6067
|
+
}
|
|
6068
|
+
break;
|
|
6069
|
+
}
|
|
6070
|
+
case 7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */: {
|
|
6071
|
+
{
|
|
6072
|
+
const target = chore.$target$;
|
|
6073
|
+
const effects = chore.$payload$;
|
|
6074
|
+
if (!effects?.size) {
|
|
6075
|
+
break;
|
|
6076
|
+
}
|
|
6077
|
+
let shouldCompute = target instanceof ComputedSignalImpl || target instanceof WrappedSignalImpl;
|
|
6078
|
+
if (target instanceof AsyncComputedSignalImpl && effects !== target.$effects$) {
|
|
6079
|
+
shouldCompute = false;
|
|
6080
|
+
}
|
|
6081
|
+
if (shouldCompute) {
|
|
5656
6082
|
const ctx = newInvokeContext();
|
|
5657
6083
|
ctx.$container$ = container;
|
|
5658
|
-
|
|
5659
|
-
|
|
5660
|
-
target.$
|
|
5661
|
-
|
|
5662
|
-
|
|
6084
|
+
// needed for computed signals and throwing QRLs
|
|
6085
|
+
returnValue = maybeThen(retryOnPromise(() => invoke.call(target, ctx, target.$computeIfNeeded$)), () => {
|
|
6086
|
+
if (target.$flags$ & 2 /* SignalFlags.RUN_EFFECTS */) {
|
|
6087
|
+
target.$flags$ &= -3 /* SignalFlags.RUN_EFFECTS */;
|
|
6088
|
+
return retryOnPromise(() => triggerEffects(container, target, effects));
|
|
5663
6089
|
}
|
|
5664
|
-
|
|
5665
|
-
|
|
5666
|
-
|
|
5667
|
-
|
|
5668
|
-
|
|
5669
|
-
|
|
5670
|
-
}
|
|
5671
|
-
else {
|
|
5672
|
-
returnValue = retryOnPromise(() => triggerEffects(container, target, effects));
|
|
5673
|
-
}
|
|
6090
|
+
});
|
|
6091
|
+
}
|
|
6092
|
+
else {
|
|
6093
|
+
returnValue = retryOnPromise(() => {
|
|
6094
|
+
triggerEffects(container, target, effects);
|
|
6095
|
+
});
|
|
5674
6096
|
}
|
|
5675
|
-
break;
|
|
5676
6097
|
}
|
|
6098
|
+
break;
|
|
5677
6099
|
}
|
|
5678
6100
|
}
|
|
5679
|
-
|
|
5680
|
-
returnValue = Promise.reject(e);
|
|
5681
|
-
}
|
|
5682
|
-
const after = (value, error) => {
|
|
5683
|
-
currentChore = null;
|
|
5684
|
-
chore.$executed$ = true;
|
|
5685
|
-
if (error) {
|
|
5686
|
-
container.handleError(error, host);
|
|
5687
|
-
}
|
|
5688
|
-
else {
|
|
5689
|
-
chore.$returnValue$ = value;
|
|
5690
|
-
chore.$resolve$?.(value);
|
|
5691
|
-
}
|
|
5692
|
-
};
|
|
5693
|
-
if (isPromise(returnValue)) {
|
|
5694
|
-
chore.$promise$ = returnValue.then(after, (error) => after(undefined, error));
|
|
5695
|
-
chore.$resolve$?.(chore.$promise$);
|
|
5696
|
-
chore.$resolve$ = undefined;
|
|
5697
|
-
}
|
|
5698
|
-
else {
|
|
5699
|
-
after(returnValue);
|
|
5700
|
-
}
|
|
6101
|
+
return returnValue;
|
|
5701
6102
|
}
|
|
5702
6103
|
/**
|
|
5703
6104
|
* Compares two chores to determine their execution order in the scheduler's queue.
|
|
@@ -5726,15 +6127,6 @@ const createScheduler = (container, scheduleDrain, journalFlush) => {
|
|
|
5726
6127
|
else {
|
|
5727
6128
|
assertFalse(vnode_isVNode(aHost), 'expected aHost to be SSRNode but it is a VNode');
|
|
5728
6129
|
assertFalse(vnode_isVNode(bHost), 'expected bHost to be SSRNode but it is a VNode');
|
|
5729
|
-
// we are running on the server.
|
|
5730
|
-
// On server we can't schedule task for a different host!
|
|
5731
|
-
// Server is SSR, and therefore scheduling for anything but the current host
|
|
5732
|
-
// implies that things need to be re-run nad that is not supported because of streaming.
|
|
5733
|
-
const errorMessage = `SERVER: during HTML streaming, re-running tasks on a different host is not allowed.
|
|
5734
|
-
You are attempting to change a state that has already been streamed to the client.
|
|
5735
|
-
This can lead to inconsistencies between Server-Side Rendering (SSR) and Client-Side Rendering (CSR).
|
|
5736
|
-
Problematic Node: ${aHost.toString()}`;
|
|
5737
|
-
logWarn(errorMessage);
|
|
5738
6130
|
const hostDiff = ssrNodeDocumentPosition(aHost, bHost);
|
|
5739
6131
|
if (hostDiff !== 0) {
|
|
5740
6132
|
return hostDiff;
|
|
@@ -5758,8 +6150,14 @@ const createScheduler = (container, scheduleDrain, journalFlush) => {
|
|
|
5758
6150
|
// 1 means that we are going to process chores as FIFO
|
|
5759
6151
|
return 1;
|
|
5760
6152
|
}
|
|
5761
|
-
//
|
|
5762
|
-
|
|
6153
|
+
// ensure that the effect chores are scheduled for the same target
|
|
6154
|
+
// TODO: can we do this better?
|
|
6155
|
+
if (a.$type$ === 7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */ &&
|
|
6156
|
+
b.$type$ === 7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */ &&
|
|
6157
|
+
((a.$target$ instanceof StoreHandler && b.$target$ instanceof StoreHandler) ||
|
|
6158
|
+
(a.$target$ instanceof AsyncComputedSignalImpl &&
|
|
6159
|
+
b.$target$ instanceof AsyncComputedSignalImpl)) &&
|
|
6160
|
+
a.$payload$ !== b.$payload$) {
|
|
5763
6161
|
return 1;
|
|
5764
6162
|
}
|
|
5765
6163
|
// The chores are the same and will run only once
|
|
@@ -5791,6 +6189,15 @@ const createScheduler = (container, scheduleDrain, journalFlush) => {
|
|
|
5791
6189
|
/// We need to ensure that the `queue` is sorted by priority.
|
|
5792
6190
|
/// 1. Find a place where to insert into.
|
|
5793
6191
|
const idx = sortedFindIndex(sortedArray, value, rootVNode);
|
|
6192
|
+
if (idx < 0 && runningChores.size) {
|
|
6193
|
+
// 1.1. Check if the chore is already running.
|
|
6194
|
+
for (const chore of runningChores) {
|
|
6195
|
+
const comp = choreComparator(value, chore, rootVNode);
|
|
6196
|
+
if (comp === 0) {
|
|
6197
|
+
return chore;
|
|
6198
|
+
}
|
|
6199
|
+
}
|
|
6200
|
+
}
|
|
5794
6201
|
if (idx < 0) {
|
|
5795
6202
|
/// 2. Insert the chore into the queue.
|
|
5796
6203
|
sortedArray.splice(~idx, 0, value);
|
|
@@ -5805,9 +6212,6 @@ const createScheduler = (container, scheduleDrain, journalFlush) => {
|
|
|
5805
6212
|
if (existing.$payload$ !== value.$payload$) {
|
|
5806
6213
|
existing.$payload$ = value.$payload$;
|
|
5807
6214
|
}
|
|
5808
|
-
if (existing.$executed$) {
|
|
5809
|
-
existing.$executed$ = false;
|
|
5810
|
-
}
|
|
5811
6215
|
return existing;
|
|
5812
6216
|
}
|
|
5813
6217
|
};
|
|
@@ -5819,6 +6223,25 @@ function vNodeAlreadyDeleted(chore) {
|
|
|
5819
6223
|
vnode_isVNode(chore.$host$) &&
|
|
5820
6224
|
chore.$host$[0 /* VNodeProps.flags */] & 32 /* VNodeFlags.Deleted */);
|
|
5821
6225
|
}
|
|
6226
|
+
function addBlockedChore(blockedChore, blockingChore, blockedChores) {
|
|
6227
|
+
blockingChore.$blockedChores$ ||= [];
|
|
6228
|
+
blockingChore.$blockedChores$.push(blockedChore);
|
|
6229
|
+
blockedChores.add(blockedChore);
|
|
6230
|
+
}
|
|
6231
|
+
function choreTypeToName(type) {
|
|
6232
|
+
return ({
|
|
6233
|
+
[1 /* ChoreType.QRL_RESOLVE */]: 'Resolve QRL',
|
|
6234
|
+
[2 /* ChoreType.RUN_QRL */]: 'Run QRL',
|
|
6235
|
+
[3 /* ChoreType.TASK */]: 'Task',
|
|
6236
|
+
[4 /* ChoreType.NODE_DIFF */]: 'Changes diffing',
|
|
6237
|
+
[5 /* ChoreType.NODE_PROP */]: 'Updating node property',
|
|
6238
|
+
[6 /* ChoreType.COMPONENT */]: 'Component',
|
|
6239
|
+
[7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */]: 'Signal recompute',
|
|
6240
|
+
[16 /* ChoreType.VISIBLE */]: 'Visible',
|
|
6241
|
+
[32 /* ChoreType.CLEANUP_VISIBLE */]: 'Cleanup visible',
|
|
6242
|
+
[255 /* ChoreType.WAIT_FOR_QUEUE */]: 'Wait for queue',
|
|
6243
|
+
}[type] || 'Unknown: ' + type);
|
|
6244
|
+
}
|
|
5822
6245
|
function debugChoreTypeToString(type) {
|
|
5823
6246
|
return ({
|
|
5824
6247
|
[1 /* ChoreType.QRL_RESOLVE */]: 'QRL_RESOLVE',
|
|
@@ -5828,31 +6251,87 @@ function debugChoreTypeToString(type) {
|
|
|
5828
6251
|
[5 /* ChoreType.NODE_PROP */]: 'NODE_PROP',
|
|
5829
6252
|
[6 /* ChoreType.COMPONENT */]: 'COMPONENT',
|
|
5830
6253
|
[7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */]: 'RECOMPUTE_SIGNAL',
|
|
5831
|
-
[16 /* ChoreType.
|
|
5832
|
-
[32 /* ChoreType.
|
|
5833
|
-
[
|
|
5834
|
-
[255 /* ChoreType.WAIT_FOR_ALL */]: 'WAIT_FOR_ALL',
|
|
6254
|
+
[16 /* ChoreType.VISIBLE */]: 'VISIBLE',
|
|
6255
|
+
[32 /* ChoreType.CLEANUP_VISIBLE */]: 'CLEANUP_VISIBLE',
|
|
6256
|
+
[255 /* ChoreType.WAIT_FOR_QUEUE */]: 'WAIT_FOR_QUEUE',
|
|
5835
6257
|
}[type] || 'UNKNOWN: ' + type);
|
|
5836
6258
|
}
|
|
5837
|
-
function
|
|
5838
|
-
const
|
|
5839
|
-
|
|
5840
|
-
|
|
5841
|
-
|
|
5842
|
-
|
|
5843
|
-
|
|
5844
|
-
|
|
5845
|
-
|
|
5846
|
-
|
|
5847
|
-
|
|
5848
|
-
|
|
5849
|
-
|
|
5850
|
-
|
|
5851
|
-
|
|
5852
|
-
|
|
5853
|
-
|
|
6259
|
+
function debugTrace(action, arg, queue, blockedChores) {
|
|
6260
|
+
const lines = [];
|
|
6261
|
+
// Header
|
|
6262
|
+
lines.push(`Scheduler: ${action}`);
|
|
6263
|
+
// Argument section
|
|
6264
|
+
if (arg) {
|
|
6265
|
+
lines.push('');
|
|
6266
|
+
if (arg && '$type$' in arg) {
|
|
6267
|
+
const chore = arg;
|
|
6268
|
+
const type = debugChoreTypeToString(chore.$type$);
|
|
6269
|
+
const host = String(chore.$host$).replaceAll(/\n.*/gim, '');
|
|
6270
|
+
const qrlTarget = chore.$target$?.$symbol$;
|
|
6271
|
+
const targetOrHost = chore.$type$ === 1 /* ChoreType.QRL_RESOLVE */ || chore.$type$ === 2 /* ChoreType.RUN_QRL */
|
|
6272
|
+
? qrlTarget
|
|
6273
|
+
: host;
|
|
6274
|
+
lines.push(`🎯 Current Chore:`);
|
|
6275
|
+
lines.push(` Type: ${type}`);
|
|
6276
|
+
lines.push(` Host: ${targetOrHost}`);
|
|
6277
|
+
// Show execution time if available
|
|
6278
|
+
if (chore.$startTime$ && chore.$endTime$) {
|
|
6279
|
+
const executionTime = chore.$endTime$ - chore.$startTime$;
|
|
6280
|
+
lines.push(` Time: ${executionTime.toFixed(2)}ms`);
|
|
6281
|
+
}
|
|
6282
|
+
else if (chore.$startTime$) {
|
|
6283
|
+
const elapsedTime = performance.now() - chore.$startTime$;
|
|
6284
|
+
lines.push(` Time: ${elapsedTime.toFixed(2)}ms (running)`);
|
|
6285
|
+
}
|
|
6286
|
+
// Show blocked chores for this chore
|
|
6287
|
+
if (chore.$blockedChores$ && chore.$blockedChores$.length > 0) {
|
|
6288
|
+
lines.push(` ⛔ Blocked Chores:`);
|
|
6289
|
+
chore.$blockedChores$.forEach((blockedChore, index) => {
|
|
6290
|
+
const blockedType = debugChoreTypeToString(blockedChore.$type$);
|
|
6291
|
+
const blockedTarget = String(blockedChore.$host$).replaceAll(/\n.*/gim, '');
|
|
6292
|
+
lines.push(` ${index + 1}. ${blockedType} ${blockedTarget} ${blockedChore.$idx$}`);
|
|
6293
|
+
});
|
|
6294
|
+
}
|
|
6295
|
+
}
|
|
6296
|
+
else {
|
|
6297
|
+
lines.push(`📝 Argument: ${String(arg).replaceAll(/\n.*/gim, '')}`);
|
|
6298
|
+
}
|
|
6299
|
+
}
|
|
6300
|
+
// Queue section
|
|
6301
|
+
if (queue && queue.length > 0) {
|
|
6302
|
+
lines.push('');
|
|
6303
|
+
lines.push(`📋 Queue (${queue.length} items):`);
|
|
6304
|
+
queue.forEach((chore, index) => {
|
|
6305
|
+
const isActive = chore === arg;
|
|
6306
|
+
const activeMarker = isActive ? `▶ ` : ' ';
|
|
6307
|
+
const type = debugChoreTypeToString(chore.$type$);
|
|
6308
|
+
const state = chore.$state$ ? `[${ChoreState[chore.$state$]}]` : '';
|
|
6309
|
+
const host = String(chore.$host$).replaceAll(/\n.*/gim, '');
|
|
6310
|
+
const qrlTarget = chore.$target$?.$symbol$;
|
|
6311
|
+
const target = chore.$type$ === 1 /* ChoreType.QRL_RESOLVE */ || chore.$type$ === 2 /* ChoreType.RUN_QRL */
|
|
6312
|
+
? qrlTarget
|
|
6313
|
+
: host;
|
|
6314
|
+
const line = `${activeMarker}${state} ${type} ${target} ${chore.$idx$}`;
|
|
6315
|
+
lines.push(line);
|
|
6316
|
+
});
|
|
6317
|
+
}
|
|
6318
|
+
// Blocked chores section
|
|
6319
|
+
if (blockedChores && blockedChores.size > 0) {
|
|
6320
|
+
lines.push('');
|
|
6321
|
+
lines.push(`🚫 Blocked Chores (${blockedChores.size} items):`);
|
|
6322
|
+
Array.from(blockedChores).forEach((chore, index) => {
|
|
6323
|
+
const type = debugChoreTypeToString(chore.$type$);
|
|
6324
|
+
const host = String(chore.$host$).replaceAll(/\n.*/gim, '');
|
|
6325
|
+
const qrlTarget = chore.$target$?.$symbol$;
|
|
6326
|
+
const target = chore.$type$ === 1 /* ChoreType.QRL_RESOLVE */ || chore.$type$ === 2 /* ChoreType.RUN_QRL */
|
|
6327
|
+
? qrlTarget
|
|
6328
|
+
: host;
|
|
6329
|
+
lines.push(` ${index + 1}. ${type} ${target} ${chore.$idx$}`);
|
|
5854
6330
|
});
|
|
5855
6331
|
}
|
|
6332
|
+
// Footer
|
|
6333
|
+
lines.push('');
|
|
6334
|
+
lines.push('─'.repeat(60));
|
|
5856
6335
|
// eslint-disable-next-line no-console
|
|
5857
6336
|
console.log(lines.join('\n') + '\n');
|
|
5858
6337
|
}
|
|
@@ -5870,7 +6349,8 @@ class _SharedContainer {
|
|
|
5870
6349
|
$currentUniqueId$ = 0;
|
|
5871
6350
|
$instanceHash$ = null;
|
|
5872
6351
|
$buildBase$ = null;
|
|
5873
|
-
|
|
6352
|
+
$flushEpoch$ = 0;
|
|
6353
|
+
constructor(journalFlush, serverData, locale) {
|
|
5874
6354
|
this.$serverData$ = serverData;
|
|
5875
6355
|
this.$locale$ = locale;
|
|
5876
6356
|
this.$version$ = version;
|
|
@@ -5878,7 +6358,7 @@ class _SharedContainer {
|
|
|
5878
6358
|
this.$getObjectById$ = (_id) => {
|
|
5879
6359
|
throw Error('Not implemented');
|
|
5880
6360
|
};
|
|
5881
|
-
this.$scheduler$ = createScheduler(this,
|
|
6361
|
+
this.$scheduler$ = createScheduler(this, journalFlush);
|
|
5882
6362
|
}
|
|
5883
6363
|
trackSignalValue(signal, subscriber, property, data) {
|
|
5884
6364
|
return trackSignalAndAssignHost(signal, subscriber, property, this, data);
|
|
@@ -6187,9 +6667,10 @@ function processVNodeData$1(document) {
|
|
|
6187
6667
|
const shadowRootContainer = node;
|
|
6188
6668
|
const shadowRoot = shadowRootContainer?.shadowRoot;
|
|
6189
6669
|
if (shadowRoot) {
|
|
6670
|
+
const firstShadowRootChild = firstChild(shadowRoot);
|
|
6190
6671
|
walkContainer(
|
|
6191
6672
|
// we need to create a new walker for the shadow root
|
|
6192
|
-
document.createTreeWalker(
|
|
6673
|
+
document.createTreeWalker(firstShadowRootChild, 0x1 /* NodeFilter.SHOW_ELEMENT */ | 0x80 /* NodeFilter.SHOW_COMMENT */), null, firstShadowRootChild, null, '', null);
|
|
6193
6674
|
}
|
|
6194
6675
|
}
|
|
6195
6676
|
if ((nodeType & 2 /* NodeType.ELEMENT */) === 2 /* NodeType.ELEMENT */) {
|
|
@@ -6265,7 +6746,7 @@ function getDomContainerFromQContainerElement(qContainerElement) {
|
|
|
6265
6746
|
/** @internal */
|
|
6266
6747
|
function _getQContainerElement(element) {
|
|
6267
6748
|
const qContainerElement = Array.isArray(element)
|
|
6268
|
-
? vnode_getDomParent(element)
|
|
6749
|
+
? vnode_getDomParent(element, true)
|
|
6269
6750
|
: element;
|
|
6270
6751
|
return qContainerElement.closest(QContainerSelector);
|
|
6271
6752
|
}
|
|
@@ -6280,7 +6761,6 @@ class DomContainer extends _SharedContainer {
|
|
|
6280
6761
|
rootVNode;
|
|
6281
6762
|
document;
|
|
6282
6763
|
$journal$;
|
|
6283
|
-
renderDone = null;
|
|
6284
6764
|
$rawStateData$;
|
|
6285
6765
|
$storeProxyMap$ = new WeakMap();
|
|
6286
6766
|
$qFuncs$;
|
|
@@ -6290,9 +6770,11 @@ class DomContainer extends _SharedContainer {
|
|
|
6290
6770
|
vNodeLocate = (id) => vnode_locate(this.rootVNode, id);
|
|
6291
6771
|
$stateData$;
|
|
6292
6772
|
$styleIds$ = null;
|
|
6293
|
-
$renderCount$ = 0;
|
|
6294
6773
|
constructor(element) {
|
|
6295
|
-
super(() =>
|
|
6774
|
+
super(() => {
|
|
6775
|
+
this.$flushEpoch$++;
|
|
6776
|
+
vnode_applyJournal(this.$journal$);
|
|
6777
|
+
}, {}, element.getAttribute(QLocaleAttr));
|
|
6296
6778
|
this.qContainer = element.getAttribute(QContainerAttr);
|
|
6297
6779
|
if (!this.qContainer) {
|
|
6298
6780
|
throw qError(25 /* QError.elementWithoutContainer */);
|
|
@@ -6334,20 +6816,17 @@ class DomContainer extends _SharedContainer {
|
|
|
6334
6816
|
}
|
|
6335
6817
|
handleError(err, host) {
|
|
6336
6818
|
if (qDev && host) {
|
|
6337
|
-
// Clean vdom
|
|
6338
6819
|
if (typeof document !== 'undefined') {
|
|
6339
6820
|
const vHost = host;
|
|
6340
|
-
const errorDiv = document.createElement('errored-host');
|
|
6341
|
-
if (err && err instanceof Error) {
|
|
6342
|
-
errorDiv.props = { error: err };
|
|
6343
|
-
}
|
|
6344
|
-
errorDiv.setAttribute('q:key', '_error_');
|
|
6345
6821
|
const journal = [];
|
|
6346
|
-
const
|
|
6347
|
-
|
|
6348
|
-
|
|
6349
|
-
|
|
6350
|
-
|
|
6822
|
+
const vHostParent = vnode_getParent(vHost);
|
|
6823
|
+
const vHostNextSibling = vnode_getNextSibling(vHost);
|
|
6824
|
+
const vErrorDiv = vnode_createErrorDiv(document, vHost, err, journal);
|
|
6825
|
+
// If the host is an element node, we need to insert the error div into its parent.
|
|
6826
|
+
const insertHost = vnode_isElementVNode(vHost) ? vHostParent || vHost : vHost;
|
|
6827
|
+
// If the host is different then we need to insert errored-host in the same position as the host.
|
|
6828
|
+
const insertBefore = insertHost === vHost ? null : vHostNextSibling;
|
|
6829
|
+
vnode_insertBefore(journal, insertHost, vErrorDiv, insertBefore);
|
|
6351
6830
|
vnode_applyJournal(journal);
|
|
6352
6831
|
}
|
|
6353
6832
|
if (err && err instanceof Error) {
|
|
@@ -6422,29 +6901,6 @@ class DomContainer extends _SharedContainer {
|
|
|
6422
6901
|
}
|
|
6423
6902
|
return vnode_getProp(vNode, name, getObjectById);
|
|
6424
6903
|
}
|
|
6425
|
-
scheduleRender() {
|
|
6426
|
-
this.$renderCount$++;
|
|
6427
|
-
this.renderDone ||= getPlatform().nextTick(() => this.processChores());
|
|
6428
|
-
return this.renderDone.finally(() => emitEvent('qrender', { instanceHash: this.$instanceHash$, renderCount: this.$renderCount$ }));
|
|
6429
|
-
}
|
|
6430
|
-
processChores() {
|
|
6431
|
-
let renderCount = this.$renderCount$;
|
|
6432
|
-
const result = this.$scheduler$(255 /* ChoreType.WAIT_FOR_ALL */);
|
|
6433
|
-
if (isPromise(result)) {
|
|
6434
|
-
return result.then(async () => {
|
|
6435
|
-
while (renderCount !== this.$renderCount$) {
|
|
6436
|
-
renderCount = this.$renderCount$;
|
|
6437
|
-
await this.$scheduler$(255 /* ChoreType.WAIT_FOR_ALL */);
|
|
6438
|
-
}
|
|
6439
|
-
this.renderDone = null;
|
|
6440
|
-
});
|
|
6441
|
-
}
|
|
6442
|
-
if (renderCount !== this.$renderCount$) {
|
|
6443
|
-
this.processChores();
|
|
6444
|
-
return;
|
|
6445
|
-
}
|
|
6446
|
-
this.renderDone = null;
|
|
6447
|
-
}
|
|
6448
6904
|
ensureProjectionResolved(vNode) {
|
|
6449
6905
|
if ((vNode[0 /* VNodeProps.flags */] & 16 /* VNodeFlags.Resolved */) === 0) {
|
|
6450
6906
|
vNode[0 /* VNodeProps.flags */] |= 16 /* VNodeFlags.Resolved */;
|
|
@@ -6454,7 +6910,9 @@ class DomContainer extends _SharedContainer {
|
|
|
6454
6910
|
if (isSlotProp(prop)) {
|
|
6455
6911
|
const value = props[i + 1];
|
|
6456
6912
|
if (typeof value == 'string') {
|
|
6457
|
-
|
|
6913
|
+
const projection = this.vNodeLocate(value);
|
|
6914
|
+
props[i + 1] = projection;
|
|
6915
|
+
vnode_getProp(projection, QSlotParent, (id) => this.vNodeLocate(id));
|
|
6458
6916
|
}
|
|
6459
6917
|
}
|
|
6460
6918
|
}
|
|
@@ -6575,7 +7033,7 @@ const addQrlToSerializationCtx = (effectSubscriber, container) => {
|
|
|
6575
7033
|
}
|
|
6576
7034
|
};
|
|
6577
7035
|
const triggerEffects = (container, signal, effects) => {
|
|
6578
|
-
const isBrowser =
|
|
7036
|
+
const isBrowser = !isServerPlatform();
|
|
6579
7037
|
if (effects) {
|
|
6580
7038
|
const scheduleEffect = (effectSubscription) => {
|
|
6581
7039
|
const consumer = effectSubscription[0 /* EffectSubscriptionProp.CONSUMER */];
|
|
@@ -6585,7 +7043,7 @@ const triggerEffects = (container, signal, effects) => {
|
|
|
6585
7043
|
consumer.$flags$ |= 8 /* TaskFlags.DIRTY */;
|
|
6586
7044
|
let choreType = 3 /* ChoreType.TASK */;
|
|
6587
7045
|
if (consumer.$flags$ & 1 /* TaskFlags.VISIBLE_TASK */) {
|
|
6588
|
-
choreType =
|
|
7046
|
+
choreType = 16 /* ChoreType.VISIBLE */;
|
|
6589
7047
|
}
|
|
6590
7048
|
container.$scheduler$(choreType, consumer);
|
|
6591
7049
|
}
|
|
@@ -6608,22 +7066,22 @@ const triggerEffects = (container, signal, effects) => {
|
|
|
6608
7066
|
const props = container.getHostProp(host, ELEMENT_PROPS);
|
|
6609
7067
|
container.$scheduler$(6 /* ChoreType.COMPONENT */, host, qrl, props);
|
|
6610
7068
|
}
|
|
6611
|
-
else if (
|
|
6612
|
-
if (
|
|
7069
|
+
else if (property === "." /* EffectProperty.VNODE */) {
|
|
7070
|
+
if (isBrowser) {
|
|
6613
7071
|
const host = consumer;
|
|
6614
7072
|
container.$scheduler$(4 /* ChoreType.NODE_DIFF */, host, host, signal);
|
|
6615
7073
|
}
|
|
6616
|
-
|
|
6617
|
-
|
|
6618
|
-
|
|
6619
|
-
|
|
6620
|
-
|
|
6621
|
-
|
|
6622
|
-
|
|
6623
|
-
|
|
6624
|
-
|
|
6625
|
-
|
|
6626
|
-
|
|
7074
|
+
}
|
|
7075
|
+
else {
|
|
7076
|
+
const host = consumer;
|
|
7077
|
+
const effectData = effectSubscription[3 /* EffectSubscriptionProp.DATA */];
|
|
7078
|
+
if (effectData instanceof SubscriptionData) {
|
|
7079
|
+
const data = effectData.data;
|
|
7080
|
+
const payload = {
|
|
7081
|
+
...data,
|
|
7082
|
+
$value$: signal,
|
|
7083
|
+
};
|
|
7084
|
+
container.$scheduler$(5 /* ChoreType.NODE_PROP */, host, property, payload);
|
|
6627
7085
|
}
|
|
6628
7086
|
}
|
|
6629
7087
|
};
|
|
@@ -6644,10 +7102,10 @@ const getComputedSignalFlags = (serializationStrategy) => {
|
|
|
6644
7102
|
// flags |= ComputedSignalFlags.SERIALIZATION_STRATEGY_AUTO;
|
|
6645
7103
|
// break;
|
|
6646
7104
|
case 'never':
|
|
6647
|
-
flags |=
|
|
7105
|
+
flags |= 16 /* SerializationSignalFlags.SERIALIZATION_STRATEGY_NEVER */;
|
|
6648
7106
|
break;
|
|
6649
7107
|
case 'always':
|
|
6650
|
-
flags |=
|
|
7108
|
+
flags |= 32 /* SerializationSignalFlags.SERIALIZATION_STRATEGY_ALWAYS */;
|
|
6651
7109
|
break;
|
|
6652
7110
|
}
|
|
6653
7111
|
return flags;
|
|
@@ -7039,6 +7497,9 @@ function vnode_walkVNode(vNode, callback) {
|
|
|
7039
7497
|
}
|
|
7040
7498
|
let vParent = null;
|
|
7041
7499
|
do {
|
|
7500
|
+
if (callback?.(vCursor, vParent)) {
|
|
7501
|
+
return;
|
|
7502
|
+
}
|
|
7042
7503
|
const vFirstChild = vnode_getFirstChild(vCursor);
|
|
7043
7504
|
if (vFirstChild) {
|
|
7044
7505
|
vCursor = vFirstChild;
|
|
@@ -7207,6 +7668,7 @@ const vnode_ensureTextInflated = (journal, vnode) => {
|
|
|
7207
7668
|
const flags = textVNode[0 /* VNodeProps.flags */];
|
|
7208
7669
|
if ((flags & 8 /* VNodeFlags.Inflated */) === 0) {
|
|
7209
7670
|
const parentNode = vnode_getDomParent(vnode);
|
|
7671
|
+
assertDefined(parentNode, 'Missing parent node.');
|
|
7210
7672
|
const sharedTextNode = textVNode[4 /* TextVNodeProps.node */];
|
|
7211
7673
|
const doc = parentNode.ownerDocument;
|
|
7212
7674
|
// Walk the previous siblings and inflate them.
|
|
@@ -7365,6 +7827,18 @@ const indexOfAlphanumeric = (id, length) => {
|
|
|
7365
7827
|
}
|
|
7366
7828
|
return length;
|
|
7367
7829
|
};
|
|
7830
|
+
const vnode_createErrorDiv = (document, host, err, journal) => {
|
|
7831
|
+
const errorDiv = document.createElement('errored-host');
|
|
7832
|
+
if (err && err instanceof Error) {
|
|
7833
|
+
errorDiv.props = { error: err };
|
|
7834
|
+
}
|
|
7835
|
+
errorDiv.setAttribute('q:key', '_error_');
|
|
7836
|
+
const vErrorDiv = vnode_newElement(errorDiv, 'errored-host');
|
|
7837
|
+
vnode_getDOMChildNodes(journal, host, true).forEach((child) => {
|
|
7838
|
+
vnode_insertBefore(journal, vErrorDiv, child, null);
|
|
7839
|
+
});
|
|
7840
|
+
return vErrorDiv;
|
|
7841
|
+
};
|
|
7368
7842
|
const parseBoolean = (value) => {
|
|
7369
7843
|
if (value === 'false') {
|
|
7370
7844
|
return false;
|
|
@@ -7503,7 +7977,7 @@ const vnode_insertBefore = (journal, parent, newChild, insertBefore) => {
|
|
|
7503
7977
|
* unlink the previous or next sibling, we don't know that after "a" node is "b". So we need to
|
|
7504
7978
|
* find children first (and inflate them).
|
|
7505
7979
|
*/
|
|
7506
|
-
const domParentVNode = vnode_getDomParentVNode(parent);
|
|
7980
|
+
const domParentVNode = vnode_getDomParentVNode(parent, false);
|
|
7507
7981
|
const parentNode = domParentVNode && domParentVNode[6 /* ElementVNodeProps.element */];
|
|
7508
7982
|
let domChildren = null;
|
|
7509
7983
|
if (domParentVNode) {
|
|
@@ -7552,27 +8026,31 @@ const vnode_insertBefore = (journal, parent, newChild, insertBefore) => {
|
|
|
7552
8026
|
newChildCurrentParent !== parent)) {
|
|
7553
8027
|
vnode_remove(journal, newChildCurrentParent, newChild, false);
|
|
7554
8028
|
}
|
|
7555
|
-
|
|
7556
|
-
if
|
|
7557
|
-
|
|
7558
|
-
|
|
7559
|
-
|
|
7560
|
-
|
|
7561
|
-
|
|
7562
|
-
|
|
8029
|
+
const parentIsDeleted = parent[0 /* VNodeProps.flags */] & 32 /* VNodeFlags.Deleted */;
|
|
8030
|
+
// if the parent is deleted, then we don't need to insert the new child
|
|
8031
|
+
if (!parentIsDeleted) {
|
|
8032
|
+
let adjustedInsertBefore = null;
|
|
8033
|
+
if (insertBefore == null) {
|
|
8034
|
+
if (vnode_isVirtualVNode(parent)) {
|
|
8035
|
+
// If `insertBefore` is null, than we need to insert at the end of the list.
|
|
8036
|
+
// Well, not quite. If the parent is a virtual node, our "last node" is not the same
|
|
8037
|
+
// as the DOM "last node". So in that case we need to look for the "next node" from
|
|
8038
|
+
// our parent.
|
|
8039
|
+
adjustedInsertBefore = vnode_getDomSibling(parent, true, false);
|
|
8040
|
+
}
|
|
8041
|
+
}
|
|
8042
|
+
else if (vnode_isVirtualVNode(insertBefore)) {
|
|
8043
|
+
// If the `insertBefore` is virtual, than we need to descend into the virtual and find e actual
|
|
8044
|
+
adjustedInsertBefore = vnode_getDomSibling(insertBefore, true, true);
|
|
8045
|
+
}
|
|
8046
|
+
else {
|
|
8047
|
+
adjustedInsertBefore = insertBefore;
|
|
8048
|
+
}
|
|
8049
|
+
adjustedInsertBefore && vnode_ensureInflatedIfText(journal, adjustedInsertBefore);
|
|
8050
|
+
// Here we know the insertBefore node
|
|
8051
|
+
if (domChildren && domChildren.length) {
|
|
8052
|
+
journal.push(5 /* VNodeJournalOpCode.Insert */, parentNode, vnode_getNode(adjustedInsertBefore), ...domChildren);
|
|
7563
8053
|
}
|
|
7564
|
-
}
|
|
7565
|
-
else if (vnode_isVirtualVNode(insertBefore)) {
|
|
7566
|
-
// If the `insertBefore` is virtual, than we need to descend into the virtual and find e actual
|
|
7567
|
-
adjustedInsertBefore = vnode_getDomSibling(insertBefore, true, true);
|
|
7568
|
-
}
|
|
7569
|
-
else {
|
|
7570
|
-
adjustedInsertBefore = insertBefore;
|
|
7571
|
-
}
|
|
7572
|
-
adjustedInsertBefore && vnode_ensureInflatedIfText(journal, adjustedInsertBefore);
|
|
7573
|
-
// Here we know the insertBefore node
|
|
7574
|
-
if (domChildren && domChildren.length) {
|
|
7575
|
-
journal.push(5 /* VNodeJournalOpCode.Insert */, parentNode, vnode_getNode(adjustedInsertBefore), ...domChildren);
|
|
7576
8054
|
}
|
|
7577
8055
|
// link newChild into the previous/next list
|
|
7578
8056
|
const vNext = insertBefore;
|
|
@@ -7594,14 +8072,22 @@ const vnode_insertBefore = (journal, parent, newChild, insertBefore) => {
|
|
|
7594
8072
|
newChild[2 /* VNodeProps.previousSibling */] = vPrevious;
|
|
7595
8073
|
newChild[3 /* VNodeProps.nextSibling */] = vNext;
|
|
7596
8074
|
newChild[1 /* VNodeProps.parent */] = parent;
|
|
8075
|
+
if (parentIsDeleted) {
|
|
8076
|
+
// if the parent is deleted, then the new child is also deleted
|
|
8077
|
+
newChild[0 /* VNodeProps.flags */] |= 32 /* VNodeFlags.Deleted */;
|
|
8078
|
+
}
|
|
7597
8079
|
};
|
|
7598
|
-
const vnode_getDomParent = (vnode) => {
|
|
7599
|
-
vnode = vnode_getDomParentVNode(vnode);
|
|
8080
|
+
const vnode_getDomParent = (vnode, includeProjection = true) => {
|
|
8081
|
+
vnode = vnode_getDomParentVNode(vnode, includeProjection);
|
|
7600
8082
|
return (vnode && vnode[6 /* ElementVNodeProps.element */]);
|
|
7601
8083
|
};
|
|
7602
|
-
const vnode_getDomParentVNode = (vnode) => {
|
|
8084
|
+
const vnode_getDomParentVNode = (vnode, includeProjection = true) => {
|
|
7603
8085
|
while (vnode && !vnode_isElementVNode(vnode)) {
|
|
7604
|
-
vnode =
|
|
8086
|
+
vnode =
|
|
8087
|
+
vnode[1 /* VNodeProps.parent */] ||
|
|
8088
|
+
(includeProjection
|
|
8089
|
+
? vnode_getProp(vnode, QSlotParent, (id) => (vnode_isVNode(id) ? id : null))
|
|
8090
|
+
: null);
|
|
7605
8091
|
}
|
|
7606
8092
|
return vnode;
|
|
7607
8093
|
};
|
|
@@ -7611,7 +8097,7 @@ const vnode_remove = (journal, vParent, vToRemove, removeDOM) => {
|
|
|
7611
8097
|
vnode_ensureTextInflated(journal, vToRemove);
|
|
7612
8098
|
}
|
|
7613
8099
|
if (removeDOM) {
|
|
7614
|
-
const domParent = vnode_getDomParent(vParent);
|
|
8100
|
+
const domParent = vnode_getDomParent(vParent, false);
|
|
7615
8101
|
const isInnerHTMLParent = vnode_getAttr(vParent, dangerouslySetInnerHTML);
|
|
7616
8102
|
if (isInnerHTMLParent) {
|
|
7617
8103
|
// ignore children, as they are inserted via innerHTML
|
|
@@ -8092,6 +8578,26 @@ const vnode_getProps = (vnode) => {
|
|
|
8092
8578
|
const vnode_getParent = (vnode) => {
|
|
8093
8579
|
return vnode[1 /* VNodeProps.parent */] || null;
|
|
8094
8580
|
};
|
|
8581
|
+
const vnode_isDescendantOf = (vnode, ancestor, rootVNode) => {
|
|
8582
|
+
let parent = vnode_getParentOrProjectionParent(vnode, rootVNode);
|
|
8583
|
+
while (parent) {
|
|
8584
|
+
if (parent === ancestor) {
|
|
8585
|
+
return true;
|
|
8586
|
+
}
|
|
8587
|
+
parent = vnode_getParentOrProjectionParent(parent, rootVNode);
|
|
8588
|
+
}
|
|
8589
|
+
return false;
|
|
8590
|
+
};
|
|
8591
|
+
const vnode_getParentOrProjectionParent = (vnode, rootVNode) => {
|
|
8592
|
+
if (rootVNode) {
|
|
8593
|
+
const parentProjection = vnode_getProp(vnode, QSlotParent, (id) => vnode_locate(rootVNode, id));
|
|
8594
|
+
if (parentProjection) {
|
|
8595
|
+
// This is a projection, so we need to check the parent of the projection
|
|
8596
|
+
return parentProjection;
|
|
8597
|
+
}
|
|
8598
|
+
}
|
|
8599
|
+
return vnode_getParent(vnode);
|
|
8600
|
+
};
|
|
8095
8601
|
const vnode_getNode = (vnode) => {
|
|
8096
8602
|
if (vnode === null || vnode_isVirtualVNode(vnode)) {
|
|
8097
8603
|
return null;
|
|
@@ -8451,13 +8957,15 @@ class DeserializationHandler {
|
|
|
8451
8957
|
}
|
|
8452
8958
|
const container = this.$container$;
|
|
8453
8959
|
let propValue = allocate(container, typeId, value);
|
|
8960
|
+
Reflect.set(target, property, propValue);
|
|
8961
|
+
this.$data$[idx] = undefined;
|
|
8962
|
+
this.$data$[idx + 1] = propValue;
|
|
8454
8963
|
/** We stored the reference, so now we can inflate, allowing cycles. */
|
|
8455
8964
|
if (typeId >= 14 /* TypeIds.Error */) {
|
|
8456
8965
|
propValue = inflate(container, propValue, typeId, value);
|
|
8966
|
+
Reflect.set(target, property, propValue);
|
|
8967
|
+
this.$data$[idx + 1] = propValue;
|
|
8457
8968
|
}
|
|
8458
|
-
Reflect.set(target, property, propValue);
|
|
8459
|
-
this.$data$[idx] = undefined;
|
|
8460
|
-
this.$data$[idx + 1] = propValue;
|
|
8461
8969
|
return propValue;
|
|
8462
8970
|
}
|
|
8463
8971
|
has(target, property) {
|
|
@@ -8636,7 +9144,7 @@ const inflate = (container, target, typeId, data) => {
|
|
|
8636
9144
|
*/
|
|
8637
9145
|
// try to download qrl in this tick
|
|
8638
9146
|
computed.$computeQrl$.resolve();
|
|
8639
|
-
container.$scheduler
|
|
9147
|
+
container.$scheduler$(1 /* ChoreType.QRL_RESOLVE */, null, computed.$computeQrl$);
|
|
8640
9148
|
}
|
|
8641
9149
|
break;
|
|
8642
9150
|
}
|
|
@@ -9424,8 +9932,8 @@ async function serialize(serializationContext) {
|
|
|
9424
9932
|
}
|
|
9425
9933
|
else if (value instanceof ComputedSignalImpl) {
|
|
9426
9934
|
let v = value.$untrackedValue$;
|
|
9427
|
-
const shouldAlwaysSerialize = value.$flags$ &
|
|
9428
|
-
const shouldNeverSerialize = value.$flags$ &
|
|
9935
|
+
const shouldAlwaysSerialize = value.$flags$ & 32 /* SerializationSignalFlags.SERIALIZATION_STRATEGY_ALWAYS */;
|
|
9936
|
+
const shouldNeverSerialize = value.$flags$ & 16 /* SerializationSignalFlags.SERIALIZATION_STRATEGY_NEVER */;
|
|
9429
9937
|
const isInvalid = value.$flags$ & 1 /* SignalFlags.INVALID */;
|
|
9430
9938
|
const isSkippable = fastSkipSerialize(value.$untrackedValue$);
|
|
9431
9939
|
if (shouldAlwaysSerialize) {
|
|
@@ -10767,7 +11275,7 @@ const render = async (parent, jsxNode, opts = {}) => {
|
|
|
10767
11275
|
container.$serverData$ = opts.serverData || {};
|
|
10768
11276
|
const host = container.rootVNode;
|
|
10769
11277
|
container.$scheduler$(4 /* ChoreType.NODE_DIFF */, host, host, jsxNode);
|
|
10770
|
-
await container.$scheduler$(255 /* ChoreType.
|
|
11278
|
+
await container.$scheduler$(255 /* ChoreType.WAIT_FOR_QUEUE */).$returnValue$;
|
|
10771
11279
|
return {
|
|
10772
11280
|
cleanup: () => {
|
|
10773
11281
|
cleanup(container, container.rootVNode);
|
|
@@ -11605,7 +12113,7 @@ const useVisibleTaskQrl = (qrl, opts) => {
|
|
|
11605
12113
|
useRunTask(task, eagerness);
|
|
11606
12114
|
if (!isServerPlatform()) {
|
|
11607
12115
|
qrl.resolve(iCtx.$element$);
|
|
11608
|
-
iCtx.$container$.$scheduler$(
|
|
12116
|
+
iCtx.$container$.$scheduler$(16 /* ChoreType.VISIBLE */, task);
|
|
11609
12117
|
}
|
|
11610
12118
|
};
|
|
11611
12119
|
const useRunTask = (task, eagerness) => {
|
|
@@ -11883,5 +12391,15 @@ const PREFETCH_CODE = /*#__PURE__*/ ((c // Service worker container
|
|
|
11883
12391
|
*/
|
|
11884
12392
|
const PrefetchGraph = (_opts = {}) => null;
|
|
11885
12393
|
|
|
11886
|
-
|
|
12394
|
+
//////////////////////////////////////////////////////////////////////////////////////////
|
|
12395
|
+
// Protect against duplicate imports
|
|
12396
|
+
//////////////////////////////////////////////////////////////////////////////////////////
|
|
12397
|
+
if (globalThis.__qwik) {
|
|
12398
|
+
console.error(`==============================================\n` +
|
|
12399
|
+
`Qwik version ${globalThis.__qwik} already imported while importing ${version}. Verify external vs bundled imports etc. This can lead to issues due to duplicated shared structures.\n` +
|
|
12400
|
+
`==============================================\n`);
|
|
12401
|
+
}
|
|
12402
|
+
globalThis.__qwik = version;
|
|
12403
|
+
|
|
12404
|
+
export { $, Fragment, NoSerializeSymbol, PrefetchGraph, PrefetchServiceWorker, RenderOnce, Resource, SSRComment, SSRRaw, SSRStream, SSRStreamBlock, SerializerSymbol, SkipRender, Slot, _CONST_PROPS, DomContainer as _DomContainer, _EFFECT_BACK_REF, EMPTY_ARRAY as _EMPTY_ARRAY, _IMMUTABLE, _SharedContainer, SubscriptionData as _SubscriptionData, _UNINITIALIZED, _VAR_PROPS, _deserialize, dumpState as _dumpState, _fnSignal, _getConstProps, _getContextContainer, _getContextElement, _getContextEvent, getDomContainer as _getDomContainer, _getQContainerElement, _getVarProps, _hasStoreEffects, isJSXNode as _isJSXNode, isStore as _isStore, isStringifiable as _isStringifiable, isTask as _isTask, _jsxBranch, _jsxC, _jsxQ, _jsxS, _jsxSorted, _jsxSplit, mapApp_findIndx as _mapApp_findIndx, mapArray_get as _mapArray_get, mapArray_set as _mapArray_set, _noopQrl, _noopQrlDEV, preprocessState as _preprocessState, _qrlSync, _regSymbol, _resolveContextWithoutSequentialScope, _restProps, _run, _serializationWeakRef, _serialize, scheduleTask as _task, verifySerializable as _verifySerializable, vnode_ensureElementInflated as _vnode_ensureElementInflated, vnode_getAttr as _vnode_getAttr, vnode_getAttrKeys as _vnode_getAttrKeys, vnode_getFirstChild as _vnode_getFirstChild, vnode_getNextSibling as _vnode_getNextSibling, vnode_getPropStartIndex as _vnode_getPropStartIndex, vnode_getProps as _vnode_getProps, vnode_isMaterialized as _vnode_isMaterialized, vnode_isTextVNode as _vnode_isTextVNode, vnode_isVirtualVNode as _vnode_isVirtualVNode, vnode_toString as _vnode_toString, _waitUntilRendered, _walkJSX, _wrapProp, _wrapSignal, component$, componentQrl, createAsyncComputed$, createAsyncComputedSignal as createAsyncComputedQrl, createComputed$, createComputedSignal as createComputedQrl, createContextId, h as createElement, createSerializer$, createSerializerSignal as createSerializerQrl, createSignal, event$, eventQrl, forceStoreEffects, getDomContainer, getLocale, getPlatform, h, implicit$FirstArg, inlinedQrl, inlinedQrlDEV, isSignal, jsx, jsxDEV, jsx as jsxs, noSerialize, qrl, qrlDEV, render, setPlatform, sync$, untrack, unwrapStore, useAsyncComputed$, useAsyncComputedQrl, useComputed$, useComputedQrl, useConstant, useContext, useContextProvider, useErrorBoundary, useId, useLexicalScope, useOn, useOnDocument, useOnWindow, useResource$, useResourceQrl, useSerializer$, useSerializerQrl, useServerData, useSignal, useStore, useStyles$, useStylesQrl, useStylesScoped$, useStylesScopedQrl, useTask$, useTaskQrl, useVisibleTask$, useVisibleTaskQrl, version, withLocale };
|
|
11887
12405
|
//# sourceMappingURL=core.mjs.map
|