@qwik.dev/core 2.0.0-beta.7 → 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 +17 -17
- package/dist/core-internal.d.ts +112 -56
- package/dist/core.cjs +1022 -469
- package/dist/core.cjs.map +1 -1
- package/dist/core.min.mjs +1 -1
- package/dist/core.mjs +1018 -469
- package/dist/core.mjs.map +1 -1
- package/dist/core.prod.cjs +654 -361
- package/dist/core.prod.mjs +729 -373
- package/dist/loader/index.cjs +2 -2
- package/dist/loader/index.mjs +2 -2
- package/dist/loader/package.json +1 -1
- package/dist/optimizer.cjs +78 -76
- package/dist/optimizer.mjs +78 -78
- package/dist/qwikloader.debug.js +0 -13
- package/dist/qwikloader.js +1 -1
- package/dist/server.cjs +217 -63
- package/dist/server.d.ts +9 -0
- package/dist/server.mjs +213 -63
- package/dist/starters/features/auth/package.json +1 -1
- package/dist/starters/features/localize/package.json +3 -3
- package/dist/starters/features/pandacss/package.json +1 -1
- package/dist/starters/features/playwright/playwright-report/index.html +943 -903
- package/dist/starters/features/postcss/postcss.config.js +1 -1
- package/dist/starters/features/tailwind/package.json +2 -2
- package/dist/starters/features/tailwind/prettier.config.js +10 -0
- package/dist/starters/features/tailwind-v3/package.json +1 -1
- package/dist/starters/features/tailwind-v3/prettier.config.js +10 -0
- package/dist/testing/index.cjs +3826 -952
- package/dist/testing/index.d.ts +972 -1
- package/dist/testing/index.mjs +3811 -946
- package/dist/testing/package.json +1 -1
- package/package.json +8 -6
- package/dist/starters/features/tailwind/.prettierrc.js +0 -3
package/dist/core.cjs
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
|
|
@@ -11,6 +11,13 @@
|
|
|
11
11
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.qwikCore = {}, global.qwikBuild, global.qwikPreloader));
|
|
12
12
|
})(this, (function (exports, build, preloader) { 'use strict';
|
|
13
13
|
|
|
14
|
+
/**
|
|
15
|
+
* QWIK_VERSION
|
|
16
|
+
*
|
|
17
|
+
* @public
|
|
18
|
+
*/
|
|
19
|
+
const version = "2.0.0-beta.9-dev+6b582c7";
|
|
20
|
+
|
|
14
21
|
// same as isDev but separate so we can test
|
|
15
22
|
const qDev = globalThis.qDev !== false;
|
|
16
23
|
const qInspector = globalThis.qInspector === true;
|
|
@@ -88,6 +95,9 @@
|
|
|
88
95
|
const isString = (v) => {
|
|
89
96
|
return typeof v === 'string';
|
|
90
97
|
};
|
|
98
|
+
const isNumber$1 = (v) => {
|
|
99
|
+
return typeof v === 'number';
|
|
100
|
+
};
|
|
91
101
|
const isFunction = (v) => {
|
|
92
102
|
return typeof v === 'function';
|
|
93
103
|
};
|
|
@@ -290,13 +300,6 @@
|
|
|
290
300
|
});
|
|
291
301
|
});
|
|
292
302
|
},
|
|
293
|
-
nextTick: (fn) => {
|
|
294
|
-
return new Promise((resolve) => {
|
|
295
|
-
setTimeout(() => {
|
|
296
|
-
resolve(fn());
|
|
297
|
-
});
|
|
298
|
-
});
|
|
299
|
-
},
|
|
300
303
|
chunkForSymbol(symbolName, chunk) {
|
|
301
304
|
return [symbolName, chunk ?? '_'];
|
|
302
305
|
},
|
|
@@ -554,6 +557,13 @@
|
|
|
554
557
|
this.$container$ = container;
|
|
555
558
|
this.$untrackedValue$ = value;
|
|
556
559
|
}
|
|
560
|
+
/**
|
|
561
|
+
* Use this to force running subscribers, for example when the calculated value has mutated but
|
|
562
|
+
* remained the same object
|
|
563
|
+
*/
|
|
564
|
+
force() {
|
|
565
|
+
this.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */, null, this, this.$effects$);
|
|
566
|
+
}
|
|
557
567
|
get untrackedValue() {
|
|
558
568
|
return this.$untrackedValue$;
|
|
559
569
|
}
|
|
@@ -567,14 +577,7 @@
|
|
|
567
577
|
set value(value) {
|
|
568
578
|
if (value !== this.$untrackedValue$) {
|
|
569
579
|
this.$untrackedValue$ = value;
|
|
570
|
-
|
|
571
|
-
triggerEffects(this.$container$, this, this.$effects$);
|
|
572
|
-
// this.$container$?.$scheduler$(
|
|
573
|
-
// ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS,
|
|
574
|
-
// null,
|
|
575
|
-
// this,
|
|
576
|
-
// this.$effects$
|
|
577
|
-
// );
|
|
580
|
+
this.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */, null, this, this.$effects$);
|
|
578
581
|
}
|
|
579
582
|
}
|
|
580
583
|
// prevent accidental use as value
|
|
@@ -636,12 +639,11 @@
|
|
|
636
639
|
$funcStr$;
|
|
637
640
|
$flags$;
|
|
638
641
|
$hostElement$ = null;
|
|
639
|
-
$forceRunEffects$ = false;
|
|
640
642
|
[_EFFECT_BACK_REF] = null;
|
|
641
643
|
constructor(container, fn, args, fnStr,
|
|
642
644
|
// We need a separate flag to know when the computation needs running because
|
|
643
645
|
// we need the old value to know if effects need running after computation
|
|
644
|
-
flags = 1 /* SignalFlags.INVALID */ |
|
|
646
|
+
flags = 1 /* SignalFlags.INVALID */ | 4 /* WrappedSignalFlags.UNWRAP */) {
|
|
645
647
|
super(container, NEEDS_COMPUTATION);
|
|
646
648
|
this.$args$ = args;
|
|
647
649
|
this.$func$ = fn;
|
|
@@ -650,7 +652,6 @@
|
|
|
650
652
|
}
|
|
651
653
|
invalidate() {
|
|
652
654
|
this.$flags$ |= 1 /* SignalFlags.INVALID */;
|
|
653
|
-
this.$forceRunEffects$ = false;
|
|
654
655
|
this.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */, this.$hostElement$, this, this.$effects$);
|
|
655
656
|
}
|
|
656
657
|
/**
|
|
@@ -658,29 +659,26 @@
|
|
|
658
659
|
* remained the same object.
|
|
659
660
|
*/
|
|
660
661
|
force() {
|
|
661
|
-
this.$
|
|
662
|
+
this.$flags$ |= 2 /* SignalFlags.RUN_EFFECTS */;
|
|
662
663
|
this.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */, this.$hostElement$, this, this.$effects$);
|
|
663
664
|
}
|
|
664
665
|
get untrackedValue() {
|
|
665
|
-
|
|
666
|
-
if (didChange) {
|
|
667
|
-
this.$forceRunEffects$ = didChange;
|
|
668
|
-
}
|
|
666
|
+
this.$computeIfNeeded$();
|
|
669
667
|
assertFalse(this.$untrackedValue$ === NEEDS_COMPUTATION, 'Invalid state');
|
|
670
668
|
return this.$untrackedValue$;
|
|
671
669
|
}
|
|
672
670
|
$computeIfNeeded$() {
|
|
673
671
|
if (!(this.$flags$ & 1 /* SignalFlags.INVALID */)) {
|
|
674
|
-
return
|
|
672
|
+
return;
|
|
675
673
|
}
|
|
676
674
|
const untrackedValue = trackSignal(() => this.$func$(...this.$args$), this, "." /* EffectProperty.VNODE */, this.$container$);
|
|
677
|
-
// TODO: we should remove invalid flag here
|
|
675
|
+
// TODO: we should remove invalid flag here, but some tests are failing
|
|
678
676
|
// this.$flags$ &= ~SignalFlags.INVALID;
|
|
679
677
|
const didChange = untrackedValue !== this.$untrackedValue$;
|
|
680
678
|
if (didChange) {
|
|
679
|
+
this.$flags$ |= 2 /* SignalFlags.RUN_EFFECTS */;
|
|
681
680
|
this.$untrackedValue$ = untrackedValue;
|
|
682
681
|
}
|
|
683
|
-
return didChange;
|
|
684
682
|
}
|
|
685
683
|
// Make this signal read-only
|
|
686
684
|
set value(_) {
|
|
@@ -875,12 +873,26 @@
|
|
|
875
873
|
};
|
|
876
874
|
/** @internal */
|
|
877
875
|
const _waitUntilRendered = (elm) => {
|
|
878
|
-
const
|
|
879
|
-
if (!
|
|
876
|
+
const container = _getQContainerElement(elm)?.qContainer;
|
|
877
|
+
if (!container) {
|
|
880
878
|
return Promise.resolve();
|
|
881
879
|
}
|
|
882
|
-
|
|
883
|
-
|
|
880
|
+
// Multi-cycle idle: loop WAIT_FOR_QUEUE until the flush epoch stays stable
|
|
881
|
+
// across an extra microtask, which signals that no new work re-scheduled.
|
|
882
|
+
return (async () => {
|
|
883
|
+
for (;;) {
|
|
884
|
+
await container.$scheduler$(255 /* ChoreType.WAIT_FOR_QUEUE */).$returnValue$;
|
|
885
|
+
const firstEpoch = container.$flushEpoch$ || 0;
|
|
886
|
+
// Give a microtask for any immediate follow-up scheduling to enqueue
|
|
887
|
+
await Promise.resolve();
|
|
888
|
+
const secondEpoch = container.$flushEpoch$ || 0;
|
|
889
|
+
// If no epoch change occurred during and after WAIT_FOR_QUEUE, we are idle.
|
|
890
|
+
if (firstEpoch === secondEpoch) {
|
|
891
|
+
return;
|
|
892
|
+
}
|
|
893
|
+
// Continue loop if epoch advanced, meaning more work flushed.
|
|
894
|
+
}
|
|
895
|
+
})();
|
|
884
896
|
};
|
|
885
897
|
|
|
886
898
|
/**
|
|
@@ -958,7 +970,7 @@
|
|
|
958
970
|
}
|
|
959
971
|
return null; // Return null if not matching expected format
|
|
960
972
|
}
|
|
961
|
-
function eventNameToJsxEvent(eventName, prefix
|
|
973
|
+
function eventNameToJsxEvent(eventName, prefix) {
|
|
962
974
|
eventName = eventName.charAt(0).toUpperCase() + eventName.substring(1);
|
|
963
975
|
return prefix + eventName + EVENT_SUFFIX;
|
|
964
976
|
}
|
|
@@ -1247,13 +1259,6 @@
|
|
|
1247
1259
|
return true;
|
|
1248
1260
|
};
|
|
1249
1261
|
|
|
1250
|
-
/**
|
|
1251
|
-
* QWIK_VERSION
|
|
1252
|
-
*
|
|
1253
|
-
* @public
|
|
1254
|
-
*/
|
|
1255
|
-
const version = "2.0.0-beta.7-dev+2dd89a6";
|
|
1256
|
-
|
|
1257
1262
|
/** @internal */
|
|
1258
1263
|
const EMPTY_ARRAY = [];
|
|
1259
1264
|
const EMPTY_OBJ = {};
|
|
@@ -1394,7 +1399,7 @@
|
|
|
1394
1399
|
*
|
|
1395
1400
|
* @internal
|
|
1396
1401
|
*/
|
|
1397
|
-
const
|
|
1402
|
+
const _run = (...args) => {
|
|
1398
1403
|
// This will already check container
|
|
1399
1404
|
const [runQrl] = useLexicalScope();
|
|
1400
1405
|
const context = getInvokeContext();
|
|
@@ -1408,7 +1413,9 @@
|
|
|
1408
1413
|
if (!scheduler) {
|
|
1409
1414
|
throw qError(1 /* QError.schedulerNotFound */);
|
|
1410
1415
|
}
|
|
1411
|
-
return
|
|
1416
|
+
// We don't return anything, the scheduler is in charge now
|
|
1417
|
+
const chore = scheduler(2 /* ChoreType.RUN_QRL */, hostElement, runQrl, args);
|
|
1418
|
+
return getChorePromise(chore);
|
|
1412
1419
|
};
|
|
1413
1420
|
|
|
1414
1421
|
/** @internal */
|
|
@@ -1432,17 +1439,17 @@
|
|
|
1432
1439
|
return (bottom << 1) ^ -1;
|
|
1433
1440
|
};
|
|
1434
1441
|
/** @internal */
|
|
1435
|
-
const mapArray_set = (array, key, value, start) => {
|
|
1442
|
+
const mapArray_set = (array, key, value, start, allowNullValue = false) => {
|
|
1436
1443
|
const indx = mapApp_findIndx(array, key, start);
|
|
1437
1444
|
if (indx >= 0) {
|
|
1438
|
-
if (value == null) {
|
|
1445
|
+
if (value == null && !allowNullValue) {
|
|
1439
1446
|
array.splice(indx, 2);
|
|
1440
1447
|
}
|
|
1441
1448
|
else {
|
|
1442
1449
|
array[indx + 1] = value;
|
|
1443
1450
|
}
|
|
1444
1451
|
}
|
|
1445
|
-
else if (value != null) {
|
|
1452
|
+
else if (value != null || allowNullValue) {
|
|
1446
1453
|
array.splice(indx ^ -1, 0, key, value);
|
|
1447
1454
|
}
|
|
1448
1455
|
};
|
|
@@ -1456,6 +1463,9 @@
|
|
|
1456
1463
|
return null;
|
|
1457
1464
|
}
|
|
1458
1465
|
};
|
|
1466
|
+
const mapArray_has = (array, key, start) => {
|
|
1467
|
+
return mapApp_findIndx(array, key, start) >= 0;
|
|
1468
|
+
};
|
|
1459
1469
|
|
|
1460
1470
|
/** @internal */
|
|
1461
1471
|
const _CONST_PROPS = Symbol('CONST');
|
|
@@ -1529,13 +1539,12 @@
|
|
|
1529
1539
|
*/
|
|
1530
1540
|
$computeQrl$;
|
|
1531
1541
|
$flags$;
|
|
1532
|
-
$forceRunEffects$ = false;
|
|
1533
1542
|
[_EFFECT_BACK_REF] = null;
|
|
1534
1543
|
constructor(container, fn,
|
|
1535
1544
|
// We need a separate flag to know when the computation needs running because
|
|
1536
1545
|
// we need the old value to know if effects need running after computation
|
|
1537
1546
|
flags = 1 /* SignalFlags.INVALID */ |
|
|
1538
|
-
|
|
1547
|
+
32 /* SerializationSignalFlags.SERIALIZATION_STRATEGY_ALWAYS */) {
|
|
1539
1548
|
// The value is used for comparison when signals trigger, which can only happen
|
|
1540
1549
|
// when it was calculated before. Therefore we can pass whatever we like.
|
|
1541
1550
|
super(container, NEEDS_COMPUTATION);
|
|
@@ -1544,7 +1553,6 @@
|
|
|
1544
1553
|
}
|
|
1545
1554
|
invalidate() {
|
|
1546
1555
|
this.$flags$ |= 1 /* SignalFlags.INVALID */;
|
|
1547
|
-
this.$forceRunEffects$ = false;
|
|
1548
1556
|
this.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */, null, this, this.$effects$);
|
|
1549
1557
|
}
|
|
1550
1558
|
/**
|
|
@@ -1552,20 +1560,17 @@
|
|
|
1552
1560
|
* remained the same object
|
|
1553
1561
|
*/
|
|
1554
1562
|
force() {
|
|
1555
|
-
this.$
|
|
1556
|
-
|
|
1563
|
+
this.$flags$ |= 2 /* SignalFlags.RUN_EFFECTS */;
|
|
1564
|
+
super.force();
|
|
1557
1565
|
}
|
|
1558
1566
|
get untrackedValue() {
|
|
1559
|
-
|
|
1560
|
-
if (didChange) {
|
|
1561
|
-
this.$forceRunEffects$ = didChange;
|
|
1562
|
-
}
|
|
1567
|
+
this.$computeIfNeeded$();
|
|
1563
1568
|
assertFalse(this.$untrackedValue$ === NEEDS_COMPUTATION, 'Invalid state');
|
|
1564
1569
|
return this.$untrackedValue$;
|
|
1565
1570
|
}
|
|
1566
1571
|
$computeIfNeeded$() {
|
|
1567
1572
|
if (!(this.$flags$ & 1 /* SignalFlags.INVALID */)) {
|
|
1568
|
-
return
|
|
1573
|
+
return;
|
|
1569
1574
|
}
|
|
1570
1575
|
const computeQrl = this.$computeQrl$;
|
|
1571
1576
|
throwIfQRLNotResolved(computeQrl);
|
|
@@ -1584,9 +1589,12 @@
|
|
|
1584
1589
|
this.$flags$ &= ~1 /* SignalFlags.INVALID */;
|
|
1585
1590
|
const didChange = untrackedValue !== this.$untrackedValue$;
|
|
1586
1591
|
if (didChange) {
|
|
1592
|
+
// skip first computation when value is not changed
|
|
1593
|
+
if (this.$untrackedValue$ !== NEEDS_COMPUTATION) {
|
|
1594
|
+
this.$flags$ |= 2 /* SignalFlags.RUN_EFFECTS */;
|
|
1595
|
+
}
|
|
1587
1596
|
this.$untrackedValue$ = untrackedValue;
|
|
1588
1597
|
}
|
|
1589
|
-
return didChange;
|
|
1590
1598
|
}
|
|
1591
1599
|
finally {
|
|
1592
1600
|
if (ctx) {
|
|
@@ -1612,12 +1620,12 @@
|
|
|
1612
1620
|
*/
|
|
1613
1621
|
class SerializerSignalImpl extends ComputedSignalImpl {
|
|
1614
1622
|
constructor(container, argQrl) {
|
|
1615
|
-
super(container, argQrl, 1 /* SignalFlags.INVALID */ |
|
|
1623
|
+
super(container, argQrl, 1 /* SignalFlags.INVALID */ | 32 /* SerializationSignalFlags.SERIALIZATION_STRATEGY_ALWAYS */);
|
|
1616
1624
|
}
|
|
1617
1625
|
$didInitialize$ = false;
|
|
1618
1626
|
$computeIfNeeded$() {
|
|
1619
1627
|
if (!(this.$flags$ & 1 /* SignalFlags.INVALID */)) {
|
|
1620
|
-
return
|
|
1628
|
+
return;
|
|
1621
1629
|
}
|
|
1622
1630
|
throwIfQRLNotResolved(this.$computeQrl$);
|
|
1623
1631
|
let arg = this.$computeQrl$.resolved;
|
|
@@ -1635,9 +1643,9 @@
|
|
|
1635
1643
|
this.$flags$ &= -2 /* SignalFlags.INVALID */;
|
|
1636
1644
|
this.$didInitialize$ = true;
|
|
1637
1645
|
if (didChange) {
|
|
1646
|
+
this.$flags$ |= 2 /* SignalFlags.RUN_EFFECTS */;
|
|
1638
1647
|
this.$untrackedValue$ = untrackedValue;
|
|
1639
1648
|
}
|
|
1640
|
-
return didChange;
|
|
1641
1649
|
}
|
|
1642
1650
|
}
|
|
1643
1651
|
|
|
@@ -1647,6 +1655,28 @@
|
|
|
1647
1655
|
const getStoreTarget = (value) => {
|
|
1648
1656
|
return value?.[STORE_TARGET] || null;
|
|
1649
1657
|
};
|
|
1658
|
+
/**
|
|
1659
|
+
* Force a store to recompute and schedule effects.
|
|
1660
|
+
*
|
|
1661
|
+
* @public
|
|
1662
|
+
*/
|
|
1663
|
+
const forceStoreEffects = (value, prop) => {
|
|
1664
|
+
const handler = getStoreHandler(value);
|
|
1665
|
+
if (handler) {
|
|
1666
|
+
handler.force(prop);
|
|
1667
|
+
}
|
|
1668
|
+
};
|
|
1669
|
+
/**
|
|
1670
|
+
* @returns True if the store has effects for the given prop
|
|
1671
|
+
* @internal
|
|
1672
|
+
*/
|
|
1673
|
+
const _hasStoreEffects = (value, prop) => {
|
|
1674
|
+
const handler = getStoreHandler(value);
|
|
1675
|
+
if (handler) {
|
|
1676
|
+
return (handler.$effects$?.get(prop)?.size ?? 0) > 0;
|
|
1677
|
+
}
|
|
1678
|
+
return false;
|
|
1679
|
+
};
|
|
1650
1680
|
/**
|
|
1651
1681
|
* Get the original object that was wrapped by the store. Useful if you want to clone a store
|
|
1652
1682
|
* (structuredClone, IndexedDB,...)
|
|
@@ -1685,7 +1715,12 @@
|
|
|
1685
1715
|
toString() {
|
|
1686
1716
|
return '[Store]';
|
|
1687
1717
|
}
|
|
1718
|
+
force(prop) {
|
|
1719
|
+
const target = getStoreTarget(this);
|
|
1720
|
+
this.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */, null, this, getEffects(target, prop, this.$effects$));
|
|
1721
|
+
}
|
|
1688
1722
|
get(target, prop) {
|
|
1723
|
+
// TODO(perf): handle better `slice` calls
|
|
1689
1724
|
if (typeof prop === 'symbol') {
|
|
1690
1725
|
if (prop === STORE_TARGET) {
|
|
1691
1726
|
return target;
|
|
@@ -1748,7 +1783,11 @@
|
|
|
1748
1783
|
if (typeof prop != 'string' || !delete target[prop]) {
|
|
1749
1784
|
return false;
|
|
1750
1785
|
}
|
|
1751
|
-
|
|
1786
|
+
if (!Array.isArray(target)) {
|
|
1787
|
+
// If the target is an array, we don't need to trigger effects.
|
|
1788
|
+
// Changing the length property will trigger effects.
|
|
1789
|
+
this.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */, null, this, getEffects(target, prop, this.$effects$));
|
|
1790
|
+
}
|
|
1752
1791
|
return true;
|
|
1753
1792
|
}
|
|
1754
1793
|
has(target, prop) {
|
|
@@ -1807,8 +1846,10 @@
|
|
|
1807
1846
|
}
|
|
1808
1847
|
function setNewValueAndTriggerEffects(prop, value, target, currentStore) {
|
|
1809
1848
|
target[prop] = value;
|
|
1810
|
-
|
|
1811
|
-
|
|
1849
|
+
const effects = getEffects(target, prop, currentStore.$effects$);
|
|
1850
|
+
if (effects) {
|
|
1851
|
+
currentStore.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */, null, currentStore, effects);
|
|
1852
|
+
}
|
|
1812
1853
|
}
|
|
1813
1854
|
function getEffects(target, prop, storeEffects) {
|
|
1814
1855
|
let effectsToTrigger;
|
|
@@ -1936,7 +1977,7 @@
|
|
|
1936
1977
|
}
|
|
1937
1978
|
$computeIfNeeded$() {
|
|
1938
1979
|
if (!(this.$flags$ & 1 /* SignalFlags.INVALID */)) {
|
|
1939
|
-
return
|
|
1980
|
+
return;
|
|
1940
1981
|
}
|
|
1941
1982
|
const computeQrl = this.$computeQrl$;
|
|
1942
1983
|
throwIfQRLNotResolved(computeQrl);
|
|
@@ -1966,6 +2007,7 @@
|
|
|
1966
2007
|
this.$flags$ &= -2 /* SignalFlags.INVALID */;
|
|
1967
2008
|
const didChange = untrackedValue !== this.$untrackedValue$;
|
|
1968
2009
|
if (didChange) {
|
|
2010
|
+
this.$flags$ |= 2 /* SignalFlags.RUN_EFFECTS */;
|
|
1969
2011
|
this.$untrackedValue$ = untrackedValue;
|
|
1970
2012
|
}
|
|
1971
2013
|
return didChange;
|
|
@@ -2053,7 +2095,7 @@
|
|
|
2053
2095
|
if (!(obj instanceof AsyncComputedSignalImpl)) {
|
|
2054
2096
|
assertEqual(prop, 'value', 'Left side is a signal, prop must be value');
|
|
2055
2097
|
}
|
|
2056
|
-
if (obj instanceof WrappedSignalImpl && obj.flags &
|
|
2098
|
+
if (obj instanceof WrappedSignalImpl && obj.flags & 4 /* WrappedSignalFlags.UNWRAP */) {
|
|
2057
2099
|
return obj;
|
|
2058
2100
|
}
|
|
2059
2101
|
return getWrapped(args);
|
|
@@ -2114,7 +2156,7 @@
|
|
|
2114
2156
|
return !prop.startsWith('q:') && !prop.startsWith(NON_SERIALIZABLE_MARKER_PREFIX);
|
|
2115
2157
|
}
|
|
2116
2158
|
/** @internal */
|
|
2117
|
-
const _restProps = (props, omit, target = {}) => {
|
|
2159
|
+
const _restProps = (props, omit = [], target = {}) => {
|
|
2118
2160
|
let constPropsTarget = null;
|
|
2119
2161
|
const constProps = props[_CONST_PROPS];
|
|
2120
2162
|
if (constProps) {
|
|
@@ -2569,12 +2611,12 @@
|
|
|
2569
2611
|
}
|
|
2570
2612
|
if (targetElement) {
|
|
2571
2613
|
if (targetElement.type === 'script' && key === qVisibleEvent) {
|
|
2572
|
-
eventKey = 'document:
|
|
2614
|
+
eventKey = 'document:onQInit$';
|
|
2573
2615
|
logWarn('You are trying to add an event "' +
|
|
2574
2616
|
key +
|
|
2575
2617
|
'" using `useVisibleTask$` hook, ' +
|
|
2576
2618
|
'but a node to which you can add an event is not found. ' +
|
|
2577
|
-
'Using document:
|
|
2619
|
+
'Using document:onQInit$ instead.');
|
|
2578
2620
|
}
|
|
2579
2621
|
addUseOnEvent(targetElement, eventKey, useOnEvents[key]);
|
|
2580
2622
|
}
|
|
@@ -2697,13 +2739,13 @@
|
|
|
2697
2739
|
if (srcProps && srcProps.children) {
|
|
2698
2740
|
delete srcProps.children;
|
|
2699
2741
|
}
|
|
2700
|
-
const scheduler = ssr.$scheduler$;
|
|
2701
2742
|
host.setProp(OnRenderProp, componentQrl);
|
|
2702
2743
|
host.setProp(ELEMENT_PROPS, srcProps);
|
|
2703
2744
|
if (jsx.key !== null) {
|
|
2704
2745
|
host.setProp(ELEMENT_KEY, jsx.key);
|
|
2705
2746
|
}
|
|
2706
|
-
|
|
2747
|
+
const componentChore = ssr.$scheduler$(6 /* ChoreType.COMPONENT */, host, componentQrl, srcProps);
|
|
2748
|
+
return getChorePromise(componentChore);
|
|
2707
2749
|
};
|
|
2708
2750
|
|
|
2709
2751
|
class ParentComponentData {
|
|
@@ -2811,7 +2853,14 @@
|
|
|
2811
2853
|
appendQwikInspectorAttribute(jsx, qwikInspectorAttrValue);
|
|
2812
2854
|
}
|
|
2813
2855
|
}
|
|
2814
|
-
const innerHTML = ssr.openElement(type, varPropsToSsrAttrs(jsx.varProps, jsx.constProps,
|
|
2856
|
+
const innerHTML = ssr.openElement(type, varPropsToSsrAttrs(jsx.varProps, jsx.constProps, {
|
|
2857
|
+
serializationCtx: ssr.serializationCtx,
|
|
2858
|
+
styleScopedId: options.styleScoped,
|
|
2859
|
+
key: jsx.key,
|
|
2860
|
+
}), constPropsToSsrAttrs(jsx.constProps, jsx.varProps, {
|
|
2861
|
+
serializationCtx: ssr.serializationCtx,
|
|
2862
|
+
styleScopedId: options.styleScoped,
|
|
2863
|
+
}), qwikInspectorAttrValue);
|
|
2815
2864
|
if (innerHTML) {
|
|
2816
2865
|
ssr.htmlNode(innerHTML);
|
|
2817
2866
|
}
|
|
@@ -2927,16 +2976,17 @@
|
|
|
2927
2976
|
}
|
|
2928
2977
|
}
|
|
2929
2978
|
}
|
|
2930
|
-
function varPropsToSsrAttrs(varProps, constProps,
|
|
2931
|
-
return toSsrAttrs(varProps, constProps,
|
|
2979
|
+
function varPropsToSsrAttrs(varProps, constProps, options) {
|
|
2980
|
+
return toSsrAttrs(varProps, constProps, false, options);
|
|
2932
2981
|
}
|
|
2933
|
-
function constPropsToSsrAttrs(constProps, varProps,
|
|
2934
|
-
return toSsrAttrs(constProps, varProps,
|
|
2982
|
+
function constPropsToSsrAttrs(constProps, varProps, options) {
|
|
2983
|
+
return toSsrAttrs(constProps, varProps, true, options);
|
|
2935
2984
|
}
|
|
2936
|
-
function toSsrAttrs(record, anotherRecord,
|
|
2985
|
+
function toSsrAttrs(record, anotherRecord, isConst, options) {
|
|
2937
2986
|
if (record == null) {
|
|
2938
2987
|
return null;
|
|
2939
2988
|
}
|
|
2989
|
+
const pushMergedEventProps = !isConst;
|
|
2940
2990
|
const ssrAttrs = [];
|
|
2941
2991
|
for (const key in record) {
|
|
2942
2992
|
let value = record[key];
|
|
@@ -2973,7 +3023,7 @@
|
|
|
2973
3023
|
}
|
|
2974
3024
|
}
|
|
2975
3025
|
}
|
|
2976
|
-
const eventValue = setEvent(serializationCtx, key, value);
|
|
3026
|
+
const eventValue = setEvent(options.serializationCtx, key, value);
|
|
2977
3027
|
if (eventValue) {
|
|
2978
3028
|
ssrAttrs.push(jsxEventToHtmlAttribute(key), eventValue);
|
|
2979
3029
|
}
|
|
@@ -2983,7 +3033,7 @@
|
|
|
2983
3033
|
// write signal as is. We will track this signal inside `writeAttrs`
|
|
2984
3034
|
if (isClassAttr(key)) {
|
|
2985
3035
|
// additionally append styleScopedId for class attr
|
|
2986
|
-
ssrAttrs.push(key, [value, styleScopedId]);
|
|
3036
|
+
ssrAttrs.push(key, [value, options.styleScopedId]);
|
|
2987
3037
|
}
|
|
2988
3038
|
else {
|
|
2989
3039
|
ssrAttrs.push(key, value);
|
|
@@ -2991,13 +3041,13 @@
|
|
|
2991
3041
|
continue;
|
|
2992
3042
|
}
|
|
2993
3043
|
if (isPreventDefault(key)) {
|
|
2994
|
-
addPreventDefaultEventToSerializationContext(serializationCtx, key);
|
|
3044
|
+
addPreventDefaultEventToSerializationContext(options.serializationCtx, key);
|
|
2995
3045
|
}
|
|
2996
|
-
value = serializeAttribute(key, value, styleScopedId);
|
|
3046
|
+
value = serializeAttribute(key, value, options.styleScopedId);
|
|
2997
3047
|
ssrAttrs.push(key, value);
|
|
2998
3048
|
}
|
|
2999
|
-
if (key != null) {
|
|
3000
|
-
ssrAttrs.push(ELEMENT_KEY, key);
|
|
3049
|
+
if (options.key != null) {
|
|
3050
|
+
ssrAttrs.push(ELEMENT_KEY, options.key);
|
|
3001
3051
|
}
|
|
3002
3052
|
return ssrAttrs;
|
|
3003
3053
|
}
|
|
@@ -3046,7 +3096,7 @@
|
|
|
3046
3096
|
* For internal qrls (starting with `_`) we assume that they do the right thing.
|
|
3047
3097
|
*/
|
|
3048
3098
|
if (!qrl.$symbol$.startsWith('_') && (qrl.$captureRef$ || qrl.$capture$)) {
|
|
3049
|
-
qrl = createQRL(null, '_run',
|
|
3099
|
+
qrl = createQRL(null, '_run', _run, null, null, [qrl]);
|
|
3050
3100
|
}
|
|
3051
3101
|
return qrlToString(serializationCtx, qrl);
|
|
3052
3102
|
};
|
|
@@ -3126,10 +3176,9 @@
|
|
|
3126
3176
|
// deleted and we need to be able to release the task subscriptions.
|
|
3127
3177
|
set(task);
|
|
3128
3178
|
const container = iCtx.$container$;
|
|
3129
|
-
const
|
|
3130
|
-
if (isPromise(
|
|
3131
|
-
|
|
3132
|
-
promise.catch(() => { });
|
|
3179
|
+
const result = runTask(task, container, iCtx.$hostElement$);
|
|
3180
|
+
if (isPromise(result)) {
|
|
3181
|
+
throw result;
|
|
3133
3182
|
}
|
|
3134
3183
|
};
|
|
3135
3184
|
const runTask = (task, container, host) => {
|
|
@@ -3141,7 +3190,7 @@
|
|
|
3141
3190
|
const track = trackFn(task, container);
|
|
3142
3191
|
const [cleanup] = cleanupFn(task, (reason) => container.handleError(reason, host));
|
|
3143
3192
|
const taskApi = { track, cleanup };
|
|
3144
|
-
|
|
3193
|
+
return safeCall(() => taskFn(taskApi), cleanup, (err) => {
|
|
3145
3194
|
// If a Promise is thrown, that means we need to re-run the task.
|
|
3146
3195
|
if (isPromise(err)) {
|
|
3147
3196
|
return err.then(() => runTask(task, container, host));
|
|
@@ -3150,7 +3199,6 @@
|
|
|
3150
3199
|
throw err;
|
|
3151
3200
|
}
|
|
3152
3201
|
});
|
|
3153
|
-
return result;
|
|
3154
3202
|
};
|
|
3155
3203
|
const cleanupTask = (task) => {
|
|
3156
3204
|
const destroy = task.$destroy$;
|
|
@@ -3192,7 +3240,7 @@
|
|
|
3192
3240
|
*/
|
|
3193
3241
|
const scheduleTask = (_event, element) => {
|
|
3194
3242
|
const [task] = useLexicalScope();
|
|
3195
|
-
const type = task.$flags$ & 1 /* TaskFlags.VISIBLE_TASK */ ?
|
|
3243
|
+
const type = task.$flags$ & 1 /* TaskFlags.VISIBLE_TASK */ ? 16 /* ChoreType.VISIBLE */ : 3 /* ChoreType.TASK */;
|
|
3196
3244
|
const container = getDomContainer(element);
|
|
3197
3245
|
container.$scheduler$(type, task);
|
|
3198
3246
|
};
|
|
@@ -3444,7 +3492,7 @@
|
|
|
3444
3492
|
? this.$constProps$[prop]
|
|
3445
3493
|
: this.$varProps$[prop];
|
|
3446
3494
|
// a proxied value that the optimizer made
|
|
3447
|
-
return value instanceof WrappedSignalImpl && value.$flags$ &
|
|
3495
|
+
return value instanceof WrappedSignalImpl && value.$flags$ & 4 /* WrappedSignalFlags.UNWRAP */
|
|
3448
3496
|
? value.value
|
|
3449
3497
|
: value;
|
|
3450
3498
|
}
|
|
@@ -3520,6 +3568,24 @@
|
|
|
3520
3568
|
const directGetPropsProxyProp = (jsx, prop) => {
|
|
3521
3569
|
return (jsx.constProps && prop in jsx.constProps ? jsx.constProps[prop] : jsx.varProps[prop]);
|
|
3522
3570
|
};
|
|
3571
|
+
/** @internal */
|
|
3572
|
+
const _getVarProps = (props) => {
|
|
3573
|
+
if (!props) {
|
|
3574
|
+
return null;
|
|
3575
|
+
}
|
|
3576
|
+
return _VAR_PROPS in props
|
|
3577
|
+
? 'children' in props
|
|
3578
|
+
? { ...props[_VAR_PROPS], children: props.children }
|
|
3579
|
+
: props[_VAR_PROPS]
|
|
3580
|
+
: props;
|
|
3581
|
+
};
|
|
3582
|
+
/** @internal */
|
|
3583
|
+
const _getConstProps = (props) => {
|
|
3584
|
+
if (!props) {
|
|
3585
|
+
return null;
|
|
3586
|
+
}
|
|
3587
|
+
return _CONST_PROPS in props ? props[_CONST_PROPS] : null;
|
|
3588
|
+
};
|
|
3523
3589
|
|
|
3524
3590
|
const isForeignObjectElement = (elementName) => {
|
|
3525
3591
|
return build.isDev ? elementName.toLowerCase() === 'foreignobject' : elementName === 'foreignObject';
|
|
@@ -3840,6 +3906,10 @@
|
|
|
3840
3906
|
vNewNode = null;
|
|
3841
3907
|
vCurrent = vnode_getFirstChild(vStartNode);
|
|
3842
3908
|
stackPush(jsxNode, true);
|
|
3909
|
+
if (vParent[0 /* VNodeProps.flags */] & 32 /* VNodeFlags.Deleted */) {
|
|
3910
|
+
// Ignore diff if the parent is deleted.
|
|
3911
|
+
return;
|
|
3912
|
+
}
|
|
3843
3913
|
while (stack.length) {
|
|
3844
3914
|
while (jsxIdx < jsxCount) {
|
|
3845
3915
|
assertFalse(vParent === vCurrent, "Parent and current can't be the same");
|
|
@@ -4268,8 +4338,10 @@
|
|
|
4268
4338
|
value = trackSignalAndAssignHost(value, vNewNode, key, container, signalData);
|
|
4269
4339
|
}
|
|
4270
4340
|
if (key === dangerouslySetInnerHTML) {
|
|
4271
|
-
|
|
4272
|
-
|
|
4341
|
+
if (value) {
|
|
4342
|
+
element.innerHTML = String(value);
|
|
4343
|
+
element.setAttribute(QContainerAttr, "html" /* QContainerValue.HTML */);
|
|
4344
|
+
}
|
|
4273
4345
|
continue;
|
|
4274
4346
|
}
|
|
4275
4347
|
if (elementName === 'textarea' && key === 'value') {
|
|
@@ -4370,8 +4442,13 @@
|
|
|
4370
4442
|
let returnValue = false;
|
|
4371
4443
|
qrls.flat(2).forEach((qrl) => {
|
|
4372
4444
|
if (qrl) {
|
|
4373
|
-
|
|
4374
|
-
|
|
4445
|
+
if (isSyncQrl(qrl)) {
|
|
4446
|
+
qrl(event, element);
|
|
4447
|
+
}
|
|
4448
|
+
else {
|
|
4449
|
+
const value = container.$scheduler$(2 /* ChoreType.RUN_QRL */, vNode, qrl, [event, element]);
|
|
4450
|
+
returnValue = returnValue || value === true;
|
|
4451
|
+
}
|
|
4375
4452
|
}
|
|
4376
4453
|
});
|
|
4377
4454
|
return returnValue;
|
|
@@ -4873,7 +4950,7 @@
|
|
|
4873
4950
|
const task = obj;
|
|
4874
4951
|
clearAllEffects(container, task);
|
|
4875
4952
|
if (task.$flags$ & 1 /* TaskFlags.VISIBLE_TASK */) {
|
|
4876
|
-
container.$scheduler$(
|
|
4953
|
+
container.$scheduler$(32 /* ChoreType.CLEANUP_VISIBLE */, task);
|
|
4877
4954
|
}
|
|
4878
4955
|
else {
|
|
4879
4956
|
cleanupTask(task);
|
|
@@ -4924,7 +5001,16 @@
|
|
|
4924
5001
|
*/
|
|
4925
5002
|
const vFirstChild = vnode_getFirstChild(vCursor);
|
|
4926
5003
|
if (vFirstChild) {
|
|
4927
|
-
vnode_walkVNode(vFirstChild)
|
|
5004
|
+
vnode_walkVNode(vFirstChild, (vNode) => {
|
|
5005
|
+
/**
|
|
5006
|
+
* Instead of an ID, we store a direct reference to the VNode. This is necessary to
|
|
5007
|
+
* locate the slot's parent in a detached subtree, as the ID would become invalid.
|
|
5008
|
+
*/
|
|
5009
|
+
if (vNode[0 /* VNodeProps.flags */] & 2 /* VNodeFlags.Virtual */) {
|
|
5010
|
+
// The QSlotParent is used to find the slot parent during scheduling
|
|
5011
|
+
vnode_getProp(vNode, QSlotParent, (id) => vnode_locate(container.rootVNode, id));
|
|
5012
|
+
}
|
|
5013
|
+
});
|
|
4928
5014
|
return;
|
|
4929
5015
|
}
|
|
4930
5016
|
}
|
|
@@ -5001,8 +5087,8 @@
|
|
|
5001
5087
|
const resource = createResourceReturn(container, opts);
|
|
5002
5088
|
const el = iCtx.$hostElement$;
|
|
5003
5089
|
const task = new Task(8 /* TaskFlags.DIRTY */ | 4 /* TaskFlags.RESOURCE */, i, el, qrl, resource, null);
|
|
5004
|
-
container.$scheduler$(3 /* ChoreType.TASK */, task);
|
|
5005
5090
|
set(resource);
|
|
5091
|
+
runResource(task, container, el);
|
|
5006
5092
|
return resource;
|
|
5007
5093
|
};
|
|
5008
5094
|
// <docs markdown="../readme.md#useResource">
|
|
@@ -5070,10 +5156,10 @@
|
|
|
5070
5156
|
function getResourceValueAsPromise(props) {
|
|
5071
5157
|
const resource = props.value;
|
|
5072
5158
|
if (isResourceReturn(resource)) {
|
|
5159
|
+
// create a subscription for the resource._state changes
|
|
5160
|
+
const state = resource._state;
|
|
5073
5161
|
const isBrowser = !isServerPlatform();
|
|
5074
5162
|
if (isBrowser) {
|
|
5075
|
-
// create a subscription for the resource._state changes
|
|
5076
|
-
const state = resource._state;
|
|
5077
5163
|
if (state === 'pending' && props.onPending) {
|
|
5078
5164
|
return Promise.resolve().then(useBindInvokeContext(props.onPending));
|
|
5079
5165
|
}
|
|
@@ -5088,14 +5174,7 @@
|
|
|
5088
5174
|
}
|
|
5089
5175
|
}
|
|
5090
5176
|
}
|
|
5091
|
-
|
|
5092
|
-
if (value) {
|
|
5093
|
-
return value.then(useBindInvokeContext(props.onResolved), useBindInvokeContext(props.onRejected));
|
|
5094
|
-
}
|
|
5095
|
-
else {
|
|
5096
|
-
// this is temporary value until the `runResource` is executed and promise is assigned to the value
|
|
5097
|
-
return Promise.resolve(undefined);
|
|
5098
|
-
}
|
|
5177
|
+
return untrack(() => resource.value).then(useBindInvokeContext(props.onResolved), useBindInvokeContext(props.onRejected));
|
|
5099
5178
|
}
|
|
5100
5179
|
else if (isPromise(resource)) {
|
|
5101
5180
|
return resource.then(useBindInvokeContext(props.onResolved), useBindInvokeContext(props.onRejected));
|
|
@@ -5113,7 +5192,7 @@
|
|
|
5113
5192
|
const resource = {
|
|
5114
5193
|
__brand: 'resource',
|
|
5115
5194
|
value: undefined,
|
|
5116
|
-
loading: isServerPlatform()
|
|
5195
|
+
loading: !isServerPlatform(),
|
|
5117
5196
|
_resolved: undefined,
|
|
5118
5197
|
_error: undefined,
|
|
5119
5198
|
_state: 'pending',
|
|
@@ -5164,19 +5243,22 @@
|
|
|
5164
5243
|
done = true;
|
|
5165
5244
|
if (resolved) {
|
|
5166
5245
|
done = true;
|
|
5167
|
-
|
|
5168
|
-
|
|
5169
|
-
|
|
5170
|
-
|
|
5246
|
+
resourceTarget.loading = false;
|
|
5247
|
+
resourceTarget._state = 'resolved';
|
|
5248
|
+
resourceTarget._resolved = value;
|
|
5249
|
+
resourceTarget._error = undefined;
|
|
5171
5250
|
resolve(value);
|
|
5172
5251
|
}
|
|
5173
5252
|
else {
|
|
5174
5253
|
done = true;
|
|
5175
|
-
|
|
5176
|
-
|
|
5177
|
-
|
|
5254
|
+
resourceTarget.loading = false;
|
|
5255
|
+
resourceTarget._state = 'rejected';
|
|
5256
|
+
resourceTarget._error = value;
|
|
5178
5257
|
reject(value);
|
|
5179
5258
|
}
|
|
5259
|
+
if (!isServerPlatform()) {
|
|
5260
|
+
forceStoreEffects(resource, '_state');
|
|
5261
|
+
}
|
|
5180
5262
|
return true;
|
|
5181
5263
|
}
|
|
5182
5264
|
return false;
|
|
@@ -5192,17 +5274,17 @@
|
|
|
5192
5274
|
}
|
|
5193
5275
|
});
|
|
5194
5276
|
// Execute mutation inside empty invocation
|
|
5277
|
+
// TODO: is it right? why we need to invoke inside context and trigger effects?
|
|
5195
5278
|
invoke(iCtx, () => {
|
|
5196
5279
|
// console.log('RESOURCE.pending: ');
|
|
5197
5280
|
resource._state = 'pending';
|
|
5198
5281
|
resource.loading = !isServerPlatform();
|
|
5199
|
-
|
|
5282
|
+
resource.value = new Promise((r, re) => {
|
|
5200
5283
|
resolve = r;
|
|
5201
5284
|
reject = re;
|
|
5202
|
-
})
|
|
5203
|
-
promise.catch(ignoreErrorToPreventNodeFromCrashing);
|
|
5285
|
+
});
|
|
5204
5286
|
});
|
|
5205
|
-
const promise = safeCall(() =>
|
|
5287
|
+
const promise = safeCall(() => taskFn(opts), (value) => {
|
|
5206
5288
|
setState(true, value);
|
|
5207
5289
|
}, (err) => {
|
|
5208
5290
|
if (isPromise(err)) {
|
|
@@ -5225,10 +5307,6 @@
|
|
|
5225
5307
|
}
|
|
5226
5308
|
return promise;
|
|
5227
5309
|
};
|
|
5228
|
-
const ignoreErrorToPreventNodeFromCrashing = (err) => {
|
|
5229
|
-
// ignore error to prevent node from crashing
|
|
5230
|
-
// node will crash in promise is rejected and no one is listening to the rejection.
|
|
5231
|
-
};
|
|
5232
5310
|
|
|
5233
5311
|
/// These global variables are used to avoid creating new arrays for each call to `vnode_documentPosition`.
|
|
5234
5312
|
const aVNodePath = [];
|
|
@@ -5311,11 +5389,11 @@
|
|
|
5311
5389
|
let bDepth = -1;
|
|
5312
5390
|
while (a) {
|
|
5313
5391
|
const ssrNode = (aSsrNodePath[++aDepth] = a);
|
|
5314
|
-
a = ssrNode.
|
|
5392
|
+
a = ssrNode.parentComponent;
|
|
5315
5393
|
}
|
|
5316
5394
|
while (b) {
|
|
5317
5395
|
const ssrNode = (bSsrNodePath[++bDepth] = b);
|
|
5318
|
-
b = ssrNode.
|
|
5396
|
+
b = ssrNode.parentComponent;
|
|
5319
5397
|
}
|
|
5320
5398
|
while (aDepth >= 0 && bDepth >= 0) {
|
|
5321
5399
|
a = aSsrNodePath[aDepth];
|
|
@@ -5332,6 +5410,210 @@
|
|
|
5332
5410
|
return aDepth < bDepth ? -1 : 1;
|
|
5333
5411
|
};
|
|
5334
5412
|
|
|
5413
|
+
/**
|
|
5414
|
+
* Rules for determining if a chore is blocked by another chore. Some chores can block other chores.
|
|
5415
|
+
* They cannot run until the blocking chore has completed.
|
|
5416
|
+
*
|
|
5417
|
+
* The match function is used to determine if the blocked chore is blocked by the blocking chore.
|
|
5418
|
+
* The match function is called with the blocked chore, the blocking chore, and the container.
|
|
5419
|
+
*/
|
|
5420
|
+
const VISIBLE_BLOCKING_RULES = [
|
|
5421
|
+
// NODE_DIFF blocks VISIBLE on same host,
|
|
5422
|
+
// if the blocked chore is a child of the blocking chore
|
|
5423
|
+
// or the blocked chore is a sibling of the blocking chore
|
|
5424
|
+
{
|
|
5425
|
+
blockedType: 16 /* ChoreType.VISIBLE */,
|
|
5426
|
+
blockingType: 4 /* ChoreType.NODE_DIFF */,
|
|
5427
|
+
match: (blocked, blocking, container) => isDescendant(blocked, blocking, container) || isDescendant(blocking, blocked, container),
|
|
5428
|
+
},
|
|
5429
|
+
// COMPONENT blocks VISIBLE on same host
|
|
5430
|
+
// if the blocked chore is a child of the blocking chore
|
|
5431
|
+
// or the blocked chore is a sibling of the blocking chore
|
|
5432
|
+
{
|
|
5433
|
+
blockedType: 16 /* ChoreType.VISIBLE */,
|
|
5434
|
+
blockingType: 6 /* ChoreType.COMPONENT */,
|
|
5435
|
+
match: (blocked, blocking, container) => isDescendant(blocked, blocking, container) || isDescendant(blocking, blocked, container),
|
|
5436
|
+
},
|
|
5437
|
+
];
|
|
5438
|
+
const BLOCKING_RULES = [
|
|
5439
|
+
// QRL_RESOLVE blocks RUN_QRL, TASK, VISIBLE on same host
|
|
5440
|
+
{
|
|
5441
|
+
blockedType: 2 /* ChoreType.RUN_QRL */,
|
|
5442
|
+
blockingType: 1 /* ChoreType.QRL_RESOLVE */,
|
|
5443
|
+
match: (blocked, blocking) => {
|
|
5444
|
+
const blockedQrl = blocked.$target$;
|
|
5445
|
+
const blockingQrl = blocking.$target$;
|
|
5446
|
+
return isSameHost(blocked, blocking) && isSameQrl(blockedQrl, blockingQrl);
|
|
5447
|
+
},
|
|
5448
|
+
},
|
|
5449
|
+
{
|
|
5450
|
+
blockedType: 3 /* ChoreType.TASK */,
|
|
5451
|
+
blockingType: 1 /* ChoreType.QRL_RESOLVE */,
|
|
5452
|
+
match: (blocked, blocking) => {
|
|
5453
|
+
const blockedTask = blocked.$payload$;
|
|
5454
|
+
const blockingQrl = blocking.$target$;
|
|
5455
|
+
return isSameHost(blocked, blocking) && isSameQrl(blockedTask.$qrl$, blockingQrl);
|
|
5456
|
+
},
|
|
5457
|
+
},
|
|
5458
|
+
{
|
|
5459
|
+
blockedType: 16 /* ChoreType.VISIBLE */,
|
|
5460
|
+
blockingType: 1 /* ChoreType.QRL_RESOLVE */,
|
|
5461
|
+
match: (blocked, blocking) => {
|
|
5462
|
+
const blockedTask = blocked.$payload$;
|
|
5463
|
+
const blockingQrl = blocking.$target$;
|
|
5464
|
+
return isSameHost(blocked, blocking) && isSameQrl(blockedTask.$qrl$, blockingQrl);
|
|
5465
|
+
},
|
|
5466
|
+
},
|
|
5467
|
+
// COMPONENT blocks NODE_DIFF, NODE_PROP on same host
|
|
5468
|
+
{
|
|
5469
|
+
blockedType: 4 /* ChoreType.NODE_DIFF */,
|
|
5470
|
+
blockingType: 6 /* ChoreType.COMPONENT */,
|
|
5471
|
+
match: (blocked, blocking) => blocked.$host$ === blocking.$host$,
|
|
5472
|
+
},
|
|
5473
|
+
{
|
|
5474
|
+
blockedType: 5 /* ChoreType.NODE_PROP */,
|
|
5475
|
+
blockingType: 6 /* ChoreType.COMPONENT */,
|
|
5476
|
+
match: (blocked, blocking) => blocked.$host$ === blocking.$host$,
|
|
5477
|
+
},
|
|
5478
|
+
...VISIBLE_BLOCKING_RULES,
|
|
5479
|
+
// TASK blocks subsequent TASKs in the same component
|
|
5480
|
+
{
|
|
5481
|
+
blockedType: 3 /* ChoreType.TASK */,
|
|
5482
|
+
blockingType: 3 /* ChoreType.TASK */,
|
|
5483
|
+
match: (blocked, blocking, container) => {
|
|
5484
|
+
if (blocked.$host$ !== blocking.$host$) {
|
|
5485
|
+
return false;
|
|
5486
|
+
}
|
|
5487
|
+
const blockedIdx = blocked.$idx$;
|
|
5488
|
+
if (!isNumber$1(blockedIdx) || blockedIdx <= 0) {
|
|
5489
|
+
return false;
|
|
5490
|
+
}
|
|
5491
|
+
const previousTask = findPreviousTaskInComponent(blocked.$host$, blockedIdx, container);
|
|
5492
|
+
return previousTask === blocking.$payload$;
|
|
5493
|
+
},
|
|
5494
|
+
},
|
|
5495
|
+
];
|
|
5496
|
+
function isDescendant(descendantChore, ancestorChore, container) {
|
|
5497
|
+
const descendantHost = descendantChore.$host$;
|
|
5498
|
+
const ancestorHost = ancestorChore.$host$;
|
|
5499
|
+
if (!vnode_isVNode(descendantHost) || !vnode_isVNode(ancestorHost)) {
|
|
5500
|
+
return false;
|
|
5501
|
+
}
|
|
5502
|
+
return vnode_isDescendantOf(descendantHost, ancestorHost, container.rootVNode);
|
|
5503
|
+
}
|
|
5504
|
+
function isSameHost(a, b) {
|
|
5505
|
+
return a.$host$ === b.$host$;
|
|
5506
|
+
}
|
|
5507
|
+
function isSameQrl(a, b) {
|
|
5508
|
+
return a.$symbol$ === b.$symbol$;
|
|
5509
|
+
}
|
|
5510
|
+
function findBlockingChoreInQueue(chore, choreQueue, container) {
|
|
5511
|
+
for (const candidate of choreQueue) {
|
|
5512
|
+
// everything after VISIBLE is not blocking. Visible task, task and resource should not block anything in this rule.
|
|
5513
|
+
if (candidate.$type$ >= 16 /* ChoreType.VISIBLE */ || candidate.$type$ === 3 /* ChoreType.TASK */) {
|
|
5514
|
+
continue;
|
|
5515
|
+
}
|
|
5516
|
+
if (isDescendant(chore, candidate, container)) {
|
|
5517
|
+
return candidate;
|
|
5518
|
+
}
|
|
5519
|
+
}
|
|
5520
|
+
return null;
|
|
5521
|
+
}
|
|
5522
|
+
function findBlockingChore(chore, choreQueue, blockedChores, runningChores, container) {
|
|
5523
|
+
const blockingChoreInChoreQueue = findBlockingChoreInQueue(chore, choreQueue, container);
|
|
5524
|
+
if (blockingChoreInChoreQueue) {
|
|
5525
|
+
return blockingChoreInChoreQueue;
|
|
5526
|
+
}
|
|
5527
|
+
const blockingChoreInBlockedChores = findBlockingChoreInQueue(chore, Array.from(blockedChores), container);
|
|
5528
|
+
if (blockingChoreInBlockedChores) {
|
|
5529
|
+
return blockingChoreInBlockedChores;
|
|
5530
|
+
}
|
|
5531
|
+
const blockingChoreInRunningChores = findBlockingChoreInQueue(chore, Array.from(runningChores), container);
|
|
5532
|
+
if (blockingChoreInRunningChores) {
|
|
5533
|
+
return blockingChoreInRunningChores;
|
|
5534
|
+
}
|
|
5535
|
+
for (const rule of BLOCKING_RULES) {
|
|
5536
|
+
if (chore.$type$ !== rule.blockedType) {
|
|
5537
|
+
continue;
|
|
5538
|
+
}
|
|
5539
|
+
// Check in choreQueue
|
|
5540
|
+
// TODO(perf): better to iterate in reverse order?
|
|
5541
|
+
for (const candidate of choreQueue) {
|
|
5542
|
+
if (candidate.$type$ === rule.blockingType && rule.match(chore, candidate, container)) {
|
|
5543
|
+
return candidate;
|
|
5544
|
+
}
|
|
5545
|
+
}
|
|
5546
|
+
// Check in blockedChores
|
|
5547
|
+
for (const candidate of blockedChores) {
|
|
5548
|
+
if (candidate.$type$ === rule.blockingType && rule.match(chore, candidate, container)) {
|
|
5549
|
+
return candidate;
|
|
5550
|
+
}
|
|
5551
|
+
}
|
|
5552
|
+
// Check in runningChores
|
|
5553
|
+
for (const candidate of runningChores) {
|
|
5554
|
+
if (candidate.$type$ === rule.blockingType && rule.match(chore, candidate, container)) {
|
|
5555
|
+
return candidate;
|
|
5556
|
+
}
|
|
5557
|
+
}
|
|
5558
|
+
}
|
|
5559
|
+
return null;
|
|
5560
|
+
}
|
|
5561
|
+
function findPreviousTaskInComponent(host, currentTaskIdx, container) {
|
|
5562
|
+
const elementSeq = container.getHostProp(host, ELEMENT_SEQ);
|
|
5563
|
+
if (!elementSeq || elementSeq.length <= currentTaskIdx) {
|
|
5564
|
+
return null;
|
|
5565
|
+
}
|
|
5566
|
+
for (let i = currentTaskIdx - 1; i >= 0; i--) {
|
|
5567
|
+
const candidate = elementSeq[i];
|
|
5568
|
+
if (candidate instanceof Task && candidate.$flags$ & 2 /* TaskFlags.TASK */) {
|
|
5569
|
+
return candidate;
|
|
5570
|
+
}
|
|
5571
|
+
}
|
|
5572
|
+
return null;
|
|
5573
|
+
}
|
|
5574
|
+
function findBlockingChoreForVisible(chore, runningChores, container) {
|
|
5575
|
+
for (const rule of VISIBLE_BLOCKING_RULES) {
|
|
5576
|
+
if (chore.$type$ !== rule.blockedType) {
|
|
5577
|
+
continue;
|
|
5578
|
+
}
|
|
5579
|
+
for (const candidate of runningChores) {
|
|
5580
|
+
if (candidate.$type$ === rule.blockingType && rule.match(chore, candidate, container)) {
|
|
5581
|
+
return candidate;
|
|
5582
|
+
}
|
|
5583
|
+
}
|
|
5584
|
+
}
|
|
5585
|
+
return null;
|
|
5586
|
+
}
|
|
5587
|
+
|
|
5588
|
+
// This can't be in platform.ts because it uses MessageChannel which cannot post messages with functions
|
|
5589
|
+
// TODO: move this to platform.ts somehow
|
|
5590
|
+
const createNextTick = (fn) => {
|
|
5591
|
+
let nextTick;
|
|
5592
|
+
// according to the https://developer.mozilla.org/en-US/docs/Web/API/Window/setImmediate#notes
|
|
5593
|
+
if (typeof setImmediate === 'function') {
|
|
5594
|
+
// setImmediate is the fastest way to schedule a task, but works only in node.js
|
|
5595
|
+
nextTick = () => {
|
|
5596
|
+
setImmediate(fn);
|
|
5597
|
+
};
|
|
5598
|
+
}
|
|
5599
|
+
else if (typeof MessageChannel !== 'undefined') {
|
|
5600
|
+
const channel = new MessageChannel();
|
|
5601
|
+
channel.port1.onmessage = () => {
|
|
5602
|
+
fn();
|
|
5603
|
+
};
|
|
5604
|
+
nextTick = () => {
|
|
5605
|
+
channel.port2.postMessage(null);
|
|
5606
|
+
};
|
|
5607
|
+
}
|
|
5608
|
+
else {
|
|
5609
|
+
// setTimeout is a fallback, creates 4ms delay
|
|
5610
|
+
nextTick = () => {
|
|
5611
|
+
setTimeout(fn);
|
|
5612
|
+
};
|
|
5613
|
+
}
|
|
5614
|
+
return nextTick;
|
|
5615
|
+
};
|
|
5616
|
+
|
|
5335
5617
|
/**
|
|
5336
5618
|
* Scheduler is responsible for running application code in predictable order.
|
|
5337
5619
|
*
|
|
@@ -5415,29 +5697,43 @@
|
|
|
5415
5697
|
*/
|
|
5416
5698
|
// Turn this on to get debug output of what the scheduler is doing.
|
|
5417
5699
|
const DEBUG = false;
|
|
5418
|
-
|
|
5419
|
-
|
|
5420
|
-
|
|
5421
|
-
|
|
5422
|
-
|
|
5423
|
-
|
|
5424
|
-
|
|
5700
|
+
var ChoreState;
|
|
5701
|
+
(function (ChoreState) {
|
|
5702
|
+
ChoreState[ChoreState["NONE"] = 0] = "NONE";
|
|
5703
|
+
ChoreState[ChoreState["RUNNING"] = 1] = "RUNNING";
|
|
5704
|
+
ChoreState[ChoreState["FAILED"] = 2] = "FAILED";
|
|
5705
|
+
ChoreState[ChoreState["DONE"] = 3] = "DONE";
|
|
5706
|
+
})(ChoreState || (ChoreState = {}));
|
|
5707
|
+
const getChorePromise = (chore) => chore.$state$ === ChoreState.NONE
|
|
5708
|
+
? (chore.$returnValue$ ||= new Promise((resolve, reject) => {
|
|
5709
|
+
chore.$resolve$ = resolve;
|
|
5710
|
+
chore.$reject$ = reject;
|
|
5711
|
+
}))
|
|
5712
|
+
: chore.$returnValue$;
|
|
5713
|
+
const createScheduler = (container, journalFlush, choreQueue = [], blockedChores = new Set(), runningChores = new Set()) => {
|
|
5714
|
+
let drainChore = null;
|
|
5425
5715
|
let drainScheduled = false;
|
|
5716
|
+
let isDraining = false;
|
|
5717
|
+
let isJournalFlushRunning = false;
|
|
5718
|
+
let flushBudgetStart = 0;
|
|
5719
|
+
let currentTime = performance.now();
|
|
5720
|
+
const nextTick = createNextTick(drainChoreQueue);
|
|
5721
|
+
function drainInNextTick() {
|
|
5722
|
+
if (!drainScheduled) {
|
|
5723
|
+
drainScheduled = true;
|
|
5724
|
+
nextTick();
|
|
5725
|
+
}
|
|
5726
|
+
}
|
|
5727
|
+
// Drain for ~16.67ms, then apply journal flush for ~16.67ms, then repeat
|
|
5728
|
+
// We divide by 60 because we want to run at 60fps
|
|
5729
|
+
const FREQUENCY_MS = Math.floor(1000 / 60);
|
|
5426
5730
|
return schedule;
|
|
5427
5731
|
///// IMPLEMENTATION /////
|
|
5428
5732
|
function schedule(type, hostOrTask = null, targetOrQrl = null, payload = null) {
|
|
5429
|
-
|
|
5430
|
-
|
|
5431
|
-
const runLater = type !== 255 /* ChoreType.WAIT_FOR_ALL */ && !isComponentSsr && type !== 2 /* ChoreType.RUN_QRL */;
|
|
5432
|
-
const isTask = type === 3 /* ChoreType.TASK */ || type === 32 /* ChoreType.VISIBLE */ || type === 48 /* ChoreType.CLEANUP_VISIBLE */;
|
|
5433
|
-
const isClientOnly = type === 16 /* ChoreType.JOURNAL_FLUSH */ ||
|
|
5434
|
-
type === 4 /* ChoreType.NODE_DIFF */ ||
|
|
5435
|
-
type === 5 /* ChoreType.NODE_PROP */ ||
|
|
5436
|
-
type === 1 /* ChoreType.QRL_RESOLVE */ ||
|
|
5437
|
-
type === 7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */;
|
|
5438
|
-
if (isServer && isClientOnly) {
|
|
5439
|
-
return;
|
|
5733
|
+
if (type === 255 /* ChoreType.WAIT_FOR_QUEUE */ && drainChore) {
|
|
5734
|
+
return drainChore;
|
|
5440
5735
|
}
|
|
5736
|
+
const isTask = type === 3 /* ChoreType.TASK */ || type === 16 /* ChoreType.VISIBLE */ || type === 32 /* ChoreType.CLEANUP_VISIBLE */;
|
|
5441
5737
|
if (isTask) {
|
|
5442
5738
|
hostOrTask.$flags$ |= 8 /* TaskFlags.DIRTY */;
|
|
5443
5739
|
}
|
|
@@ -5451,167 +5747,310 @@
|
|
|
5451
5747
|
$host$: isTask ? hostOrTask.$el$ : hostOrTask,
|
|
5452
5748
|
$target$: targetOrQrl,
|
|
5453
5749
|
$payload$: isTask ? hostOrTask : payload,
|
|
5454
|
-
$
|
|
5455
|
-
$
|
|
5750
|
+
$state$: ChoreState.NONE,
|
|
5751
|
+
$blockedChores$: null,
|
|
5752
|
+
$startTime$: undefined,
|
|
5753
|
+
$endTime$: undefined,
|
|
5754
|
+
$resolve$: undefined,
|
|
5755
|
+
$reject$: undefined,
|
|
5456
5756
|
$returnValue$: null,
|
|
5457
|
-
$executed$: false,
|
|
5458
5757
|
};
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
|
|
5462
|
-
|
|
5463
|
-
|
|
5464
|
-
|
|
5465
|
-
|
|
5758
|
+
if (type === 255 /* ChoreType.WAIT_FOR_QUEUE */) {
|
|
5759
|
+
getChorePromise(chore);
|
|
5760
|
+
drainChore = chore;
|
|
5761
|
+
drainInNextTick();
|
|
5762
|
+
return chore;
|
|
5763
|
+
}
|
|
5764
|
+
const isServer = isServerPlatform();
|
|
5765
|
+
const isClientOnly = type === 4 /* ChoreType.NODE_DIFF */ || type === 1 /* ChoreType.QRL_RESOLVE */;
|
|
5766
|
+
if (isServer && isClientOnly) {
|
|
5767
|
+
// Mark skipped client-only chores as completed on the server
|
|
5768
|
+
finishChore(chore, undefined);
|
|
5769
|
+
return chore;
|
|
5770
|
+
}
|
|
5771
|
+
if (isServer && chore.$host$ && isSsrNode(chore.$host$)) {
|
|
5772
|
+
const isUpdatable = !!(chore.$host$.flags & 1 /* SsrNodeFlags.Updatable */);
|
|
5773
|
+
if (!isUpdatable) {
|
|
5774
|
+
if (
|
|
5775
|
+
// backpatching exceptions:
|
|
5776
|
+
// - node prop is allowed because it is used to update the node property
|
|
5777
|
+
// - recompute and schedule effects because it triggers effects (so node prop too)
|
|
5778
|
+
chore.$type$ !== 5 /* ChoreType.NODE_PROP */ &&
|
|
5779
|
+
chore.$type$ !== 7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */) {
|
|
5780
|
+
// We are running on the server.
|
|
5781
|
+
// On server we can't schedule task for a different host!
|
|
5782
|
+
// Server is SSR, and therefore scheduling for anything but the current host
|
|
5783
|
+
// implies that things need to be re-run and that is not supported because of streaming.
|
|
5784
|
+
const warningMessage = `A '${choreTypeToName(chore.$type$)}' chore was scheduled on a host element that has already been streamed to the client.
|
|
5785
|
+
This can lead to inconsistencies between Server-Side Rendering (SSR) and Client-Side Rendering (CSR).
|
|
5786
|
+
|
|
5787
|
+
Problematic chore:
|
|
5788
|
+
- Type: ${choreTypeToName(chore.$type$)}
|
|
5789
|
+
- Host: ${chore.$host$.toString()}
|
|
5790
|
+
- Nearest element location: ${chore.$host$.currentFile}
|
|
5791
|
+
|
|
5792
|
+
This is often caused by modifying a signal in an already rendered component during SSR.`;
|
|
5793
|
+
logWarn(warningMessage);
|
|
5794
|
+
return chore;
|
|
5795
|
+
}
|
|
5796
|
+
}
|
|
5797
|
+
}
|
|
5798
|
+
const blockingChore = findBlockingChore(chore, choreQueue, blockedChores, runningChores, container);
|
|
5799
|
+
if (blockingChore) {
|
|
5800
|
+
addBlockedChore(chore, blockingChore, blockedChores);
|
|
5801
|
+
return chore;
|
|
5466
5802
|
}
|
|
5467
|
-
|
|
5468
|
-
|
|
5469
|
-
|
|
5803
|
+
chore = sortedInsert(choreQueue, chore, container.rootVNode || null);
|
|
5804
|
+
const runImmediately = (isServer && type === 6 /* ChoreType.COMPONENT */) || type === 2 /* ChoreType.RUN_QRL */;
|
|
5805
|
+
if (runImmediately && !isDraining) {
|
|
5806
|
+
immediateDrain();
|
|
5470
5807
|
}
|
|
5471
5808
|
else {
|
|
5472
|
-
|
|
5473
|
-
}
|
|
5474
|
-
|
|
5475
|
-
|
|
5476
|
-
function
|
|
5477
|
-
|
|
5478
|
-
|
|
5479
|
-
|
|
5480
|
-
|
|
5481
|
-
|
|
5482
|
-
|
|
5483
|
-
|
|
5484
|
-
|
|
5485
|
-
|
|
5486
|
-
|
|
5487
|
-
|
|
5488
|
-
|
|
5809
|
+
drainInNextTick();
|
|
5810
|
+
}
|
|
5811
|
+
return chore;
|
|
5812
|
+
}
|
|
5813
|
+
function immediateDrain() {
|
|
5814
|
+
drainScheduled = true;
|
|
5815
|
+
drainChoreQueue();
|
|
5816
|
+
}
|
|
5817
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
5818
|
+
// Drain queue helpers
|
|
5819
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
5820
|
+
function applyJournalFlush() {
|
|
5821
|
+
if (!isJournalFlushRunning) {
|
|
5822
|
+
// prevent multiple journal flushes from running at the same time
|
|
5823
|
+
isJournalFlushRunning = true;
|
|
5824
|
+
journalFlush();
|
|
5825
|
+
isJournalFlushRunning = false;
|
|
5826
|
+
flushBudgetStart = performance.now();
|
|
5827
|
+
}
|
|
5828
|
+
}
|
|
5829
|
+
function shouldApplyJournalFlush(isServer) {
|
|
5830
|
+
return !isServer && currentTime - flushBudgetStart >= FREQUENCY_MS;
|
|
5831
|
+
}
|
|
5832
|
+
function drainChoreQueue() {
|
|
5833
|
+
const isServer = isServerPlatform();
|
|
5834
|
+
drainScheduled = false;
|
|
5835
|
+
if (isDraining) {
|
|
5836
|
+
return;
|
|
5837
|
+
}
|
|
5838
|
+
// early return if the queue is empty
|
|
5839
|
+
if (!choreQueue.length) {
|
|
5840
|
+
applyJournalFlush();
|
|
5841
|
+
if (drainChore && !runningChores.size) {
|
|
5842
|
+
// resolve drainChore only if there are no running chores, because
|
|
5843
|
+
// we are sure that we are done
|
|
5844
|
+
drainChore.$resolve$(null);
|
|
5845
|
+
drainChore = null;
|
|
5489
5846
|
}
|
|
5490
|
-
|
|
5491
|
-
|
|
5492
|
-
|
|
5493
|
-
|
|
5494
|
-
|
|
5847
|
+
return;
|
|
5848
|
+
}
|
|
5849
|
+
isDraining = true;
|
|
5850
|
+
flushBudgetStart = performance.now();
|
|
5851
|
+
const maybeFinishDrain = () => {
|
|
5852
|
+
if (choreQueue.length) {
|
|
5853
|
+
drainInNextTick();
|
|
5854
|
+
return false;
|
|
5855
|
+
}
|
|
5856
|
+
if (drainChore && runningChores.size) {
|
|
5857
|
+
if (shouldApplyJournalFlush(isServer)) {
|
|
5858
|
+
// apply journal flush even if we are not finished draining the queue
|
|
5859
|
+
applyJournalFlush();
|
|
5495
5860
|
}
|
|
5496
|
-
|
|
5861
|
+
return false;
|
|
5497
5862
|
}
|
|
5498
|
-
|
|
5499
|
-
|
|
5500
|
-
|
|
5501
|
-
|
|
5502
|
-
|
|
5863
|
+
currentChore = null;
|
|
5864
|
+
applyJournalFlush();
|
|
5865
|
+
drainChore?.$resolve$(null);
|
|
5866
|
+
drainChore = null;
|
|
5867
|
+
return true;
|
|
5868
|
+
};
|
|
5869
|
+
const scheduleBlockedChoresAndDrainIfNeeded = (chore) => {
|
|
5870
|
+
let blockedChoresScheduled = false;
|
|
5871
|
+
if (chore.$blockedChores$) {
|
|
5872
|
+
for (const blockedChore of chore.$blockedChores$) {
|
|
5873
|
+
const blockingChore = findBlockingChore(blockedChore, choreQueue, blockedChores, runningChores, container);
|
|
5874
|
+
if (blockingChore) {
|
|
5875
|
+
addBlockedChore(blockedChore, blockingChore, blockedChores);
|
|
5876
|
+
}
|
|
5877
|
+
else {
|
|
5878
|
+
blockedChores.delete(blockedChore);
|
|
5879
|
+
sortedInsert(choreQueue, blockedChore, container.rootVNode || null);
|
|
5880
|
+
blockedChoresScheduled = true;
|
|
5881
|
+
}
|
|
5882
|
+
}
|
|
5883
|
+
chore.$blockedChores$ = null;
|
|
5503
5884
|
}
|
|
5504
|
-
|
|
5505
|
-
|
|
5506
|
-
|
|
5507
|
-
|
|
5508
|
-
|
|
5509
|
-
const host = chore.$host$;
|
|
5510
|
-
assertEqual(currentChore, null, 'Chore already running.');
|
|
5511
|
-
currentChore = chore;
|
|
5512
|
-
let returnValue = null;
|
|
5885
|
+
if (blockedChoresScheduled && !isDraining) {
|
|
5886
|
+
drainInNextTick();
|
|
5887
|
+
}
|
|
5888
|
+
};
|
|
5889
|
+
let currentChore = null;
|
|
5513
5890
|
try {
|
|
5514
|
-
|
|
5515
|
-
|
|
5516
|
-
|
|
5517
|
-
|
|
5518
|
-
|
|
5519
|
-
|
|
5520
|
-
|
|
5521
|
-
|
|
5522
|
-
|
|
5523
|
-
|
|
5524
|
-
|
|
5525
|
-
|
|
5891
|
+
while (choreQueue.length) {
|
|
5892
|
+
currentTime = performance.now();
|
|
5893
|
+
const chore = (currentChore = choreQueue.shift());
|
|
5894
|
+
if (chore.$state$ !== ChoreState.NONE) {
|
|
5895
|
+
continue;
|
|
5896
|
+
}
|
|
5897
|
+
if (vNodeAlreadyDeleted(chore) &&
|
|
5898
|
+
// we need to process cleanup tasks for deleted nodes
|
|
5899
|
+
chore.$type$ !== 32 /* ChoreType.CLEANUP_VISIBLE */) {
|
|
5900
|
+
// skip deleted chore
|
|
5901
|
+
DEBUG && debugTrace('skip chore', chore, choreQueue, blockedChores);
|
|
5902
|
+
continue;
|
|
5903
|
+
}
|
|
5904
|
+
if (chore.$type$ === 16 /* ChoreType.VISIBLE */) {
|
|
5905
|
+
// ensure that the journal flush is applied before the visible chore is executed
|
|
5906
|
+
// so that the visible chore can see the latest DOM changes
|
|
5907
|
+
applyJournalFlush();
|
|
5908
|
+
const blockingChore = findBlockingChoreForVisible(chore, runningChores, container);
|
|
5909
|
+
if (blockingChore && blockingChore.$state$ === ChoreState.RUNNING) {
|
|
5910
|
+
addBlockedChore(chore, blockingChore, blockedChores);
|
|
5911
|
+
continue;
|
|
5526
5912
|
}
|
|
5527
|
-
|
|
5528
|
-
|
|
5529
|
-
|
|
5530
|
-
|
|
5531
|
-
|
|
5532
|
-
|
|
5913
|
+
}
|
|
5914
|
+
// Note that this never throws
|
|
5915
|
+
chore.$startTime$ = performance.now();
|
|
5916
|
+
const result = executeChore(chore, isServer);
|
|
5917
|
+
chore.$returnValue$ = result;
|
|
5918
|
+
if (isPromise(result)) {
|
|
5919
|
+
runningChores.add(chore);
|
|
5920
|
+
chore.$state$ = ChoreState.RUNNING;
|
|
5921
|
+
result
|
|
5922
|
+
.then((value) => {
|
|
5923
|
+
finishChore(chore, value);
|
|
5924
|
+
})
|
|
5925
|
+
.catch((e) => {
|
|
5926
|
+
if (chore.$state$ !== ChoreState.RUNNING) {
|
|
5927
|
+
// we already handled the error
|
|
5928
|
+
return;
|
|
5929
|
+
}
|
|
5930
|
+
handleError(chore, e);
|
|
5931
|
+
})
|
|
5932
|
+
.finally(() => {
|
|
5933
|
+
runningChores.delete(chore);
|
|
5934
|
+
// Note that we ignore failed chores so the app keeps working
|
|
5935
|
+
// TODO decide if this is ok and document it
|
|
5936
|
+
scheduleBlockedChoresAndDrainIfNeeded(chore);
|
|
5937
|
+
// If drainChore is not null, we are waiting for it to finish.
|
|
5938
|
+
// If there are no running chores, we can finish the drain.
|
|
5939
|
+
if (!runningChores.size) {
|
|
5940
|
+
let finished = false;
|
|
5941
|
+
if (drainChore) {
|
|
5942
|
+
finished = maybeFinishDrain();
|
|
5533
5943
|
}
|
|
5534
|
-
|
|
5535
|
-
|
|
5536
|
-
|
|
5944
|
+
if (!finished && !isDraining) {
|
|
5945
|
+
// if finished, then journal flush is already applied
|
|
5946
|
+
applyJournalFlush();
|
|
5537
5947
|
}
|
|
5538
|
-
}, (err) => container.handleError(err, host));
|
|
5539
|
-
}
|
|
5540
|
-
break;
|
|
5541
|
-
case 2 /* ChoreType.RUN_QRL */:
|
|
5542
|
-
{
|
|
5543
|
-
const fn = chore.$target$.getFn();
|
|
5544
|
-
const result = retryOnPromise(() => fn(...chore.$payload$));
|
|
5545
|
-
if (isPromise(result)) {
|
|
5546
|
-
const handled = result
|
|
5547
|
-
.finally(() => {
|
|
5548
|
-
qrlRuns.splice(qrlRuns.indexOf(handled), 1);
|
|
5549
|
-
})
|
|
5550
|
-
.catch((error) => {
|
|
5551
|
-
container.handleError(error, chore.$host$);
|
|
5552
|
-
});
|
|
5553
|
-
// Don't wait for the promise to resolve
|
|
5554
|
-
// TODO come up with a better solution, we also want concurrent signal handling with tasks but serial tasks
|
|
5555
|
-
qrlRuns.push(handled);
|
|
5556
|
-
DEBUG &&
|
|
5557
|
-
debugTrace('execute.DONE (but still running)', chore, currentChore, choreQueue);
|
|
5558
|
-
chore.$returnValue$ = handled;
|
|
5559
|
-
chore.$resolve$?.(handled);
|
|
5560
|
-
currentChore = null;
|
|
5561
|
-
chore.$executed$ = true;
|
|
5562
|
-
// early out so we don't call after()
|
|
5563
|
-
return;
|
|
5564
5948
|
}
|
|
5565
|
-
|
|
5566
|
-
|
|
5567
|
-
|
|
5568
|
-
|
|
5569
|
-
|
|
5570
|
-
|
|
5571
|
-
|
|
5572
|
-
|
|
5573
|
-
|
|
5574
|
-
|
|
5575
|
-
|
|
5576
|
-
|
|
5577
|
-
|
|
5578
|
-
|
|
5579
|
-
|
|
5580
|
-
|
|
5949
|
+
});
|
|
5950
|
+
}
|
|
5951
|
+
else {
|
|
5952
|
+
finishChore(chore, result);
|
|
5953
|
+
scheduleBlockedChoresAndDrainIfNeeded(chore);
|
|
5954
|
+
}
|
|
5955
|
+
if (shouldApplyJournalFlush(isServer)) {
|
|
5956
|
+
applyJournalFlush();
|
|
5957
|
+
drainInNextTick();
|
|
5958
|
+
return;
|
|
5959
|
+
}
|
|
5960
|
+
}
|
|
5961
|
+
}
|
|
5962
|
+
catch (e) {
|
|
5963
|
+
handleError(currentChore, e);
|
|
5964
|
+
scheduleBlockedChoresAndDrainIfNeeded(currentChore);
|
|
5965
|
+
}
|
|
5966
|
+
finally {
|
|
5967
|
+
isDraining = false;
|
|
5968
|
+
maybeFinishDrain();
|
|
5969
|
+
}
|
|
5970
|
+
}
|
|
5971
|
+
function finishChore(chore, value) {
|
|
5972
|
+
chore.$endTime$ = performance.now();
|
|
5973
|
+
chore.$state$ = ChoreState.DONE;
|
|
5974
|
+
chore.$returnValue$ = value;
|
|
5975
|
+
chore.$resolve$?.(value);
|
|
5976
|
+
}
|
|
5977
|
+
function handleError(chore, e) {
|
|
5978
|
+
chore.$endTime$ = performance.now();
|
|
5979
|
+
chore.$state$ = ChoreState.FAILED;
|
|
5980
|
+
// If we used the result as promise, this won't exist
|
|
5981
|
+
chore.$reject$?.(e);
|
|
5982
|
+
container.handleError(e, chore.$host$);
|
|
5983
|
+
}
|
|
5984
|
+
function executeChore(chore, isServer) {
|
|
5985
|
+
const host = chore.$host$;
|
|
5986
|
+
let returnValue;
|
|
5987
|
+
switch (chore.$type$) {
|
|
5988
|
+
case 6 /* ChoreType.COMPONENT */:
|
|
5989
|
+
{
|
|
5990
|
+
returnValue = safeCall(() => executeComponent(container, host, host, chore.$target$, chore.$payload$), (jsx) => {
|
|
5991
|
+
if (isServer) {
|
|
5992
|
+
return jsx;
|
|
5581
5993
|
}
|
|
5582
5994
|
else {
|
|
5583
|
-
|
|
5995
|
+
const styleScopedId = container.getHostProp(host, QScopedStyle);
|
|
5996
|
+
return retryOnPromise(() => vnode_diff(container, jsx, host, addComponentStylePrefix(styleScopedId)));
|
|
5584
5997
|
}
|
|
5998
|
+
}, (err) => {
|
|
5999
|
+
handleError(chore, err);
|
|
6000
|
+
});
|
|
6001
|
+
}
|
|
6002
|
+
break;
|
|
6003
|
+
case 2 /* ChoreType.RUN_QRL */:
|
|
6004
|
+
{
|
|
6005
|
+
const fn = chore.$target$.getFn();
|
|
6006
|
+
returnValue = retryOnPromise(() => fn(...chore.$payload$));
|
|
6007
|
+
}
|
|
6008
|
+
break;
|
|
6009
|
+
case 3 /* ChoreType.TASK */:
|
|
6010
|
+
case 16 /* ChoreType.VISIBLE */:
|
|
6011
|
+
{
|
|
6012
|
+
const payload = chore.$payload$;
|
|
6013
|
+
if (payload.$flags$ & 4 /* TaskFlags.RESOURCE */) {
|
|
6014
|
+
returnValue = runResource(payload, container, host);
|
|
5585
6015
|
}
|
|
5586
|
-
|
|
5587
|
-
|
|
5588
|
-
{
|
|
5589
|
-
const task = chore.$payload$;
|
|
5590
|
-
cleanupTask(task);
|
|
6016
|
+
else {
|
|
6017
|
+
returnValue = runTask(payload, container, host);
|
|
5591
6018
|
}
|
|
5592
|
-
|
|
5593
|
-
|
|
5594
|
-
|
|
5595
|
-
|
|
5596
|
-
|
|
5597
|
-
|
|
5598
|
-
|
|
5599
|
-
|
|
5600
|
-
|
|
6019
|
+
}
|
|
6020
|
+
break;
|
|
6021
|
+
case 32 /* ChoreType.CLEANUP_VISIBLE */:
|
|
6022
|
+
{
|
|
6023
|
+
const task = chore.$payload$;
|
|
6024
|
+
cleanupTask(task);
|
|
6025
|
+
}
|
|
6026
|
+
break;
|
|
6027
|
+
case 4 /* ChoreType.NODE_DIFF */:
|
|
6028
|
+
{
|
|
6029
|
+
const parentVirtualNode = chore.$target$;
|
|
6030
|
+
let jsx = chore.$payload$;
|
|
6031
|
+
if (isSignal(jsx)) {
|
|
6032
|
+
jsx = jsx.value;
|
|
5601
6033
|
}
|
|
5602
|
-
|
|
5603
|
-
|
|
5604
|
-
|
|
5605
|
-
|
|
5606
|
-
|
|
5607
|
-
|
|
5608
|
-
|
|
5609
|
-
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
|
|
6034
|
+
returnValue = retryOnPromise(() => vnode_diff(container, jsx, parentVirtualNode, null));
|
|
6035
|
+
}
|
|
6036
|
+
break;
|
|
6037
|
+
case 5 /* ChoreType.NODE_PROP */:
|
|
6038
|
+
{
|
|
6039
|
+
const virtualNode = chore.$host$;
|
|
6040
|
+
const payload = chore.$payload$;
|
|
6041
|
+
let value = payload.$value$;
|
|
6042
|
+
if (isSignal(value)) {
|
|
6043
|
+
value = value.value;
|
|
6044
|
+
}
|
|
6045
|
+
const isConst = payload.$isConst$;
|
|
6046
|
+
const journal = container.$journal$;
|
|
6047
|
+
const property = chore.$idx$;
|
|
6048
|
+
const serializedValue = serializeAttribute(property, value, payload.$scopedStyleIdPrefix$);
|
|
6049
|
+
if (isServer) {
|
|
6050
|
+
container.addBackpatchEntry(chore.$host$.id, property, serializedValue);
|
|
6051
|
+
returnValue = null;
|
|
6052
|
+
}
|
|
6053
|
+
else {
|
|
5615
6054
|
if (isConst) {
|
|
5616
6055
|
const element = virtualNode[6 /* ElementVNodeProps.element */];
|
|
5617
6056
|
journal.push(2 /* VNodeJournalOpCode.SetAttribute */, element, property, serializedValue);
|
|
@@ -5619,64 +6058,49 @@
|
|
|
5619
6058
|
else {
|
|
5620
6059
|
vnode_setAttr(journal, virtualNode, property, serializedValue);
|
|
5621
6060
|
}
|
|
6061
|
+
returnValue = undefined;
|
|
5622
6062
|
}
|
|
5623
|
-
break;
|
|
5624
|
-
case 1 /* ChoreType.QRL_RESOLVE */: {
|
|
5625
|
-
{
|
|
5626
|
-
const target = chore.$target$;
|
|
5627
|
-
returnValue = !target.resolved ? target.resolve() : null;
|
|
5628
|
-
}
|
|
5629
|
-
break;
|
|
5630
6063
|
}
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
5634
|
-
|
|
6064
|
+
break;
|
|
6065
|
+
case 1 /* ChoreType.QRL_RESOLVE */: {
|
|
6066
|
+
{
|
|
6067
|
+
const target = chore.$target$;
|
|
6068
|
+
returnValue = (!target.resolved ? target.resolve() : null);
|
|
6069
|
+
}
|
|
6070
|
+
break;
|
|
6071
|
+
}
|
|
6072
|
+
case 7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */: {
|
|
6073
|
+
{
|
|
6074
|
+
const target = chore.$target$;
|
|
6075
|
+
const effects = chore.$payload$;
|
|
6076
|
+
if (!effects?.size) {
|
|
6077
|
+
break;
|
|
6078
|
+
}
|
|
6079
|
+
let shouldCompute = target instanceof ComputedSignalImpl || target instanceof WrappedSignalImpl;
|
|
6080
|
+
if (target instanceof AsyncComputedSignalImpl && effects !== target.$effects$) {
|
|
6081
|
+
shouldCompute = false;
|
|
6082
|
+
}
|
|
6083
|
+
if (shouldCompute) {
|
|
5635
6084
|
const ctx = newInvokeContext();
|
|
5636
6085
|
ctx.$container$ = container;
|
|
5637
|
-
|
|
5638
|
-
|
|
5639
|
-
target.$
|
|
5640
|
-
|
|
5641
|
-
|
|
6086
|
+
// needed for computed signals and throwing QRLs
|
|
6087
|
+
returnValue = maybeThen(retryOnPromise(() => invoke.call(target, ctx, target.$computeIfNeeded$)), () => {
|
|
6088
|
+
if (target.$flags$ & 2 /* SignalFlags.RUN_EFFECTS */) {
|
|
6089
|
+
target.$flags$ &= -3 /* SignalFlags.RUN_EFFECTS */;
|
|
6090
|
+
return retryOnPromise(() => triggerEffects(container, target, effects));
|
|
5642
6091
|
}
|
|
5643
|
-
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
|
|
5649
|
-
}
|
|
5650
|
-
else {
|
|
5651
|
-
returnValue = retryOnPromise(() => triggerEffects(container, target, effects));
|
|
5652
|
-
}
|
|
6092
|
+
});
|
|
6093
|
+
}
|
|
6094
|
+
else {
|
|
6095
|
+
returnValue = retryOnPromise(() => {
|
|
6096
|
+
triggerEffects(container, target, effects);
|
|
6097
|
+
});
|
|
5653
6098
|
}
|
|
5654
|
-
break;
|
|
5655
6099
|
}
|
|
6100
|
+
break;
|
|
5656
6101
|
}
|
|
5657
6102
|
}
|
|
5658
|
-
|
|
5659
|
-
returnValue = Promise.reject(e);
|
|
5660
|
-
}
|
|
5661
|
-
const after = (value, error) => {
|
|
5662
|
-
currentChore = null;
|
|
5663
|
-
chore.$executed$ = true;
|
|
5664
|
-
if (error) {
|
|
5665
|
-
container.handleError(error, host);
|
|
5666
|
-
}
|
|
5667
|
-
else {
|
|
5668
|
-
chore.$returnValue$ = value;
|
|
5669
|
-
chore.$resolve$?.(value);
|
|
5670
|
-
}
|
|
5671
|
-
};
|
|
5672
|
-
if (isPromise(returnValue)) {
|
|
5673
|
-
chore.$promise$ = returnValue.then(after, (error) => after(undefined, error));
|
|
5674
|
-
chore.$resolve$?.(chore.$promise$);
|
|
5675
|
-
chore.$resolve$ = undefined;
|
|
5676
|
-
}
|
|
5677
|
-
else {
|
|
5678
|
-
after(returnValue);
|
|
5679
|
-
}
|
|
6103
|
+
return returnValue;
|
|
5680
6104
|
}
|
|
5681
6105
|
/**
|
|
5682
6106
|
* Compares two chores to determine their execution order in the scheduler's queue.
|
|
@@ -5705,15 +6129,6 @@
|
|
|
5705
6129
|
else {
|
|
5706
6130
|
assertFalse(vnode_isVNode(aHost), 'expected aHost to be SSRNode but it is a VNode');
|
|
5707
6131
|
assertFalse(vnode_isVNode(bHost), 'expected bHost to be SSRNode but it is a VNode');
|
|
5708
|
-
// we are running on the server.
|
|
5709
|
-
// On server we can't schedule task for a different host!
|
|
5710
|
-
// Server is SSR, and therefore scheduling for anything but the current host
|
|
5711
|
-
// implies that things need to be re-run nad that is not supported because of streaming.
|
|
5712
|
-
const errorMessage = `SERVER: during HTML streaming, re-running tasks on a different host is not allowed.
|
|
5713
|
-
You are attempting to change a state that has already been streamed to the client.
|
|
5714
|
-
This can lead to inconsistencies between Server-Side Rendering (SSR) and Client-Side Rendering (CSR).
|
|
5715
|
-
Problematic Node: ${aHost.toString()}`;
|
|
5716
|
-
logWarn(errorMessage);
|
|
5717
6132
|
const hostDiff = ssrNodeDocumentPosition(aHost, bHost);
|
|
5718
6133
|
if (hostDiff !== 0) {
|
|
5719
6134
|
return hostDiff;
|
|
@@ -5737,8 +6152,14 @@
|
|
|
5737
6152
|
// 1 means that we are going to process chores as FIFO
|
|
5738
6153
|
return 1;
|
|
5739
6154
|
}
|
|
5740
|
-
//
|
|
5741
|
-
|
|
6155
|
+
// ensure that the effect chores are scheduled for the same target
|
|
6156
|
+
// TODO: can we do this better?
|
|
6157
|
+
if (a.$type$ === 7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */ &&
|
|
6158
|
+
b.$type$ === 7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */ &&
|
|
6159
|
+
((a.$target$ instanceof StoreHandler && b.$target$ instanceof StoreHandler) ||
|
|
6160
|
+
(a.$target$ instanceof AsyncComputedSignalImpl &&
|
|
6161
|
+
b.$target$ instanceof AsyncComputedSignalImpl)) &&
|
|
6162
|
+
a.$payload$ !== b.$payload$) {
|
|
5742
6163
|
return 1;
|
|
5743
6164
|
}
|
|
5744
6165
|
// The chores are the same and will run only once
|
|
@@ -5770,6 +6191,15 @@
|
|
|
5770
6191
|
/// We need to ensure that the `queue` is sorted by priority.
|
|
5771
6192
|
/// 1. Find a place where to insert into.
|
|
5772
6193
|
const idx = sortedFindIndex(sortedArray, value, rootVNode);
|
|
6194
|
+
if (idx < 0 && runningChores.size) {
|
|
6195
|
+
// 1.1. Check if the chore is already running.
|
|
6196
|
+
for (const chore of runningChores) {
|
|
6197
|
+
const comp = choreComparator(value, chore, rootVNode);
|
|
6198
|
+
if (comp === 0) {
|
|
6199
|
+
return chore;
|
|
6200
|
+
}
|
|
6201
|
+
}
|
|
6202
|
+
}
|
|
5773
6203
|
if (idx < 0) {
|
|
5774
6204
|
/// 2. Insert the chore into the queue.
|
|
5775
6205
|
sortedArray.splice(~idx, 0, value);
|
|
@@ -5784,9 +6214,6 @@
|
|
|
5784
6214
|
if (existing.$payload$ !== value.$payload$) {
|
|
5785
6215
|
existing.$payload$ = value.$payload$;
|
|
5786
6216
|
}
|
|
5787
|
-
if (existing.$executed$) {
|
|
5788
|
-
existing.$executed$ = false;
|
|
5789
|
-
}
|
|
5790
6217
|
return existing;
|
|
5791
6218
|
}
|
|
5792
6219
|
};
|
|
@@ -5798,6 +6225,25 @@
|
|
|
5798
6225
|
vnode_isVNode(chore.$host$) &&
|
|
5799
6226
|
chore.$host$[0 /* VNodeProps.flags */] & 32 /* VNodeFlags.Deleted */);
|
|
5800
6227
|
}
|
|
6228
|
+
function addBlockedChore(blockedChore, blockingChore, blockedChores) {
|
|
6229
|
+
blockingChore.$blockedChores$ ||= [];
|
|
6230
|
+
blockingChore.$blockedChores$.push(blockedChore);
|
|
6231
|
+
blockedChores.add(blockedChore);
|
|
6232
|
+
}
|
|
6233
|
+
function choreTypeToName(type) {
|
|
6234
|
+
return ({
|
|
6235
|
+
[1 /* ChoreType.QRL_RESOLVE */]: 'Resolve QRL',
|
|
6236
|
+
[2 /* ChoreType.RUN_QRL */]: 'Run QRL',
|
|
6237
|
+
[3 /* ChoreType.TASK */]: 'Task',
|
|
6238
|
+
[4 /* ChoreType.NODE_DIFF */]: 'Changes diffing',
|
|
6239
|
+
[5 /* ChoreType.NODE_PROP */]: 'Updating node property',
|
|
6240
|
+
[6 /* ChoreType.COMPONENT */]: 'Component',
|
|
6241
|
+
[7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */]: 'Signal recompute',
|
|
6242
|
+
[16 /* ChoreType.VISIBLE */]: 'Visible',
|
|
6243
|
+
[32 /* ChoreType.CLEANUP_VISIBLE */]: 'Cleanup visible',
|
|
6244
|
+
[255 /* ChoreType.WAIT_FOR_QUEUE */]: 'Wait for queue',
|
|
6245
|
+
}[type] || 'Unknown: ' + type);
|
|
6246
|
+
}
|
|
5801
6247
|
function debugChoreTypeToString(type) {
|
|
5802
6248
|
return ({
|
|
5803
6249
|
[1 /* ChoreType.QRL_RESOLVE */]: 'QRL_RESOLVE',
|
|
@@ -5807,31 +6253,87 @@
|
|
|
5807
6253
|
[5 /* ChoreType.NODE_PROP */]: 'NODE_PROP',
|
|
5808
6254
|
[6 /* ChoreType.COMPONENT */]: 'COMPONENT',
|
|
5809
6255
|
[7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */]: 'RECOMPUTE_SIGNAL',
|
|
5810
|
-
[16 /* ChoreType.
|
|
5811
|
-
[32 /* ChoreType.
|
|
5812
|
-
[
|
|
5813
|
-
[255 /* ChoreType.WAIT_FOR_ALL */]: 'WAIT_FOR_ALL',
|
|
6256
|
+
[16 /* ChoreType.VISIBLE */]: 'VISIBLE',
|
|
6257
|
+
[32 /* ChoreType.CLEANUP_VISIBLE */]: 'CLEANUP_VISIBLE',
|
|
6258
|
+
[255 /* ChoreType.WAIT_FOR_QUEUE */]: 'WAIT_FOR_QUEUE',
|
|
5814
6259
|
}[type] || 'UNKNOWN: ' + type);
|
|
5815
6260
|
}
|
|
5816
|
-
function
|
|
5817
|
-
const
|
|
5818
|
-
|
|
5819
|
-
|
|
5820
|
-
|
|
5821
|
-
|
|
5822
|
-
|
|
5823
|
-
|
|
5824
|
-
|
|
5825
|
-
|
|
5826
|
-
|
|
5827
|
-
|
|
5828
|
-
|
|
5829
|
-
|
|
5830
|
-
|
|
5831
|
-
|
|
5832
|
-
|
|
6261
|
+
function debugTrace(action, arg, queue, blockedChores) {
|
|
6262
|
+
const lines = [];
|
|
6263
|
+
// Header
|
|
6264
|
+
lines.push(`Scheduler: ${action}`);
|
|
6265
|
+
// Argument section
|
|
6266
|
+
if (arg) {
|
|
6267
|
+
lines.push('');
|
|
6268
|
+
if (arg && '$type$' in arg) {
|
|
6269
|
+
const chore = arg;
|
|
6270
|
+
const type = debugChoreTypeToString(chore.$type$);
|
|
6271
|
+
const host = String(chore.$host$).replaceAll(/\n.*/gim, '');
|
|
6272
|
+
const qrlTarget = chore.$target$?.$symbol$;
|
|
6273
|
+
const targetOrHost = chore.$type$ === 1 /* ChoreType.QRL_RESOLVE */ || chore.$type$ === 2 /* ChoreType.RUN_QRL */
|
|
6274
|
+
? qrlTarget
|
|
6275
|
+
: host;
|
|
6276
|
+
lines.push(`🎯 Current Chore:`);
|
|
6277
|
+
lines.push(` Type: ${type}`);
|
|
6278
|
+
lines.push(` Host: ${targetOrHost}`);
|
|
6279
|
+
// Show execution time if available
|
|
6280
|
+
if (chore.$startTime$ && chore.$endTime$) {
|
|
6281
|
+
const executionTime = chore.$endTime$ - chore.$startTime$;
|
|
6282
|
+
lines.push(` Time: ${executionTime.toFixed(2)}ms`);
|
|
6283
|
+
}
|
|
6284
|
+
else if (chore.$startTime$) {
|
|
6285
|
+
const elapsedTime = performance.now() - chore.$startTime$;
|
|
6286
|
+
lines.push(` Time: ${elapsedTime.toFixed(2)}ms (running)`);
|
|
6287
|
+
}
|
|
6288
|
+
// Show blocked chores for this chore
|
|
6289
|
+
if (chore.$blockedChores$ && chore.$blockedChores$.length > 0) {
|
|
6290
|
+
lines.push(` ⛔ Blocked Chores:`);
|
|
6291
|
+
chore.$blockedChores$.forEach((blockedChore, index) => {
|
|
6292
|
+
const blockedType = debugChoreTypeToString(blockedChore.$type$);
|
|
6293
|
+
const blockedTarget = String(blockedChore.$host$).replaceAll(/\n.*/gim, '');
|
|
6294
|
+
lines.push(` ${index + 1}. ${blockedType} ${blockedTarget} ${blockedChore.$idx$}`);
|
|
6295
|
+
});
|
|
6296
|
+
}
|
|
6297
|
+
}
|
|
6298
|
+
else {
|
|
6299
|
+
lines.push(`📝 Argument: ${String(arg).replaceAll(/\n.*/gim, '')}`);
|
|
6300
|
+
}
|
|
6301
|
+
}
|
|
6302
|
+
// Queue section
|
|
6303
|
+
if (queue && queue.length > 0) {
|
|
6304
|
+
lines.push('');
|
|
6305
|
+
lines.push(`📋 Queue (${queue.length} items):`);
|
|
6306
|
+
queue.forEach((chore, index) => {
|
|
6307
|
+
const isActive = chore === arg;
|
|
6308
|
+
const activeMarker = isActive ? `▶ ` : ' ';
|
|
6309
|
+
const type = debugChoreTypeToString(chore.$type$);
|
|
6310
|
+
const state = chore.$state$ ? `[${ChoreState[chore.$state$]}]` : '';
|
|
6311
|
+
const host = String(chore.$host$).replaceAll(/\n.*/gim, '');
|
|
6312
|
+
const qrlTarget = chore.$target$?.$symbol$;
|
|
6313
|
+
const target = chore.$type$ === 1 /* ChoreType.QRL_RESOLVE */ || chore.$type$ === 2 /* ChoreType.RUN_QRL */
|
|
6314
|
+
? qrlTarget
|
|
6315
|
+
: host;
|
|
6316
|
+
const line = `${activeMarker}${state} ${type} ${target} ${chore.$idx$}`;
|
|
6317
|
+
lines.push(line);
|
|
5833
6318
|
});
|
|
5834
6319
|
}
|
|
6320
|
+
// Blocked chores section
|
|
6321
|
+
if (blockedChores && blockedChores.size > 0) {
|
|
6322
|
+
lines.push('');
|
|
6323
|
+
lines.push(`🚫 Blocked Chores (${blockedChores.size} items):`);
|
|
6324
|
+
Array.from(blockedChores).forEach((chore, index) => {
|
|
6325
|
+
const type = debugChoreTypeToString(chore.$type$);
|
|
6326
|
+
const host = String(chore.$host$).replaceAll(/\n.*/gim, '');
|
|
6327
|
+
const qrlTarget = chore.$target$?.$symbol$;
|
|
6328
|
+
const target = chore.$type$ === 1 /* ChoreType.QRL_RESOLVE */ || chore.$type$ === 2 /* ChoreType.RUN_QRL */
|
|
6329
|
+
? qrlTarget
|
|
6330
|
+
: host;
|
|
6331
|
+
lines.push(` ${index + 1}. ${type} ${target} ${chore.$idx$}`);
|
|
6332
|
+
});
|
|
6333
|
+
}
|
|
6334
|
+
// Footer
|
|
6335
|
+
lines.push('');
|
|
6336
|
+
lines.push('─'.repeat(60));
|
|
5835
6337
|
// eslint-disable-next-line no-console
|
|
5836
6338
|
console.log(lines.join('\n') + '\n');
|
|
5837
6339
|
}
|
|
@@ -5849,7 +6351,8 @@
|
|
|
5849
6351
|
$currentUniqueId$ = 0;
|
|
5850
6352
|
$instanceHash$ = null;
|
|
5851
6353
|
$buildBase$ = null;
|
|
5852
|
-
|
|
6354
|
+
$flushEpoch$ = 0;
|
|
6355
|
+
constructor(journalFlush, serverData, locale) {
|
|
5853
6356
|
this.$serverData$ = serverData;
|
|
5854
6357
|
this.$locale$ = locale;
|
|
5855
6358
|
this.$version$ = version;
|
|
@@ -5857,7 +6360,7 @@
|
|
|
5857
6360
|
this.$getObjectById$ = (_id) => {
|
|
5858
6361
|
throw Error('Not implemented');
|
|
5859
6362
|
};
|
|
5860
|
-
this.$scheduler$ = createScheduler(this,
|
|
6363
|
+
this.$scheduler$ = createScheduler(this, journalFlush);
|
|
5861
6364
|
}
|
|
5862
6365
|
trackSignalValue(signal, subscriber, property, data) {
|
|
5863
6366
|
return trackSignalAndAssignHost(signal, subscriber, property, this, data);
|
|
@@ -6166,9 +6669,10 @@
|
|
|
6166
6669
|
const shadowRootContainer = node;
|
|
6167
6670
|
const shadowRoot = shadowRootContainer?.shadowRoot;
|
|
6168
6671
|
if (shadowRoot) {
|
|
6672
|
+
const firstShadowRootChild = firstChild(shadowRoot);
|
|
6169
6673
|
walkContainer(
|
|
6170
6674
|
// we need to create a new walker for the shadow root
|
|
6171
|
-
document.createTreeWalker(
|
|
6675
|
+
document.createTreeWalker(firstShadowRootChild, 0x1 /* NodeFilter.SHOW_ELEMENT */ | 0x80 /* NodeFilter.SHOW_COMMENT */), null, firstShadowRootChild, null, '', null);
|
|
6172
6676
|
}
|
|
6173
6677
|
}
|
|
6174
6678
|
if ((nodeType & 2 /* NodeType.ELEMENT */) === 2 /* NodeType.ELEMENT */) {
|
|
@@ -6244,7 +6748,7 @@
|
|
|
6244
6748
|
/** @internal */
|
|
6245
6749
|
function _getQContainerElement(element) {
|
|
6246
6750
|
const qContainerElement = Array.isArray(element)
|
|
6247
|
-
? vnode_getDomParent(element)
|
|
6751
|
+
? vnode_getDomParent(element, true)
|
|
6248
6752
|
: element;
|
|
6249
6753
|
return qContainerElement.closest(QContainerSelector);
|
|
6250
6754
|
}
|
|
@@ -6259,7 +6763,6 @@
|
|
|
6259
6763
|
rootVNode;
|
|
6260
6764
|
document;
|
|
6261
6765
|
$journal$;
|
|
6262
|
-
renderDone = null;
|
|
6263
6766
|
$rawStateData$;
|
|
6264
6767
|
$storeProxyMap$ = new WeakMap();
|
|
6265
6768
|
$qFuncs$;
|
|
@@ -6269,9 +6772,11 @@
|
|
|
6269
6772
|
vNodeLocate = (id) => vnode_locate(this.rootVNode, id);
|
|
6270
6773
|
$stateData$;
|
|
6271
6774
|
$styleIds$ = null;
|
|
6272
|
-
$renderCount$ = 0;
|
|
6273
6775
|
constructor(element) {
|
|
6274
|
-
super(() =>
|
|
6776
|
+
super(() => {
|
|
6777
|
+
this.$flushEpoch$++;
|
|
6778
|
+
vnode_applyJournal(this.$journal$);
|
|
6779
|
+
}, {}, element.getAttribute(QLocaleAttr));
|
|
6275
6780
|
this.qContainer = element.getAttribute(QContainerAttr);
|
|
6276
6781
|
if (!this.qContainer) {
|
|
6277
6782
|
throw qError(25 /* QError.elementWithoutContainer */);
|
|
@@ -6313,20 +6818,17 @@
|
|
|
6313
6818
|
}
|
|
6314
6819
|
handleError(err, host) {
|
|
6315
6820
|
if (qDev && host) {
|
|
6316
|
-
// Clean vdom
|
|
6317
6821
|
if (typeof document !== 'undefined') {
|
|
6318
6822
|
const vHost = host;
|
|
6319
|
-
const errorDiv = document.createElement('errored-host');
|
|
6320
|
-
if (err && err instanceof Error) {
|
|
6321
|
-
errorDiv.props = { error: err };
|
|
6322
|
-
}
|
|
6323
|
-
errorDiv.setAttribute('q:key', '_error_');
|
|
6324
6823
|
const journal = [];
|
|
6325
|
-
const
|
|
6326
|
-
|
|
6327
|
-
|
|
6328
|
-
|
|
6329
|
-
|
|
6824
|
+
const vHostParent = vnode_getParent(vHost);
|
|
6825
|
+
const vHostNextSibling = vnode_getNextSibling(vHost);
|
|
6826
|
+
const vErrorDiv = vnode_createErrorDiv(document, vHost, err, journal);
|
|
6827
|
+
// If the host is an element node, we need to insert the error div into its parent.
|
|
6828
|
+
const insertHost = vnode_isElementVNode(vHost) ? vHostParent || vHost : vHost;
|
|
6829
|
+
// If the host is different then we need to insert errored-host in the same position as the host.
|
|
6830
|
+
const insertBefore = insertHost === vHost ? null : vHostNextSibling;
|
|
6831
|
+
vnode_insertBefore(journal, insertHost, vErrorDiv, insertBefore);
|
|
6330
6832
|
vnode_applyJournal(journal);
|
|
6331
6833
|
}
|
|
6332
6834
|
if (err && err instanceof Error) {
|
|
@@ -6346,19 +6848,16 @@
|
|
|
6346
6848
|
}
|
|
6347
6849
|
setContext(host, context, value) {
|
|
6348
6850
|
let ctx = this.getHostProp(host, QCtxAttr);
|
|
6349
|
-
if (
|
|
6851
|
+
if (ctx == null) {
|
|
6350
6852
|
this.setHostProp(host, QCtxAttr, (ctx = []));
|
|
6351
6853
|
}
|
|
6352
|
-
mapArray_set(ctx, context.id, value, 0);
|
|
6854
|
+
mapArray_set(ctx, context.id, value, 0, true);
|
|
6353
6855
|
}
|
|
6354
6856
|
resolveContext(host, contextId) {
|
|
6355
6857
|
while (host) {
|
|
6356
6858
|
const ctx = this.getHostProp(host, QCtxAttr);
|
|
6357
|
-
if (ctx) {
|
|
6358
|
-
|
|
6359
|
-
if (value) {
|
|
6360
|
-
return value;
|
|
6361
|
-
}
|
|
6859
|
+
if (ctx != null && mapArray_has(ctx, contextId.id, 0)) {
|
|
6860
|
+
return mapArray_get(ctx, contextId.id, 0);
|
|
6362
6861
|
}
|
|
6363
6862
|
host = this.getParentHost(host);
|
|
6364
6863
|
}
|
|
@@ -6404,29 +6903,6 @@
|
|
|
6404
6903
|
}
|
|
6405
6904
|
return vnode_getProp(vNode, name, getObjectById);
|
|
6406
6905
|
}
|
|
6407
|
-
scheduleRender() {
|
|
6408
|
-
this.$renderCount$++;
|
|
6409
|
-
this.renderDone ||= getPlatform().nextTick(() => this.processChores());
|
|
6410
|
-
return this.renderDone.finally(() => emitEvent('qrender', { instanceHash: this.$instanceHash$, renderCount: this.$renderCount$ }));
|
|
6411
|
-
}
|
|
6412
|
-
processChores() {
|
|
6413
|
-
let renderCount = this.$renderCount$;
|
|
6414
|
-
const result = this.$scheduler$(255 /* ChoreType.WAIT_FOR_ALL */);
|
|
6415
|
-
if (isPromise(result)) {
|
|
6416
|
-
return result.then(async () => {
|
|
6417
|
-
while (renderCount !== this.$renderCount$) {
|
|
6418
|
-
renderCount = this.$renderCount$;
|
|
6419
|
-
await this.$scheduler$(255 /* ChoreType.WAIT_FOR_ALL */);
|
|
6420
|
-
}
|
|
6421
|
-
this.renderDone = null;
|
|
6422
|
-
});
|
|
6423
|
-
}
|
|
6424
|
-
if (renderCount !== this.$renderCount$) {
|
|
6425
|
-
this.processChores();
|
|
6426
|
-
return;
|
|
6427
|
-
}
|
|
6428
|
-
this.renderDone = null;
|
|
6429
|
-
}
|
|
6430
6906
|
ensureProjectionResolved(vNode) {
|
|
6431
6907
|
if ((vNode[0 /* VNodeProps.flags */] & 16 /* VNodeFlags.Resolved */) === 0) {
|
|
6432
6908
|
vNode[0 /* VNodeProps.flags */] |= 16 /* VNodeFlags.Resolved */;
|
|
@@ -6436,7 +6912,9 @@
|
|
|
6436
6912
|
if (isSlotProp(prop)) {
|
|
6437
6913
|
const value = props[i + 1];
|
|
6438
6914
|
if (typeof value == 'string') {
|
|
6439
|
-
|
|
6915
|
+
const projection = this.vNodeLocate(value);
|
|
6916
|
+
props[i + 1] = projection;
|
|
6917
|
+
vnode_getProp(projection, QSlotParent, (id) => this.vNodeLocate(id));
|
|
6440
6918
|
}
|
|
6441
6919
|
}
|
|
6442
6920
|
}
|
|
@@ -6557,7 +7035,7 @@
|
|
|
6557
7035
|
}
|
|
6558
7036
|
};
|
|
6559
7037
|
const triggerEffects = (container, signal, effects) => {
|
|
6560
|
-
const isBrowser =
|
|
7038
|
+
const isBrowser = !isServerPlatform();
|
|
6561
7039
|
if (effects) {
|
|
6562
7040
|
const scheduleEffect = (effectSubscription) => {
|
|
6563
7041
|
const consumer = effectSubscription[0 /* EffectSubscriptionProp.CONSUMER */];
|
|
@@ -6567,7 +7045,7 @@
|
|
|
6567
7045
|
consumer.$flags$ |= 8 /* TaskFlags.DIRTY */;
|
|
6568
7046
|
let choreType = 3 /* ChoreType.TASK */;
|
|
6569
7047
|
if (consumer.$flags$ & 1 /* TaskFlags.VISIBLE_TASK */) {
|
|
6570
|
-
choreType =
|
|
7048
|
+
choreType = 16 /* ChoreType.VISIBLE */;
|
|
6571
7049
|
}
|
|
6572
7050
|
container.$scheduler$(choreType, consumer);
|
|
6573
7051
|
}
|
|
@@ -6590,22 +7068,22 @@
|
|
|
6590
7068
|
const props = container.getHostProp(host, ELEMENT_PROPS);
|
|
6591
7069
|
container.$scheduler$(6 /* ChoreType.COMPONENT */, host, qrl, props);
|
|
6592
7070
|
}
|
|
6593
|
-
else if (
|
|
6594
|
-
if (
|
|
7071
|
+
else if (property === "." /* EffectProperty.VNODE */) {
|
|
7072
|
+
if (isBrowser) {
|
|
6595
7073
|
const host = consumer;
|
|
6596
7074
|
container.$scheduler$(4 /* ChoreType.NODE_DIFF */, host, host, signal);
|
|
6597
7075
|
}
|
|
6598
|
-
|
|
6599
|
-
|
|
6600
|
-
|
|
6601
|
-
|
|
6602
|
-
|
|
6603
|
-
|
|
6604
|
-
|
|
6605
|
-
|
|
6606
|
-
|
|
6607
|
-
|
|
6608
|
-
|
|
7076
|
+
}
|
|
7077
|
+
else {
|
|
7078
|
+
const host = consumer;
|
|
7079
|
+
const effectData = effectSubscription[3 /* EffectSubscriptionProp.DATA */];
|
|
7080
|
+
if (effectData instanceof SubscriptionData) {
|
|
7081
|
+
const data = effectData.data;
|
|
7082
|
+
const payload = {
|
|
7083
|
+
...data,
|
|
7084
|
+
$value$: signal,
|
|
7085
|
+
};
|
|
7086
|
+
container.$scheduler$(5 /* ChoreType.NODE_PROP */, host, property, payload);
|
|
6609
7087
|
}
|
|
6610
7088
|
}
|
|
6611
7089
|
};
|
|
@@ -6626,10 +7104,10 @@
|
|
|
6626
7104
|
// flags |= ComputedSignalFlags.SERIALIZATION_STRATEGY_AUTO;
|
|
6627
7105
|
// break;
|
|
6628
7106
|
case 'never':
|
|
6629
|
-
flags |=
|
|
7107
|
+
flags |= 16 /* SerializationSignalFlags.SERIALIZATION_STRATEGY_NEVER */;
|
|
6630
7108
|
break;
|
|
6631
7109
|
case 'always':
|
|
6632
|
-
flags |=
|
|
7110
|
+
flags |= 32 /* SerializationSignalFlags.SERIALIZATION_STRATEGY_ALWAYS */;
|
|
6633
7111
|
break;
|
|
6634
7112
|
}
|
|
6635
7113
|
return flags;
|
|
@@ -7021,6 +7499,9 @@
|
|
|
7021
7499
|
}
|
|
7022
7500
|
let vParent = null;
|
|
7023
7501
|
do {
|
|
7502
|
+
if (callback?.(vCursor, vParent)) {
|
|
7503
|
+
return;
|
|
7504
|
+
}
|
|
7024
7505
|
const vFirstChild = vnode_getFirstChild(vCursor);
|
|
7025
7506
|
if (vFirstChild) {
|
|
7026
7507
|
vCursor = vFirstChild;
|
|
@@ -7189,6 +7670,7 @@
|
|
|
7189
7670
|
const flags = textVNode[0 /* VNodeProps.flags */];
|
|
7190
7671
|
if ((flags & 8 /* VNodeFlags.Inflated */) === 0) {
|
|
7191
7672
|
const parentNode = vnode_getDomParent(vnode);
|
|
7673
|
+
assertDefined(parentNode, 'Missing parent node.');
|
|
7192
7674
|
const sharedTextNode = textVNode[4 /* TextVNodeProps.node */];
|
|
7193
7675
|
const doc = parentNode.ownerDocument;
|
|
7194
7676
|
// Walk the previous siblings and inflate them.
|
|
@@ -7347,6 +7829,18 @@
|
|
|
7347
7829
|
}
|
|
7348
7830
|
return length;
|
|
7349
7831
|
};
|
|
7832
|
+
const vnode_createErrorDiv = (document, host, err, journal) => {
|
|
7833
|
+
const errorDiv = document.createElement('errored-host');
|
|
7834
|
+
if (err && err instanceof Error) {
|
|
7835
|
+
errorDiv.props = { error: err };
|
|
7836
|
+
}
|
|
7837
|
+
errorDiv.setAttribute('q:key', '_error_');
|
|
7838
|
+
const vErrorDiv = vnode_newElement(errorDiv, 'errored-host');
|
|
7839
|
+
vnode_getDOMChildNodes(journal, host, true).forEach((child) => {
|
|
7840
|
+
vnode_insertBefore(journal, vErrorDiv, child, null);
|
|
7841
|
+
});
|
|
7842
|
+
return vErrorDiv;
|
|
7843
|
+
};
|
|
7350
7844
|
const parseBoolean = (value) => {
|
|
7351
7845
|
if (value === 'false') {
|
|
7352
7846
|
return false;
|
|
@@ -7485,7 +7979,7 @@
|
|
|
7485
7979
|
* unlink the previous or next sibling, we don't know that after "a" node is "b". So we need to
|
|
7486
7980
|
* find children first (and inflate them).
|
|
7487
7981
|
*/
|
|
7488
|
-
const domParentVNode = vnode_getDomParentVNode(parent);
|
|
7982
|
+
const domParentVNode = vnode_getDomParentVNode(parent, false);
|
|
7489
7983
|
const parentNode = domParentVNode && domParentVNode[6 /* ElementVNodeProps.element */];
|
|
7490
7984
|
let domChildren = null;
|
|
7491
7985
|
if (domParentVNode) {
|
|
@@ -7534,27 +8028,31 @@
|
|
|
7534
8028
|
newChildCurrentParent !== parent)) {
|
|
7535
8029
|
vnode_remove(journal, newChildCurrentParent, newChild, false);
|
|
7536
8030
|
}
|
|
7537
|
-
|
|
7538
|
-
if
|
|
7539
|
-
|
|
7540
|
-
|
|
7541
|
-
|
|
7542
|
-
|
|
7543
|
-
|
|
7544
|
-
|
|
8031
|
+
const parentIsDeleted = parent[0 /* VNodeProps.flags */] & 32 /* VNodeFlags.Deleted */;
|
|
8032
|
+
// if the parent is deleted, then we don't need to insert the new child
|
|
8033
|
+
if (!parentIsDeleted) {
|
|
8034
|
+
let adjustedInsertBefore = null;
|
|
8035
|
+
if (insertBefore == null) {
|
|
8036
|
+
if (vnode_isVirtualVNode(parent)) {
|
|
8037
|
+
// If `insertBefore` is null, than we need to insert at the end of the list.
|
|
8038
|
+
// Well, not quite. If the parent is a virtual node, our "last node" is not the same
|
|
8039
|
+
// as the DOM "last node". So in that case we need to look for the "next node" from
|
|
8040
|
+
// our parent.
|
|
8041
|
+
adjustedInsertBefore = vnode_getDomSibling(parent, true, false);
|
|
8042
|
+
}
|
|
8043
|
+
}
|
|
8044
|
+
else if (vnode_isVirtualVNode(insertBefore)) {
|
|
8045
|
+
// If the `insertBefore` is virtual, than we need to descend into the virtual and find e actual
|
|
8046
|
+
adjustedInsertBefore = vnode_getDomSibling(insertBefore, true, true);
|
|
8047
|
+
}
|
|
8048
|
+
else {
|
|
8049
|
+
adjustedInsertBefore = insertBefore;
|
|
8050
|
+
}
|
|
8051
|
+
adjustedInsertBefore && vnode_ensureInflatedIfText(journal, adjustedInsertBefore);
|
|
8052
|
+
// Here we know the insertBefore node
|
|
8053
|
+
if (domChildren && domChildren.length) {
|
|
8054
|
+
journal.push(5 /* VNodeJournalOpCode.Insert */, parentNode, vnode_getNode(adjustedInsertBefore), ...domChildren);
|
|
7545
8055
|
}
|
|
7546
|
-
}
|
|
7547
|
-
else if (vnode_isVirtualVNode(insertBefore)) {
|
|
7548
|
-
// If the `insertBefore` is virtual, than we need to descend into the virtual and find e actual
|
|
7549
|
-
adjustedInsertBefore = vnode_getDomSibling(insertBefore, true, true);
|
|
7550
|
-
}
|
|
7551
|
-
else {
|
|
7552
|
-
adjustedInsertBefore = insertBefore;
|
|
7553
|
-
}
|
|
7554
|
-
adjustedInsertBefore && vnode_ensureInflatedIfText(journal, adjustedInsertBefore);
|
|
7555
|
-
// Here we know the insertBefore node
|
|
7556
|
-
if (domChildren && domChildren.length) {
|
|
7557
|
-
journal.push(5 /* VNodeJournalOpCode.Insert */, parentNode, vnode_getNode(adjustedInsertBefore), ...domChildren);
|
|
7558
8056
|
}
|
|
7559
8057
|
// link newChild into the previous/next list
|
|
7560
8058
|
const vNext = insertBefore;
|
|
@@ -7576,14 +8074,22 @@
|
|
|
7576
8074
|
newChild[2 /* VNodeProps.previousSibling */] = vPrevious;
|
|
7577
8075
|
newChild[3 /* VNodeProps.nextSibling */] = vNext;
|
|
7578
8076
|
newChild[1 /* VNodeProps.parent */] = parent;
|
|
8077
|
+
if (parentIsDeleted) {
|
|
8078
|
+
// if the parent is deleted, then the new child is also deleted
|
|
8079
|
+
newChild[0 /* VNodeProps.flags */] |= 32 /* VNodeFlags.Deleted */;
|
|
8080
|
+
}
|
|
7579
8081
|
};
|
|
7580
|
-
const vnode_getDomParent = (vnode) => {
|
|
7581
|
-
vnode = vnode_getDomParentVNode(vnode);
|
|
8082
|
+
const vnode_getDomParent = (vnode, includeProjection = true) => {
|
|
8083
|
+
vnode = vnode_getDomParentVNode(vnode, includeProjection);
|
|
7582
8084
|
return (vnode && vnode[6 /* ElementVNodeProps.element */]);
|
|
7583
8085
|
};
|
|
7584
|
-
const vnode_getDomParentVNode = (vnode) => {
|
|
8086
|
+
const vnode_getDomParentVNode = (vnode, includeProjection = true) => {
|
|
7585
8087
|
while (vnode && !vnode_isElementVNode(vnode)) {
|
|
7586
|
-
vnode =
|
|
8088
|
+
vnode =
|
|
8089
|
+
vnode[1 /* VNodeProps.parent */] ||
|
|
8090
|
+
(includeProjection
|
|
8091
|
+
? vnode_getProp(vnode, QSlotParent, (id) => (vnode_isVNode(id) ? id : null))
|
|
8092
|
+
: null);
|
|
7587
8093
|
}
|
|
7588
8094
|
return vnode;
|
|
7589
8095
|
};
|
|
@@ -7593,7 +8099,7 @@
|
|
|
7593
8099
|
vnode_ensureTextInflated(journal, vToRemove);
|
|
7594
8100
|
}
|
|
7595
8101
|
if (removeDOM) {
|
|
7596
|
-
const domParent = vnode_getDomParent(vParent);
|
|
8102
|
+
const domParent = vnode_getDomParent(vParent, false);
|
|
7597
8103
|
const isInnerHTMLParent = vnode_getAttr(vParent, dangerouslySetInnerHTML);
|
|
7598
8104
|
if (isInnerHTMLParent) {
|
|
7599
8105
|
// ignore children, as they are inserted via innerHTML
|
|
@@ -8074,6 +8580,26 @@
|
|
|
8074
8580
|
const vnode_getParent = (vnode) => {
|
|
8075
8581
|
return vnode[1 /* VNodeProps.parent */] || null;
|
|
8076
8582
|
};
|
|
8583
|
+
const vnode_isDescendantOf = (vnode, ancestor, rootVNode) => {
|
|
8584
|
+
let parent = vnode_getParentOrProjectionParent(vnode, rootVNode);
|
|
8585
|
+
while (parent) {
|
|
8586
|
+
if (parent === ancestor) {
|
|
8587
|
+
return true;
|
|
8588
|
+
}
|
|
8589
|
+
parent = vnode_getParentOrProjectionParent(parent, rootVNode);
|
|
8590
|
+
}
|
|
8591
|
+
return false;
|
|
8592
|
+
};
|
|
8593
|
+
const vnode_getParentOrProjectionParent = (vnode, rootVNode) => {
|
|
8594
|
+
if (rootVNode) {
|
|
8595
|
+
const parentProjection = vnode_getProp(vnode, QSlotParent, (id) => vnode_locate(rootVNode, id));
|
|
8596
|
+
if (parentProjection) {
|
|
8597
|
+
// This is a projection, so we need to check the parent of the projection
|
|
8598
|
+
return parentProjection;
|
|
8599
|
+
}
|
|
8600
|
+
}
|
|
8601
|
+
return vnode_getParent(vnode);
|
|
8602
|
+
};
|
|
8077
8603
|
const vnode_getNode = (vnode) => {
|
|
8078
8604
|
if (vnode === null || vnode_isVirtualVNode(vnode)) {
|
|
8079
8605
|
return null;
|
|
@@ -8433,13 +8959,15 @@
|
|
|
8433
8959
|
}
|
|
8434
8960
|
const container = this.$container$;
|
|
8435
8961
|
let propValue = allocate(container, typeId, value);
|
|
8962
|
+
Reflect.set(target, property, propValue);
|
|
8963
|
+
this.$data$[idx] = undefined;
|
|
8964
|
+
this.$data$[idx + 1] = propValue;
|
|
8436
8965
|
/** We stored the reference, so now we can inflate, allowing cycles. */
|
|
8437
8966
|
if (typeId >= 14 /* TypeIds.Error */) {
|
|
8438
8967
|
propValue = inflate(container, propValue, typeId, value);
|
|
8968
|
+
Reflect.set(target, property, propValue);
|
|
8969
|
+
this.$data$[idx + 1] = propValue;
|
|
8439
8970
|
}
|
|
8440
|
-
Reflect.set(target, property, propValue);
|
|
8441
|
-
this.$data$[idx] = undefined;
|
|
8442
|
-
this.$data$[idx + 1] = propValue;
|
|
8443
8971
|
return propValue;
|
|
8444
8972
|
}
|
|
8445
8973
|
has(target, property) {
|
|
@@ -8618,7 +9146,7 @@
|
|
|
8618
9146
|
*/
|
|
8619
9147
|
// try to download qrl in this tick
|
|
8620
9148
|
computed.$computeQrl$.resolve();
|
|
8621
|
-
container.$scheduler
|
|
9149
|
+
container.$scheduler$(1 /* ChoreType.QRL_RESOLVE */, null, computed.$computeQrl$);
|
|
8622
9150
|
}
|
|
8623
9151
|
break;
|
|
8624
9152
|
}
|
|
@@ -9406,8 +9934,8 @@
|
|
|
9406
9934
|
}
|
|
9407
9935
|
else if (value instanceof ComputedSignalImpl) {
|
|
9408
9936
|
let v = value.$untrackedValue$;
|
|
9409
|
-
const shouldAlwaysSerialize = value.$flags$ &
|
|
9410
|
-
const shouldNeverSerialize = value.$flags$ &
|
|
9937
|
+
const shouldAlwaysSerialize = value.$flags$ & 32 /* SerializationSignalFlags.SERIALIZATION_STRATEGY_ALWAYS */;
|
|
9938
|
+
const shouldNeverSerialize = value.$flags$ & 16 /* SerializationSignalFlags.SERIALIZATION_STRATEGY_NEVER */;
|
|
9411
9939
|
const isInvalid = value.$flags$ & 1 /* SignalFlags.INVALID */;
|
|
9412
9940
|
const isSkippable = fastSkipSerialize(value.$untrackedValue$);
|
|
9413
9941
|
if (shouldAlwaysSerialize) {
|
|
@@ -10749,7 +11277,7 @@
|
|
|
10749
11277
|
container.$serverData$ = opts.serverData || {};
|
|
10750
11278
|
const host = container.rootVNode;
|
|
10751
11279
|
container.$scheduler$(4 /* ChoreType.NODE_DIFF */, host, host, jsxNode);
|
|
10752
|
-
await container.$scheduler$(255 /* ChoreType.
|
|
11280
|
+
await container.$scheduler$(255 /* ChoreType.WAIT_FOR_QUEUE */).$returnValue$;
|
|
10753
11281
|
return {
|
|
10754
11282
|
cleanup: () => {
|
|
10755
11283
|
cleanup(container, container.rootVNode);
|
|
@@ -11587,7 +12115,7 @@
|
|
|
11587
12115
|
useRunTask(task, eagerness);
|
|
11588
12116
|
if (!isServerPlatform()) {
|
|
11589
12117
|
qrl.resolve(iCtx.$element$);
|
|
11590
|
-
iCtx.$container$.$scheduler$(
|
|
12118
|
+
iCtx.$container$.$scheduler$(16 /* ChoreType.VISIBLE */, task);
|
|
11591
12119
|
}
|
|
11592
12120
|
};
|
|
11593
12121
|
const useRunTask = (task, eagerness) => {
|
|
@@ -11816,7 +12344,7 @@
|
|
|
11816
12344
|
// the file 'qwik-prefetch-service-worker.js' is not located in /build/
|
|
11817
12345
|
resolvedOpts.path = baseUrl + resolvedOpts.path;
|
|
11818
12346
|
}
|
|
11819
|
-
let code = PREFETCH_CODE.replace("
|
|
12347
|
+
let code = PREFETCH_CODE.replace('"_URL_"', JSON.stringify(resolvedOpts.path.split('/').pop()));
|
|
11820
12348
|
if (!build.isDev) {
|
|
11821
12349
|
// consecutive spaces are indentation
|
|
11822
12350
|
code = code.replaceAll(/\s\s+/gm, '');
|
|
@@ -11846,6 +12374,17 @@
|
|
|
11846
12374
|
});
|
|
11847
12375
|
});
|
|
11848
12376
|
}
|
|
12377
|
+
if ('caches' in window) {
|
|
12378
|
+
caches
|
|
12379
|
+
.keys()
|
|
12380
|
+
.then((names) => {
|
|
12381
|
+
const cacheName = names.find((name) => name.startsWith('QwikBundles'));
|
|
12382
|
+
if (cacheName) {
|
|
12383
|
+
caches.delete(cacheName).catch(console.error);
|
|
12384
|
+
}
|
|
12385
|
+
})
|
|
12386
|
+
.catch(console.error);
|
|
12387
|
+
}
|
|
11849
12388
|
}).toString();
|
|
11850
12389
|
/**
|
|
11851
12390
|
* @deprecated This is no longer needed as the preloading happens automatically in qrl-class. You
|
|
@@ -11854,6 +12393,16 @@
|
|
|
11854
12393
|
*/
|
|
11855
12394
|
const PrefetchGraph = (_opts = {}) => null;
|
|
11856
12395
|
|
|
12396
|
+
//////////////////////////////////////////////////////////////////////////////////////////
|
|
12397
|
+
// Protect against duplicate imports
|
|
12398
|
+
//////////////////////////////////////////////////////////////////////////////////////////
|
|
12399
|
+
if (globalThis.__qwik) {
|
|
12400
|
+
console.error(`==============================================\n` +
|
|
12401
|
+
`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` +
|
|
12402
|
+
`==============================================\n`);
|
|
12403
|
+
}
|
|
12404
|
+
globalThis.__qwik = version;
|
|
12405
|
+
|
|
11857
12406
|
Object.defineProperty(exports, "isBrowser", {
|
|
11858
12407
|
enumerable: true,
|
|
11859
12408
|
get: function () { return build.isBrowser; }
|
|
@@ -11892,11 +12441,14 @@
|
|
|
11892
12441
|
exports._deserialize = _deserialize;
|
|
11893
12442
|
exports._dumpState = dumpState;
|
|
11894
12443
|
exports._fnSignal = _fnSignal;
|
|
12444
|
+
exports._getConstProps = _getConstProps;
|
|
11895
12445
|
exports._getContextContainer = _getContextContainer;
|
|
11896
12446
|
exports._getContextElement = _getContextElement;
|
|
11897
12447
|
exports._getContextEvent = _getContextEvent;
|
|
11898
12448
|
exports._getDomContainer = getDomContainer;
|
|
11899
12449
|
exports._getQContainerElement = _getQContainerElement;
|
|
12450
|
+
exports._getVarProps = _getVarProps;
|
|
12451
|
+
exports._hasStoreEffects = _hasStoreEffects;
|
|
11900
12452
|
exports._isJSXNode = isJSXNode;
|
|
11901
12453
|
exports._isStore = isStore;
|
|
11902
12454
|
exports._isStringifiable = isStringifiable;
|
|
@@ -11917,7 +12469,7 @@
|
|
|
11917
12469
|
exports._regSymbol = _regSymbol;
|
|
11918
12470
|
exports._resolveContextWithoutSequentialScope = _resolveContextWithoutSequentialScope;
|
|
11919
12471
|
exports._restProps = _restProps;
|
|
11920
|
-
exports._run =
|
|
12472
|
+
exports._run = _run;
|
|
11921
12473
|
exports._serializationWeakRef = _serializationWeakRef;
|
|
11922
12474
|
exports._serialize = _serialize;
|
|
11923
12475
|
exports._task = scheduleTask;
|
|
@@ -11950,6 +12502,7 @@
|
|
|
11950
12502
|
exports.createSignal = createSignal;
|
|
11951
12503
|
exports.event$ = event$;
|
|
11952
12504
|
exports.eventQrl = eventQrl;
|
|
12505
|
+
exports.forceStoreEffects = forceStoreEffects;
|
|
11953
12506
|
exports.getDomContainer = getDomContainer;
|
|
11954
12507
|
exports.getLocale = getLocale;
|
|
11955
12508
|
exports.getPlatform = getPlatform;
|