@qwik.dev/core 2.0.0-beta.32 → 2.0.0-beta.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/backpatch/index.mjs +2 -2
- package/dist/backpatch/package.json +1 -1
- package/dist/backpatch-executor.debug.js +12 -6
- package/dist/backpatch-executor.js +1 -1
- package/dist/build/package.json +1 -1
- package/dist/cli.mjs +26 -22
- package/dist/core-internal.d.ts +137 -5
- package/dist/core.min.mjs +9 -2
- package/dist/core.mjs +672 -321
- package/dist/core.mjs.map +1 -1
- package/dist/core.prod.mjs +3274 -3131
- package/dist/loader/package.json +1 -1
- package/dist/optimizer.d.ts +2 -2
- package/dist/optimizer.mjs +2392 -1565
- package/dist/preloader.mjs +1 -293
- package/dist/server-modules.d.ts +1 -0
- package/dist/server.d.ts +0 -54
- package/dist/server.mjs +194 -620
- package/dist/server.prod.mjs +404 -864
- package/dist/testing/index.d.ts +3 -1
- package/dist/testing/index.mjs +1128 -3723
- package/dist/testing/package.json +1 -1
- package/dist/worker/index.d.mts +21 -0
- package/dist/worker/index.mjs +318 -0
- package/dist/worker/package.json +9 -0
- package/dist/worker/worker.js +13 -0
- package/dist/worker/worker.node.js +15 -0
- package/dist/worker/worker.shared.js +63 -0
- package/handlers.mjs +18 -1
- package/package.json +10 -4
- package/public.d.ts +5 -0
- package/worker.d.ts +2 -0
package/dist/core.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @license
|
|
3
|
-
* @qwik.dev/core 2.0.0-beta.
|
|
3
|
+
* @qwik.dev/core 2.0.0-beta.35-dev+4603135
|
|
4
4
|
* Copyright QwikDev. All Rights Reserved.
|
|
5
5
|
* Use of this source code is governed by an MIT-style license that can be
|
|
6
6
|
* found in the LICENSE file at https://github.com/QwikDev/qwik/blob/main/LICENSE
|
|
@@ -9,13 +9,14 @@ import { isDev, isServer, isBrowser as isBrowser$1 } from '@qwik.dev/core/build'
|
|
|
9
9
|
export { isBrowser, isDev, isServer } from '@qwik.dev/core/build';
|
|
10
10
|
import { p } from '@qwik.dev/core/preloader';
|
|
11
11
|
|
|
12
|
-
//
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
const
|
|
12
|
+
// Direct `globalThis.X` accesses (no alias) so Terser's `global_defs` engages
|
|
13
|
+
// and folds these to literal booleans in production builds, allowing
|
|
14
|
+
// `qTest ? testBranch : prodBranch` shims to tree-shake.
|
|
15
|
+
const qDev = globalThis.qDev !== false;
|
|
16
|
+
const qInspector = globalThis.qInspector === true;
|
|
17
|
+
const qDynamicPlatform = globalThis.qDynamicPlatform !== false;
|
|
18
|
+
const qTest = globalThis.qTest === true;
|
|
19
|
+
const qRuntimeQrl = globalThis.qRuntimeQrl === true;
|
|
19
20
|
const seal = (obj) => {
|
|
20
21
|
if (qDev) {
|
|
21
22
|
Object.seal(obj);
|
|
@@ -189,9 +190,9 @@ const isPrimitiveOrNullUndefined = (v) => {
|
|
|
189
190
|
return (typeof v !== 'object' && typeof v !== 'function') || v === null || v === undefined;
|
|
190
191
|
};
|
|
191
192
|
|
|
192
|
-
const baseUrl = 'https://qwikdev-build-v2.qwik-8nx.pages.dev/docs/errors/#
|
|
193
|
+
const baseUrl = 'https://qwikdev-build-v2.qwik-8nx.pages.dev/docs/errors/#q';
|
|
193
194
|
const codeToText = (code, ...parts) => {
|
|
194
|
-
if (
|
|
195
|
+
if (isDev) {
|
|
195
196
|
// Keep one error, one line to make it easier to search for the error message.
|
|
196
197
|
// Keep in sync with packages/docs/src/routes/docs/errors/index.mdx
|
|
197
198
|
const MAP = [
|
|
@@ -443,6 +444,7 @@ const ELEMENT_KEY = 'q:key';
|
|
|
443
444
|
const ELEMENT_PROPS = 'q:props';
|
|
444
445
|
const ELEMENT_SEQ = 'q:seq';
|
|
445
446
|
const ELEMENT_SEQ_IDX = 'q:seqIdx';
|
|
447
|
+
const Q_PREFIX = 'q:';
|
|
446
448
|
const ITERATION_ITEM_SINGLE = 'q:p'; // Single iteration parameter (not an array)
|
|
447
449
|
const ITERATION_ITEM_MULTI = 'q:ps'; // Multiple iteration parameters (array)
|
|
448
450
|
/** Non serializable markers - always begins with `:` character */
|
|
@@ -450,6 +452,8 @@ const NON_SERIALIZABLE_MARKER_PREFIX = ':';
|
|
|
450
452
|
const USE_ON_LOCAL = NON_SERIALIZABLE_MARKER_PREFIX + 'on';
|
|
451
453
|
const USE_ON_LOCAL_SEQ_IDX = NON_SERIALIZABLE_MARKER_PREFIX + 'onIdx';
|
|
452
454
|
const USE_ON_LOCAL_FLAGS = NON_SERIALIZABLE_MARKER_PREFIX + 'onFlags';
|
|
455
|
+
const QCursorBoundary = Q_PREFIX + 'cursorBoundary';
|
|
456
|
+
const QNearestCursorBoundary = NON_SERIALIZABLE_MARKER_PREFIX + 'nearestCursorBoundary';
|
|
453
457
|
const Q_PROPS_SEPARATOR = ':';
|
|
454
458
|
const dangerouslySetInnerHTML = 'dangerouslySetInnerHTML';
|
|
455
459
|
const qwikInspectorAttr = 'data-qwik-inspector';
|
|
@@ -793,6 +797,30 @@ const styleKey = (qStyles, index) => {
|
|
|
793
797
|
return `${hashCode(qStyles.$hash$)}-${index}`;
|
|
794
798
|
};
|
|
795
799
|
|
|
800
|
+
/**
|
|
801
|
+
* Creates a function that schedules `fn` to run as a microtask. Microtasks run before browser
|
|
802
|
+
* paint, preventing flickering.
|
|
803
|
+
*/
|
|
804
|
+
const createMicroTask = (fn) => {
|
|
805
|
+
return () => queueMicrotask(fn);
|
|
806
|
+
};
|
|
807
|
+
/**
|
|
808
|
+
* Creates a function that schedules `fn` to run as a macrotask. Macrotasks yield to the browser,
|
|
809
|
+
* allowing paint and user input. Used for time-slicing to avoid blocking the main thread.
|
|
810
|
+
*/
|
|
811
|
+
const createMacroTask = (fn) => {
|
|
812
|
+
let macroTask;
|
|
813
|
+
if (typeof MessageChannel !== 'undefined') {
|
|
814
|
+
const channel = new MessageChannel();
|
|
815
|
+
channel.port1.onmessage = () => fn();
|
|
816
|
+
macroTask = () => channel.port2.postMessage(null);
|
|
817
|
+
}
|
|
818
|
+
else {
|
|
819
|
+
macroTask = () => setTimeout(fn);
|
|
820
|
+
}
|
|
821
|
+
return macroTask;
|
|
822
|
+
};
|
|
823
|
+
|
|
796
824
|
// keep this import from core/build so the cjs build works
|
|
797
825
|
const createPlatform = () => {
|
|
798
826
|
return {
|
|
@@ -893,33 +921,13 @@ const isServerPlatform = () => {
|
|
|
893
921
|
return false;
|
|
894
922
|
};
|
|
895
923
|
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
* paint, preventing flickering.
|
|
899
|
-
*/
|
|
900
|
-
const createMicroTask = (fn) => {
|
|
901
|
-
return () => queueMicrotask(fn);
|
|
902
|
-
};
|
|
903
|
-
/**
|
|
904
|
-
* Creates a function that schedules `fn` to run as a macrotask. Macrotasks yield to the browser,
|
|
905
|
-
* allowing paint and user input. Used for time-slicing to avoid blocking the main thread.
|
|
906
|
-
*/
|
|
907
|
-
const createMacroTask = (fn) => {
|
|
908
|
-
let macroTask;
|
|
909
|
-
if (typeof MessageChannel !== 'undefined') {
|
|
910
|
-
const channel = new MessageChannel();
|
|
911
|
-
channel.port1.onmessage = () => fn();
|
|
912
|
-
macroTask = () => channel.port2.postMessage(null);
|
|
913
|
-
}
|
|
914
|
-
else {
|
|
915
|
-
macroTask = () => setTimeout(fn);
|
|
916
|
-
}
|
|
917
|
-
return macroTask;
|
|
918
|
-
};
|
|
919
|
-
|
|
920
|
-
const isBrowser = import.meta.env.TEST ? !isServerPlatform() : !isServer;
|
|
924
|
+
const hasDocument = typeof document !== 'undefined';
|
|
925
|
+
const isBrowser = (qTest ? !isServerPlatform() : !isServer) && hasDocument;
|
|
921
926
|
// Browser-specific setup
|
|
922
927
|
const doc = isBrowser ? document : undefined;
|
|
928
|
+
const config = {
|
|
929
|
+
$maxIdlePreloads$: 25,
|
|
930
|
+
};
|
|
923
931
|
// Determine which rel attribute to use based on browser support
|
|
924
932
|
const rel = isBrowser && doc.createElement('link').relList?.supports?.('modulepreload')
|
|
925
933
|
? 'modulePreload'
|
|
@@ -935,7 +943,6 @@ const BundleImportState_Alias = 3;
|
|
|
935
943
|
const BundleImportState_Loaded = 4;
|
|
936
944
|
|
|
937
945
|
let base;
|
|
938
|
-
import.meta.env.TEST ? !isServerPlatform() : !isServer;
|
|
939
946
|
const makeBundle = (name, deps) => {
|
|
940
947
|
return {
|
|
941
948
|
$name$: name,
|
|
@@ -965,7 +972,6 @@ const nextAdjustmentMacroTask = createMacroTask(processPendingAdjustments);
|
|
|
965
972
|
let isTriggerScheduled = false;
|
|
966
973
|
let isAdjustmentScheduled = false;
|
|
967
974
|
let isProcessingAdjustments = false;
|
|
968
|
-
const shouldYieldInBrowser = import.meta.env.TEST ? !isServerPlatform() : isBrowser$1;
|
|
969
975
|
const adjustmentStack = [];
|
|
970
976
|
/**
|
|
971
977
|
* This is called when a bundle is queued, or finished loading.
|
|
@@ -987,10 +993,8 @@ function trigger() {
|
|
|
987
993
|
const bundle = queue[0];
|
|
988
994
|
const inverseProbability = bundle.$inverseProbability$;
|
|
989
995
|
const probability = 1 - inverseProbability;
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
// When we're 99% sure, everything needs to be queued
|
|
993
|
-
if (probability >= 0.99 || preloadCount < allowedPreloads) {
|
|
996
|
+
// We want to preload all the transitive static (1) and dynamic (0.99) dependencies, throttled by the user defined maxIdlePreloads.
|
|
997
|
+
if (probability >= 0.99 || preloadCount < config.$maxIdlePreloads$) {
|
|
994
998
|
queue.shift();
|
|
995
999
|
preloadOne(bundle);
|
|
996
1000
|
if (performance.now() >= deadline) {
|
|
@@ -1007,13 +1011,12 @@ function trigger() {
|
|
|
1007
1011
|
nextTriggerMacroTask();
|
|
1008
1012
|
}
|
|
1009
1013
|
}
|
|
1010
|
-
const enqueueAdjustment = (bundle, inverseProbability,
|
|
1014
|
+
const enqueueAdjustment = (bundle, inverseProbability, seen) => {
|
|
1011
1015
|
// Keep existing work on the stack hot and append new roots behind it.
|
|
1012
1016
|
adjustmentStack.unshift({
|
|
1013
1017
|
$bundle$: bundle,
|
|
1014
1018
|
$inverseProbability$: inverseProbability,
|
|
1015
1019
|
$seen$: seen,
|
|
1016
|
-
$context$: context,
|
|
1017
1020
|
});
|
|
1018
1021
|
};
|
|
1019
1022
|
const processAdjustmentFrame = () => {
|
|
@@ -1033,9 +1036,8 @@ const processAdjustmentFrame = () => {
|
|
|
1033
1036
|
}
|
|
1034
1037
|
const probability = 1 - bundle.$inverseProbability$;
|
|
1035
1038
|
let newInverseProbability;
|
|
1036
|
-
if (probability === 1 ||
|
|
1037
|
-
|
|
1038
|
-
// we're loaded at max probability, so elevate dynamic imports to 99% sure
|
|
1039
|
+
if (probability === 1 || probability >= 0.99) {
|
|
1040
|
+
// bundle is requested at max probability, so elevate all its transitive static and dynamic deps to 99% sure
|
|
1039
1041
|
newInverseProbability = Math.min(0.01, 1 - dep.$importProbability$);
|
|
1040
1042
|
}
|
|
1041
1043
|
else {
|
|
@@ -1051,7 +1053,6 @@ const processAdjustmentFrame = () => {
|
|
|
1051
1053
|
$bundle$: depBundle,
|
|
1052
1054
|
$inverseProbability$: newInverseProbability,
|
|
1053
1055
|
$seen$: frame.$seen$,
|
|
1054
|
-
$context$: frame.$context$,
|
|
1055
1056
|
});
|
|
1056
1057
|
return true;
|
|
1057
1058
|
}
|
|
@@ -1083,12 +1084,12 @@ function processPendingAdjustments() {
|
|
|
1083
1084
|
}
|
|
1084
1085
|
isAdjustmentScheduled = false;
|
|
1085
1086
|
isProcessingAdjustments = true;
|
|
1086
|
-
const deadline =
|
|
1087
|
+
const deadline = isBrowser ? performance.now() + yieldInterval : 0;
|
|
1087
1088
|
let processed = false;
|
|
1088
1089
|
while (adjustmentStack.length) {
|
|
1089
1090
|
processed = true;
|
|
1090
1091
|
const checkDeadline = processAdjustmentFrame();
|
|
1091
|
-
if (
|
|
1092
|
+
if (isBrowser && checkDeadline && performance.now() >= deadline) {
|
|
1092
1093
|
if (!isAdjustmentScheduled) {
|
|
1093
1094
|
isAdjustmentScheduled = true;
|
|
1094
1095
|
nextAdjustmentMacroTask();
|
|
@@ -1097,7 +1098,7 @@ function processPendingAdjustments() {
|
|
|
1097
1098
|
}
|
|
1098
1099
|
}
|
|
1099
1100
|
isProcessingAdjustments = false;
|
|
1100
|
-
if (processed &&
|
|
1101
|
+
if (processed && isBrowser) {
|
|
1101
1102
|
nextTriggerMacroTask();
|
|
1102
1103
|
}
|
|
1103
1104
|
}
|
|
@@ -1128,64 +1129,35 @@ const preloadOne = (bundle) => {
|
|
|
1128
1129
|
};
|
|
1129
1130
|
doc.head.appendChild(link);
|
|
1130
1131
|
};
|
|
1131
|
-
|
|
1132
|
-
* Adjust the probability of a bundle based on the probability of its dependent bundles, and queue
|
|
1133
|
-
* it if it's likely enough to be preloaded.
|
|
1134
|
-
*
|
|
1135
|
-
* Note that if the probability is 100%, we treat the dynamic imports as 99% sure, and both will be
|
|
1136
|
-
* preloaded without limit.
|
|
1137
|
-
*
|
|
1138
|
-
* We also limit "organic" probability to 98% so they don't get unlimited preloads.
|
|
1139
|
-
*/
|
|
1140
|
-
const adjustProbabilities = (bundle, newInverseProbability, seen) => {
|
|
1141
|
-
enqueueAdjustment(bundle, newInverseProbability, { $depsCount$: 0 }, seen);
|
|
1142
|
-
if (shouldYieldInBrowser) {
|
|
1143
|
-
nextAdjustmentMacroTask();
|
|
1144
|
-
}
|
|
1145
|
-
else {
|
|
1146
|
-
processPendingAdjustments();
|
|
1147
|
-
}
|
|
1148
|
-
};
|
|
1149
|
-
const handleBundle = (name, inverseProbability, context) => {
|
|
1132
|
+
const handleBundle = (name, inverseProbability) => {
|
|
1150
1133
|
const bundle = getBundle(name);
|
|
1151
|
-
if (bundle
|
|
1152
|
-
|
|
1153
|
-
enqueueAdjustment(bundle, inverseProbability, context);
|
|
1154
|
-
}
|
|
1155
|
-
else {
|
|
1156
|
-
adjustProbabilities(bundle, inverseProbability);
|
|
1157
|
-
}
|
|
1134
|
+
if (bundle) {
|
|
1135
|
+
enqueueAdjustment(bundle, inverseProbability);
|
|
1158
1136
|
}
|
|
1159
1137
|
};
|
|
1160
|
-
const preload = (
|
|
1161
|
-
if (!
|
|
1138
|
+
const preload = (item, probability) => {
|
|
1139
|
+
if (!item?.length) {
|
|
1162
1140
|
return;
|
|
1163
1141
|
}
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
if (Array.isArray(name)) {
|
|
1142
|
+
const inverseProbability = 1 - probability ;
|
|
1143
|
+
if (Array.isArray(item)) {
|
|
1167
1144
|
// We must process in reverse order to ensure first bundles are handled first
|
|
1168
|
-
for (let i =
|
|
1169
|
-
const
|
|
1170
|
-
|
|
1171
|
-
inverseProbability = 1 - item / 10;
|
|
1172
|
-
}
|
|
1173
|
-
else {
|
|
1174
|
-
handleBundle(item, inverseProbability, context);
|
|
1175
|
-
}
|
|
1145
|
+
for (let i = item.length - 1; i >= 0; i--) {
|
|
1146
|
+
const bundle = item[i];
|
|
1147
|
+
handleBundle(bundle, inverseProbability);
|
|
1176
1148
|
}
|
|
1177
1149
|
}
|
|
1178
1150
|
else {
|
|
1179
|
-
handleBundle(
|
|
1151
|
+
handleBundle(item, inverseProbability);
|
|
1180
1152
|
}
|
|
1181
|
-
if (
|
|
1153
|
+
if (isBrowser) {
|
|
1182
1154
|
nextAdjustmentMacroTask();
|
|
1183
1155
|
}
|
|
1184
1156
|
else {
|
|
1185
1157
|
processPendingAdjustments();
|
|
1186
1158
|
}
|
|
1187
1159
|
};
|
|
1188
|
-
if (
|
|
1160
|
+
if (isBrowser) {
|
|
1189
1161
|
// Get early hints from qwikloader
|
|
1190
1162
|
document.addEventListener('qsymbol', (ev) => {
|
|
1191
1163
|
const { symbol, href } = ev.detail;
|
|
@@ -1219,7 +1191,7 @@ const COMMA = ',';
|
|
|
1219
1191
|
*
|
|
1220
1192
|
* @public
|
|
1221
1193
|
*/
|
|
1222
|
-
const version = "2.0.0-beta.
|
|
1194
|
+
const version = "2.0.0-beta.35-dev+4603135";
|
|
1223
1195
|
|
|
1224
1196
|
const isNode = (value) => {
|
|
1225
1197
|
return value && typeof value.nodeType === 'number';
|
|
@@ -1675,6 +1647,17 @@ function mergeCursors(container, newCursorData, oldCursor) {
|
|
|
1675
1647
|
newCursorData.journal = oldJournal;
|
|
1676
1648
|
}
|
|
1677
1649
|
}
|
|
1650
|
+
// merge cursor boundaries
|
|
1651
|
+
const oldBoundaries = oldCursorData.boundaries;
|
|
1652
|
+
if (__EXPERIMENTAL__.suspense && oldBoundaries && oldBoundaries.length > 0) {
|
|
1653
|
+
const newBoundaries = (newCursorData.boundaries ||= []);
|
|
1654
|
+
for (let i = 0; i < oldBoundaries.length; i++) {
|
|
1655
|
+
const boundary = oldBoundaries[i];
|
|
1656
|
+
if (!newBoundaries.includes(boundary)) {
|
|
1657
|
+
newBoundaries.push(boundary);
|
|
1658
|
+
}
|
|
1659
|
+
}
|
|
1660
|
+
}
|
|
1678
1661
|
}
|
|
1679
1662
|
/**
|
|
1680
1663
|
* Gets the cursor data from a vNode.
|
|
@@ -1905,7 +1888,7 @@ class SignalImpl {
|
|
|
1905
1888
|
// to unsubscribe from. So we need to store the reference from the effect back
|
|
1906
1889
|
// to this signal.
|
|
1907
1890
|
ensureContainsBackRef(effectSubscriber, this);
|
|
1908
|
-
(
|
|
1891
|
+
(qTest ? !isDomContainer(this.$container$) : isServer) &&
|
|
1909
1892
|
addQrlToSerializationCtx(effectSubscriber, this.$container$);
|
|
1910
1893
|
}
|
|
1911
1894
|
return val;
|
|
@@ -2131,8 +2114,7 @@ class AsyncSignalImpl extends ComputedSignalImpl {
|
|
|
2131
2114
|
get untrackedValue() {
|
|
2132
2115
|
this.$computeIfNeeded$();
|
|
2133
2116
|
if (this.$current$?.$promise$) {
|
|
2134
|
-
if (this.$untrackedValue$ === NEEDS_COMPUTATION ||
|
|
2135
|
-
(import.meta.env.TEST ? isServerPlatform() : isServer)) {
|
|
2117
|
+
if (this.$untrackedValue$ === NEEDS_COMPUTATION || (qTest ? isServerPlatform() : isServer)) {
|
|
2136
2118
|
throw this.$current$?.$promise$;
|
|
2137
2119
|
}
|
|
2138
2120
|
return this.$untrackedValue$;
|
|
@@ -2142,7 +2124,7 @@ class AsyncSignalImpl extends ComputedSignalImpl {
|
|
|
2142
2124
|
}
|
|
2143
2125
|
// For clientOnly signals without initial value during SSR, throw if trying to read value
|
|
2144
2126
|
// During SSR, clientOnly signals are skipped, so there's no computed value available
|
|
2145
|
-
if ((
|
|
2127
|
+
if ((qTest ? isServerPlatform() : isServer) &&
|
|
2146
2128
|
this.$flags$ & 64 /* AsyncSignalFlags.CLIENT_ONLY */ &&
|
|
2147
2129
|
this.$untrackedValue$ === NEEDS_COMPUTATION) {
|
|
2148
2130
|
throw qError(35 /* QError.asyncClientOnlyValueDuringSSR */);
|
|
@@ -2216,7 +2198,7 @@ class AsyncSignalImpl extends ComputedSignalImpl {
|
|
|
2216
2198
|
// reading `.loading` means someone is interested in the result, so we should trigger the computation. The alternative is eager computation or imperative calls to invalidate; this seems nicer.
|
|
2217
2199
|
this.$computeIfNeeded$();
|
|
2218
2200
|
// During SSR there's no such thing as loading state, we must render complete results
|
|
2219
|
-
if ((
|
|
2201
|
+
if ((qTest ? isServerPlatform() : isServer) && this.$current$?.$promise$) {
|
|
2220
2202
|
throw this.$current$?.$promise$;
|
|
2221
2203
|
}
|
|
2222
2204
|
return this.$untrackedLoading$;
|
|
@@ -2317,7 +2299,7 @@ class AsyncSignalImpl extends ComputedSignalImpl {
|
|
|
2317
2299
|
if (!(this.$flags$ & 32 /* AsyncSignalFlags.EAGER_CLEANUP */) || this.$hasSubscribers$()) {
|
|
2318
2300
|
return;
|
|
2319
2301
|
}
|
|
2320
|
-
if (!(
|
|
2302
|
+
if (!(qTest ? !isServerPlatform() : isBrowser$1)) {
|
|
2321
2303
|
return;
|
|
2322
2304
|
}
|
|
2323
2305
|
setTimeout(() => {
|
|
@@ -2340,8 +2322,7 @@ class AsyncSignalImpl extends ComputedSignalImpl {
|
|
|
2340
2322
|
return;
|
|
2341
2323
|
}
|
|
2342
2324
|
// Skip computation on SSR for clientOnly signals
|
|
2343
|
-
if ((
|
|
2344
|
-
this.$flags$ & 64 /* AsyncSignalFlags.CLIENT_ONLY */) {
|
|
2325
|
+
if ((qTest ? isServerPlatform() : isServer) && this.$flags$ & 64 /* AsyncSignalFlags.CLIENT_ONLY */) {
|
|
2345
2326
|
// We must pretend to load, and register as a listener for the captures
|
|
2346
2327
|
this.$untrackedLoading$ = true;
|
|
2347
2328
|
this.$container$?.serializationCtx.$eagerResume$.add(this);
|
|
@@ -2373,9 +2354,11 @@ class AsyncSignalImpl extends ComputedSignalImpl {
|
|
|
2373
2354
|
}
|
|
2374
2355
|
async $runComputation$(running) {
|
|
2375
2356
|
const isCurrent = () => running === this.$current$;
|
|
2376
|
-
this.untrackedLoading = true;
|
|
2377
2357
|
let fn = this.$computeQrl$.resolved;
|
|
2378
2358
|
if (!fn) {
|
|
2359
|
+
// QRL resolution is async — we have to publish loading=true before awaiting so
|
|
2360
|
+
// subscribers know the value isn't ready yet.
|
|
2361
|
+
this.untrackedLoading = true;
|
|
2379
2362
|
fn = await this.$computeQrl$.resolve();
|
|
2380
2363
|
if (running.$abortController$?.signal.aborted) {
|
|
2381
2364
|
running.$promise$ = null;
|
|
@@ -2390,9 +2373,20 @@ class AsyncSignalImpl extends ComputedSignalImpl {
|
|
|
2390
2373
|
running.$abortController$?.abort(error);
|
|
2391
2374
|
}, this.$timeoutMs$);
|
|
2392
2375
|
}
|
|
2393
|
-
// Try to stay sync if possible
|
|
2376
|
+
// Try to stay sync if possible. Only publish loading=true to subscribers when
|
|
2377
|
+
// the compute is actually asynchronous — a synchronous resolve (e.g. pre-loaded
|
|
2378
|
+
// values injected via _injectAsyncSignalValue) should never transition through a
|
|
2379
|
+
// visible loading state, which on SSR would fire the loading-effect subscribers
|
|
2380
|
+
// (tasks) while the value is still "loading" from their perspective.
|
|
2394
2381
|
const valuePromise = retryOnPromise(fn.bind(null, running));
|
|
2395
|
-
|
|
2382
|
+
let value;
|
|
2383
|
+
if (isPromise(valuePromise)) {
|
|
2384
|
+
this.untrackedLoading = true;
|
|
2385
|
+
value = await valuePromise;
|
|
2386
|
+
}
|
|
2387
|
+
else {
|
|
2388
|
+
value = valuePromise;
|
|
2389
|
+
}
|
|
2396
2390
|
running.$promise$ = null;
|
|
2397
2391
|
if (running.$canWrite$) {
|
|
2398
2392
|
const jobs = this.$jobs$;
|
|
@@ -2476,7 +2470,7 @@ class AsyncSignalImpl extends ComputedSignalImpl {
|
|
|
2476
2470
|
}
|
|
2477
2471
|
}
|
|
2478
2472
|
$scheduleNextPoll$() {
|
|
2479
|
-
if ((
|
|
2473
|
+
if ((qTest ? isServerPlatform() : isServer) || !this.$expires$) {
|
|
2480
2474
|
return;
|
|
2481
2475
|
}
|
|
2482
2476
|
this.$clearNextPoll$();
|
|
@@ -3619,7 +3613,7 @@ const executeComponent = (container, renderHost, subscriptionHost, componentQRL,
|
|
|
3619
3613
|
const inlineComponent = componentQRL;
|
|
3620
3614
|
componentFn = () => invokeApply(iCtx, inlineComponent, [props || EMPTY_OBJ]);
|
|
3621
3615
|
}
|
|
3622
|
-
const isSsr =
|
|
3616
|
+
const isSsr = qTest ? isServerPlatform() : isServer;
|
|
3623
3617
|
const executeComponentWithPromiseExceptionRetry = (retryCount = 0) => safeCall(() => {
|
|
3624
3618
|
if (!isInlineComponent) {
|
|
3625
3619
|
container.setHostProp(renderHost, ELEMENT_SEQ_IDX, null);
|
|
@@ -4004,6 +3998,214 @@ const createSetTextOperation = (target, text) => new SetTextOperation(target, te
|
|
|
4004
3998
|
const createInsertOrMoveOperation = (target, parent, beforeTarget) => new InsertOrMoveOperation(target, parent, beforeTarget);
|
|
4005
3999
|
const createSetAttributeOperation = (target, attrName, attrValue, scopedStyleIdPrefix = null, isSvg = false) => new SetAttributeOperation(target, attrName, attrValue, scopedStyleIdPrefix, isSvg);
|
|
4006
4000
|
|
|
4001
|
+
/**
|
|
4002
|
+
* @internal
|
|
4003
|
+
* The storage provider for hooks. Each invocation increases index i. Data is stored in an array.
|
|
4004
|
+
*/
|
|
4005
|
+
const useSequentialScope = () => {
|
|
4006
|
+
const iCtx = useInvokeContext();
|
|
4007
|
+
const hostElement = iCtx.$hostElement$;
|
|
4008
|
+
const host = hostElement;
|
|
4009
|
+
let seq = iCtx.$container$.getHostProp(host, ELEMENT_SEQ);
|
|
4010
|
+
if (seq === null) {
|
|
4011
|
+
seq = [];
|
|
4012
|
+
iCtx.$container$.setHostProp(host, ELEMENT_SEQ, seq);
|
|
4013
|
+
}
|
|
4014
|
+
let seqIdx = iCtx.$container$.getHostProp(host, ELEMENT_SEQ_IDX);
|
|
4015
|
+
if (seqIdx === null) {
|
|
4016
|
+
seqIdx = 0;
|
|
4017
|
+
}
|
|
4018
|
+
iCtx.$container$.setHostProp(host, ELEMENT_SEQ_IDX, seqIdx + 1);
|
|
4019
|
+
while (seq.length <= seqIdx) {
|
|
4020
|
+
seq.push(undefined);
|
|
4021
|
+
}
|
|
4022
|
+
const set = (value) => {
|
|
4023
|
+
if (qDev) {
|
|
4024
|
+
verifySerializable(value);
|
|
4025
|
+
}
|
|
4026
|
+
return (seq[seqIdx] = value);
|
|
4027
|
+
};
|
|
4028
|
+
return {
|
|
4029
|
+
val: seq[seqIdx],
|
|
4030
|
+
set,
|
|
4031
|
+
i: seqIdx,
|
|
4032
|
+
iCtx,
|
|
4033
|
+
};
|
|
4034
|
+
};
|
|
4035
|
+
|
|
4036
|
+
const getSignal = (initialState) => {
|
|
4037
|
+
const value = isFunction(initialState) && !isQwikComponent(initialState)
|
|
4038
|
+
? invoke(undefined, initialState)
|
|
4039
|
+
: initialState;
|
|
4040
|
+
return createSignal(value);
|
|
4041
|
+
};
|
|
4042
|
+
// <docs markdown="../readme.md#useSignal">
|
|
4043
|
+
// !!DO NOT EDIT THIS COMMENT DIRECTLY!!!
|
|
4044
|
+
// (edit ../readme.md#useSignal instead and run `pnpm docs.sync`)
|
|
4045
|
+
/**
|
|
4046
|
+
* Creates an object with a single reactive `.value` property, that Qwik can track across
|
|
4047
|
+
* serializations.
|
|
4048
|
+
*
|
|
4049
|
+
* Use it to create state for your application. The object has a getter and setter to track reads
|
|
4050
|
+
* and writes of the `.value` property. When the value changes, any functions that read from it will
|
|
4051
|
+
* re-run.
|
|
4052
|
+
*
|
|
4053
|
+
* Prefer `useSignal` over `useStore` when possible, as it is more efficient.
|
|
4054
|
+
*
|
|
4055
|
+
* ### Example
|
|
4056
|
+
*
|
|
4057
|
+
* ```tsx
|
|
4058
|
+
* const Signals = component$(() => {
|
|
4059
|
+
* const counter = useSignal(1);
|
|
4060
|
+
* const text = useSignal('changeme');
|
|
4061
|
+
* const toggle = useSignal(false);
|
|
4062
|
+
*
|
|
4063
|
+
* // useSignal() can also accept a function to calculate the initial value
|
|
4064
|
+
* const state = useSignal(() => {
|
|
4065
|
+
* return expensiveInitialValue();
|
|
4066
|
+
* });
|
|
4067
|
+
*
|
|
4068
|
+
* return (
|
|
4069
|
+
* <div>
|
|
4070
|
+
* <button onClick$={() => counter.value++}>Counter: {counter.value}</button>
|
|
4071
|
+
* {
|
|
4072
|
+
* // pass signal values as the value, the optimizer will make it pass the signal
|
|
4073
|
+
* }
|
|
4074
|
+
* <Child state={state.value} />
|
|
4075
|
+
* {
|
|
4076
|
+
* // signals can be bound to inputs. A property named `bind:x` implies that the property
|
|
4077
|
+
* is a signal
|
|
4078
|
+
* }
|
|
4079
|
+
* <input type="text" bind:value={text} />
|
|
4080
|
+
* <input type="checkbox" bind:checked={toggle} />
|
|
4081
|
+
* </div>
|
|
4082
|
+
* );
|
|
4083
|
+
* });
|
|
4084
|
+
* ```
|
|
4085
|
+
*
|
|
4086
|
+
* @public
|
|
4087
|
+
*/
|
|
4088
|
+
// </docs>
|
|
4089
|
+
const useSignal = (initialState) => {
|
|
4090
|
+
return useConstant((getSignal), initialState);
|
|
4091
|
+
};
|
|
4092
|
+
/**
|
|
4093
|
+
* Stores a value which is retained for the lifetime of the component. Subsequent calls to
|
|
4094
|
+
* `useConstant` will always return the first value given.
|
|
4095
|
+
*
|
|
4096
|
+
* If the value is a function, the function is invoked once to calculate the actual value. You can
|
|
4097
|
+
* then also pass arguments to call the function with, so that you don't need to create a new
|
|
4098
|
+
* function on every render.
|
|
4099
|
+
*
|
|
4100
|
+
* @example
|
|
4101
|
+
*
|
|
4102
|
+
* ```tsx
|
|
4103
|
+
* const fixedRandomValue = useConstant(() => Math.random);
|
|
4104
|
+
* const otherFixedRandomValue = useConstant(Math.random);
|
|
4105
|
+
*
|
|
4106
|
+
* const getConfig = (env: string) => { ... }
|
|
4107
|
+
* const config = useConstant(getConfig, environment);
|
|
4108
|
+
* ```
|
|
4109
|
+
*
|
|
4110
|
+
* @public
|
|
4111
|
+
*/
|
|
4112
|
+
const useConstant = (value, ...args) => {
|
|
4113
|
+
const { val, set } = useSequentialScope();
|
|
4114
|
+
if (val != null) {
|
|
4115
|
+
return val;
|
|
4116
|
+
}
|
|
4117
|
+
// We don't want to create a subscription since we only run this once
|
|
4118
|
+
// Note: We are not using `invoke` here because we don't want to clear the context
|
|
4119
|
+
value = isFunction(value) && !isQwikComponent(value) ? untrack(value, ...args) : value;
|
|
4120
|
+
return set(value);
|
|
4121
|
+
};
|
|
4122
|
+
|
|
4123
|
+
const createCursorBoundary = () => {
|
|
4124
|
+
return {
|
|
4125
|
+
pending: createSignal(0),
|
|
4126
|
+
version: createSignal(0),
|
|
4127
|
+
};
|
|
4128
|
+
};
|
|
4129
|
+
/** @internal */
|
|
4130
|
+
const useCursorBoundary = () => {
|
|
4131
|
+
if (!__EXPERIMENTAL__.suspense) {
|
|
4132
|
+
throw new Error('useCursorBoundary is experimental and must be enabled with `experimental: ["suspense"]` in the `qwikVite` plugin.');
|
|
4133
|
+
}
|
|
4134
|
+
return useConstant(createCursorBoundary);
|
|
4135
|
+
};
|
|
4136
|
+
function addCursorBoundary(cursorData, vNode) {
|
|
4137
|
+
if (!__EXPERIMENTAL__.suspense) {
|
|
4138
|
+
return;
|
|
4139
|
+
}
|
|
4140
|
+
const boundary = getNearestCursorBoundary(cursorData.container, vNode);
|
|
4141
|
+
if (!boundary) {
|
|
4142
|
+
return;
|
|
4143
|
+
}
|
|
4144
|
+
const boundaries = (cursorData.boundaries ||= []);
|
|
4145
|
+
if (!boundaries.includes(boundary)) {
|
|
4146
|
+
boundaries.push(boundary);
|
|
4147
|
+
boundary.pending.value++;
|
|
4148
|
+
}
|
|
4149
|
+
}
|
|
4150
|
+
function resolveCursorBoundaries(cursorData) {
|
|
4151
|
+
if (!__EXPERIMENTAL__.suspense) {
|
|
4152
|
+
return;
|
|
4153
|
+
}
|
|
4154
|
+
const boundaries = cursorData.boundaries;
|
|
4155
|
+
if (!boundaries) {
|
|
4156
|
+
return;
|
|
4157
|
+
}
|
|
4158
|
+
cursorData.boundaries = null;
|
|
4159
|
+
for (let i = 0; i < boundaries.length; i++) {
|
|
4160
|
+
const boundary = boundaries[i];
|
|
4161
|
+
boundary.pending.value = Math.max(0, boundary.pending.value - 1);
|
|
4162
|
+
boundary.version.value++;
|
|
4163
|
+
}
|
|
4164
|
+
}
|
|
4165
|
+
function getOwnCursorBoundary(container, vNode) {
|
|
4166
|
+
if (!__EXPERIMENTAL__.suspense) {
|
|
4167
|
+
return null;
|
|
4168
|
+
}
|
|
4169
|
+
return container.getHostProp(vNode, QCursorBoundary);
|
|
4170
|
+
}
|
|
4171
|
+
function getNearestCursorBoundaryProp(vNode) {
|
|
4172
|
+
if (!__EXPERIMENTAL__.suspense) {
|
|
4173
|
+
return null;
|
|
4174
|
+
}
|
|
4175
|
+
return (vnode_getProp(vNode, QNearestCursorBoundary, null) ||
|
|
4176
|
+
null);
|
|
4177
|
+
}
|
|
4178
|
+
function clearNearestCursorBoundary(vNode) {
|
|
4179
|
+
if (!__EXPERIMENTAL__.suspense) {
|
|
4180
|
+
return;
|
|
4181
|
+
}
|
|
4182
|
+
vnode_setProp(vNode, QNearestCursorBoundary, null);
|
|
4183
|
+
}
|
|
4184
|
+
function getNearestCursorBoundary(container, vNode) {
|
|
4185
|
+
if (!__EXPERIMENTAL__.suspense) {
|
|
4186
|
+
return null;
|
|
4187
|
+
}
|
|
4188
|
+
return getNearestCursorBoundaryProp(vNode) || getOwnCursorBoundary(container, vNode);
|
|
4189
|
+
}
|
|
4190
|
+
function setNearestCursorBoundary(vNode, boundary) {
|
|
4191
|
+
__EXPERIMENTAL__.suspense && vnode_setProp(vNode, QNearestCursorBoundary, boundary);
|
|
4192
|
+
}
|
|
4193
|
+
/** Updates the nearest cursor boundary cache on a vnode and any already-dirty descendants. */
|
|
4194
|
+
function updateDirtySubtreeCursorBoundary(container, vNode, boundary) {
|
|
4195
|
+
if (!__EXPERIMENTAL__.suspense) {
|
|
4196
|
+
return;
|
|
4197
|
+
}
|
|
4198
|
+
setNearestCursorBoundary(vNode, boundary);
|
|
4199
|
+
const dirtyChildren = vNode.dirtyChildren;
|
|
4200
|
+
if (!dirtyChildren || dirtyChildren.length === 0) {
|
|
4201
|
+
return;
|
|
4202
|
+
}
|
|
4203
|
+
for (let i = 0; i < dirtyChildren.length; i++) {
|
|
4204
|
+
const child = dirtyChildren[i];
|
|
4205
|
+
updateDirtySubtreeCursorBoundary(container, child, getOwnCursorBoundary(container, child) || boundary);
|
|
4206
|
+
}
|
|
4207
|
+
}
|
|
4208
|
+
|
|
4007
4209
|
const cleanupDestroyable = (destroyable) => {
|
|
4008
4210
|
if (destroyable.$destroy$) {
|
|
4009
4211
|
try {
|
|
@@ -4124,7 +4326,7 @@ function peekNextSiblingWithinBoundary(diffContext, vCurrent) {
|
|
|
4124
4326
|
const _hasOwnProperty = Object.prototype.hasOwnProperty;
|
|
4125
4327
|
/** Helper to set an attribute on a vnode. Extracted to module scope to avoid closure allocation. */
|
|
4126
4328
|
function setAttribute(journal, vnode, key, value, scopedStyleIdPrefix, originalValue) {
|
|
4127
|
-
|
|
4329
|
+
qTest &&
|
|
4128
4330
|
scopedStyleIdPrefix &&
|
|
4129
4331
|
vnode_setProp(vnode, debugStyleScopeIdPrefixAttr, scopedStyleIdPrefix);
|
|
4130
4332
|
vnode_setProp(vnode, key, originalValue);
|
|
@@ -4528,8 +4730,10 @@ function expectProjection(diffContext) {
|
|
|
4528
4730
|
}
|
|
4529
4731
|
}
|
|
4530
4732
|
function expectSlot(diffContext) {
|
|
4733
|
+
const jsxNode = diffContext.$jsxValue$;
|
|
4531
4734
|
const vHost = vnode_getProjectionParentComponent(diffContext.$vParent$);
|
|
4532
4735
|
const slotNameKey = getSlotNameKey(diffContext, vHost);
|
|
4736
|
+
const cursorBoundary = directGetPropsProxyProp(jsxNode, QCursorBoundary) || null;
|
|
4533
4737
|
const vProjectedNode = vHost
|
|
4534
4738
|
? vnode_getProp(vHost, slotNameKey,
|
|
4535
4739
|
// for slots this id is vnode ref id
|
|
@@ -4540,6 +4744,8 @@ function expectSlot(diffContext) {
|
|
|
4540
4744
|
if (vProjectedNode == null) {
|
|
4541
4745
|
diffContext.$vNewNode$ = vnode_newVirtual();
|
|
4542
4746
|
vnode_setProp(diffContext.$vNewNode$, QSlot, slotNameKey);
|
|
4747
|
+
vnode_setProp(diffContext.$vNewNode$, QCursorBoundary, cursorBoundary);
|
|
4748
|
+
updateDirtySubtreeCursorBoundary(diffContext.$container$, diffContext.$vNewNode$, cursorBoundary);
|
|
4543
4749
|
vHost && vnode_setProp(vHost, slotNameKey, diffContext.$vNewNode$);
|
|
4544
4750
|
isDev &&
|
|
4545
4751
|
vnode_setProp(diffContext.$vNewNode$, DEBUG_TYPE, "P" /* VirtualType.Projection */); // Nothing to project, so render content of the slot.
|
|
@@ -4552,6 +4758,8 @@ function expectSlot(diffContext) {
|
|
|
4552
4758
|
const oldParent = vProjectedNode.parent;
|
|
4553
4759
|
diffContext.$vNewNode$ = vProjectedNode;
|
|
4554
4760
|
vnode_setProp(diffContext.$vNewNode$, QSlot, slotNameKey);
|
|
4761
|
+
vnode_setProp(diffContext.$vNewNode$, QCursorBoundary, cursorBoundary);
|
|
4762
|
+
updateDirtySubtreeCursorBoundary(diffContext.$container$, diffContext.$vNewNode$, cursorBoundary);
|
|
4555
4763
|
vHost && vnode_setProp(vHost, slotNameKey, diffContext.$vNewNode$);
|
|
4556
4764
|
isDev &&
|
|
4557
4765
|
vnode_setProp(diffContext.$vNewNode$, DEBUG_TYPE, "P" /* VirtualType.Projection */);
|
|
@@ -4787,7 +4995,7 @@ function registerEventHandlers(key, value, element, vnode, diffContext) {
|
|
|
4787
4995
|
function createElementWithNamespace(diffContext, elementName) {
|
|
4788
4996
|
const domParentVNode = vnode_getDomParentVNode(diffContext.$vParent$, true);
|
|
4789
4997
|
const namespaceData = getNewElementNamespaceData(domParentVNode, elementName);
|
|
4790
|
-
const currentDocument =
|
|
4998
|
+
const currentDocument = qTest ? diffContext.$container$.document : document;
|
|
4791
4999
|
const element = namespaceData.elementNamespaceFlag === 0 /* VNodeFlags.NS_html */
|
|
4792
5000
|
? currentDocument.createElement(elementName)
|
|
4793
5001
|
: currentDocument.createElementNS(namespaceData.elementNamespace, elementName);
|
|
@@ -4912,7 +5120,7 @@ const patchProperty = (diffContext, vnode, key, value, currentFile) => {
|
|
|
4912
5120
|
setAttribute(diffContext.$journal$, vnode, key, value, diffContext.$scopedStyleIdPrefix$, originalValue);
|
|
4913
5121
|
};
|
|
4914
5122
|
function registerQwikLoaderEvent(diffContext, eventName) {
|
|
4915
|
-
const qWindow =
|
|
5123
|
+
const qWindow = qTest
|
|
4916
5124
|
? diffContext.$container$.document.defaultView
|
|
4917
5125
|
: window;
|
|
4918
5126
|
if (qWindow) {
|
|
@@ -5226,7 +5434,7 @@ function expectText(diffContext, text) {
|
|
|
5226
5434
|
return;
|
|
5227
5435
|
}
|
|
5228
5436
|
}
|
|
5229
|
-
vnode_insertElementBefore(diffContext.$journal$, diffContext.$vParent$, (diffContext.$vNewNode$ = vnode_newText((
|
|
5437
|
+
vnode_insertElementBefore(diffContext.$journal$, diffContext.$vParent$, (diffContext.$vNewNode$ = vnode_newText((qTest ? diffContext.$container$.document : document).createTextNode(text), text)), getCurrentInsertBefore(diffContext));
|
|
5230
5438
|
}
|
|
5231
5439
|
/**
|
|
5232
5440
|
* Retrieve the key from the VNode.
|
|
@@ -6294,13 +6502,18 @@ function scheduleYield() {
|
|
|
6294
6502
|
*
|
|
6295
6503
|
* @param options - Walk options (time budget, etc.)
|
|
6296
6504
|
*/
|
|
6297
|
-
function processCursorQueue(
|
|
6298
|
-
timeBudget: 1000 / 60, // 60fps
|
|
6299
|
-
}) {
|
|
6505
|
+
function processCursorQueue() {
|
|
6300
6506
|
isNextTickScheduled = false;
|
|
6507
|
+
const startTime = performance.now();
|
|
6508
|
+
const yieldTime = startTime + 15; // 16 ms = 60 FPS, use 15 to yield slightly before next frame
|
|
6301
6509
|
let cursor = null;
|
|
6302
6510
|
while ((cursor = getHighestPriorityCursor())) {
|
|
6303
|
-
walkCursor(cursor,
|
|
6511
|
+
if (walkCursor(cursor, yieldTime)) {
|
|
6512
|
+
// Cursor overran time budget, yield to browser
|
|
6513
|
+
// Note that each tick we process at least one thing
|
|
6514
|
+
scheduleYield();
|
|
6515
|
+
return;
|
|
6516
|
+
}
|
|
6304
6517
|
}
|
|
6305
6518
|
}
|
|
6306
6519
|
/**
|
|
@@ -6319,13 +6532,12 @@ function processCursorQueue(options = {
|
|
|
6319
6532
|
* Note that there is only one walker for all containers in the app with the same Qwik version.
|
|
6320
6533
|
*
|
|
6321
6534
|
* @param cursor - The cursor to walk
|
|
6322
|
-
* @param
|
|
6323
|
-
* @returns
|
|
6535
|
+
* @param until - Time budget (timestamp to yield by)
|
|
6536
|
+
* @returns `true` if the walk was paused due to time budget (do not process more cursors in this
|
|
6537
|
+
* tick)
|
|
6324
6538
|
*/
|
|
6325
|
-
function walkCursor(cursor,
|
|
6326
|
-
const
|
|
6327
|
-
const isRunningOnServer = import.meta.env.TEST ? isServerPlatform() : isServer;
|
|
6328
|
-
const startTime = performance.now();
|
|
6539
|
+
function walkCursor(cursor, until) {
|
|
6540
|
+
const isRunningOnServer = qTest ? isServerPlatform() : isServer;
|
|
6329
6541
|
const cursorData = getCursorData(cursor);
|
|
6330
6542
|
// Check if cursor is blocked by a promise
|
|
6331
6543
|
const blockingPromise = cursorData.promise;
|
|
@@ -6349,7 +6561,8 @@ function walkCursor(cursor, options) {
|
|
|
6349
6561
|
// Skip if the vNode is not dirty
|
|
6350
6562
|
if (!(currentVNode.dirty & 511 /* ChoreBits.DIRTY_MASK */)) {
|
|
6351
6563
|
// Move to next node
|
|
6352
|
-
|
|
6564
|
+
__EXPERIMENTAL__.suspense && clearNearestCursorBoundary(currentVNode);
|
|
6565
|
+
setCursorPosition(container, cursorData, getNextVNode(currentVNode, cursor, container));
|
|
6353
6566
|
continue;
|
|
6354
6567
|
}
|
|
6355
6568
|
// Skip if the vNode is deleted
|
|
@@ -6367,7 +6580,7 @@ function walkCursor(cursor, options) {
|
|
|
6367
6580
|
}
|
|
6368
6581
|
// Clear dirty bits and move to next node
|
|
6369
6582
|
currentVNode.dirty &= -512 /* ChoreBits.DIRTY_MASK */;
|
|
6370
|
-
setCursorPosition(container, cursorData, getNextVNode(currentVNode, cursor));
|
|
6583
|
+
setCursorPosition(container, cursorData, getNextVNode(currentVNode, cursor, container));
|
|
6371
6584
|
continue;
|
|
6372
6585
|
}
|
|
6373
6586
|
let result;
|
|
@@ -6410,6 +6623,7 @@ function walkCursor(cursor, options) {
|
|
|
6410
6623
|
}
|
|
6411
6624
|
// Handle blocking promise
|
|
6412
6625
|
if (result && isPromise(result)) {
|
|
6626
|
+
addCursorBoundary(cursorData, currentVNode);
|
|
6413
6627
|
// Store promise on cursor and pause
|
|
6414
6628
|
cursorData.promise = result;
|
|
6415
6629
|
pauseCursor(cursor, container);
|
|
@@ -6426,13 +6640,8 @@ function walkCursor(cursor, options) {
|
|
|
6426
6640
|
return;
|
|
6427
6641
|
}
|
|
6428
6642
|
// Check time budget (only for DOM, not SSR)
|
|
6429
|
-
if (
|
|
6430
|
-
|
|
6431
|
-
if (elapsed >= timeBudget) {
|
|
6432
|
-
// Schedule continuation as macrotask to actually yield to browser
|
|
6433
|
-
scheduleYield();
|
|
6434
|
-
return;
|
|
6435
|
-
}
|
|
6643
|
+
if (performance.now() >= until) {
|
|
6644
|
+
return true;
|
|
6436
6645
|
}
|
|
6437
6646
|
}
|
|
6438
6647
|
isDev &&
|
|
@@ -6445,6 +6654,7 @@ function finishWalk(container, cursor, cursorData, isServer) {
|
|
|
6445
6654
|
if (!isServer) {
|
|
6446
6655
|
executeFlushPhase(cursor, container);
|
|
6447
6656
|
}
|
|
6657
|
+
resolveCursorBoundaries(cursorData);
|
|
6448
6658
|
if (cursorData.extraPromises) {
|
|
6449
6659
|
Promise.all(cursorData.extraPromises).then(() => {
|
|
6450
6660
|
resolveCursor(container);
|
|
@@ -6465,30 +6675,14 @@ function tryDescendDirtyChildren(container, cursorData, currentVNode, cursor) {
|
|
|
6465
6675
|
const dirtyChildren = currentVNode.dirtyChildren;
|
|
6466
6676
|
if (!dirtyChildren || dirtyChildren.length === 0) {
|
|
6467
6677
|
currentVNode.dirty &= -33 /* ChoreBits.CHILDREN */;
|
|
6678
|
+
clearNearestCursorBoundary(currentVNode);
|
|
6468
6679
|
return null;
|
|
6469
6680
|
}
|
|
6470
6681
|
partitionDirtyChildren(dirtyChildren, currentVNode);
|
|
6471
|
-
// Scan dirtyChildren directly instead of going through getNextVNode.
|
|
6472
|
-
// getNextVNode follows the child's parent/slotParent pointer, which for Projection nodes
|
|
6473
|
-
// points to the DOM insertion location rather than currentVNode — that would scan the
|
|
6474
|
-
// wrong dirtyChildren array and potentially cause infinite loops.
|
|
6475
|
-
// const len = dirtyChildren.length;
|
|
6476
|
-
// for (let i = 0; i < len; i++) {
|
|
6477
|
-
// const child = dirtyChildren[i];
|
|
6478
|
-
// if (child.dirty & ChoreBits.DIRTY_MASK) {
|
|
6479
|
-
// currentVNode.nextDirtyChildIndex = (i + 1) % len;
|
|
6480
|
-
// setCursorPosition(container, cursorData, child);
|
|
6481
|
-
// return child;
|
|
6482
|
-
// }
|
|
6483
|
-
// }
|
|
6484
|
-
// // No dirty child found — clean up
|
|
6485
|
-
// currentVNode.dirty &= ~ChoreBits.CHILDREN;
|
|
6486
|
-
// currentVNode.dirtyChildren = null;
|
|
6487
6682
|
currentVNode.nextDirtyChildIndex = 0;
|
|
6488
|
-
const next = getNextVNode(dirtyChildren[0], cursor);
|
|
6683
|
+
const next = getNextVNode(dirtyChildren[0], cursor, container);
|
|
6489
6684
|
setCursorPosition(container, cursorData, next);
|
|
6490
6685
|
return next;
|
|
6491
|
-
// return null;
|
|
6492
6686
|
}
|
|
6493
6687
|
/**
|
|
6494
6688
|
* Partitions dirtyChildren array so non-projections come first, projections last. Uses in-place
|
|
@@ -6510,7 +6704,7 @@ function partitionDirtyChildren(dirtyChildren, parent) {
|
|
|
6510
6704
|
}
|
|
6511
6705
|
}
|
|
6512
6706
|
/** @returns Next vNode to process, or null if traversal is complete */
|
|
6513
|
-
function getNextVNode(vNode, cursor) {
|
|
6707
|
+
function getNextVNode(vNode, cursor, container) {
|
|
6514
6708
|
if (vNode === cursor) {
|
|
6515
6709
|
if (cursor.dirty & 511 /* ChoreBits.DIRTY_MASK */) {
|
|
6516
6710
|
return cursor;
|
|
@@ -6538,6 +6732,13 @@ function getNextVNode(vNode, cursor) {
|
|
|
6538
6732
|
while (count-- > 0) {
|
|
6539
6733
|
const nextVNode = dirtyChildren[index];
|
|
6540
6734
|
if (nextVNode.dirty & 511 /* ChoreBits.DIRTY_MASK */) {
|
|
6735
|
+
if (container && splitCursorBoundary(container, nextVNode)) {
|
|
6736
|
+
index++;
|
|
6737
|
+
if (index === len) {
|
|
6738
|
+
index = 0;
|
|
6739
|
+
}
|
|
6740
|
+
continue;
|
|
6741
|
+
}
|
|
6541
6742
|
parent.nextDirtyChildIndex = (index + 1) % len;
|
|
6542
6743
|
return nextVNode;
|
|
6543
6744
|
}
|
|
@@ -6550,7 +6751,22 @@ function getNextVNode(vNode, cursor) {
|
|
|
6550
6751
|
parent.dirty &= -33 /* ChoreBits.CHILDREN */;
|
|
6551
6752
|
parent.dirtyChildren = null;
|
|
6552
6753
|
parent.nextDirtyChildIndex = 0;
|
|
6553
|
-
|
|
6754
|
+
__EXPERIMENTAL__.suspense && clearNearestCursorBoundary(parent);
|
|
6755
|
+
return getNextVNode(parent, cursor, container);
|
|
6756
|
+
}
|
|
6757
|
+
function splitCursorBoundary(container, vNode) {
|
|
6758
|
+
if (!__EXPERIMENTAL__.suspense) {
|
|
6759
|
+
return false;
|
|
6760
|
+
}
|
|
6761
|
+
if (!vNode.props ||
|
|
6762
|
+
!(QCursorBoundary in vNode.props) ||
|
|
6763
|
+
!container.getHostProp(vNode, QCursorBoundary)) {
|
|
6764
|
+
return false;
|
|
6765
|
+
}
|
|
6766
|
+
if (!isCursor(vNode)) {
|
|
6767
|
+
addCursor(container, vNode, 0);
|
|
6768
|
+
}
|
|
6769
|
+
return true;
|
|
6554
6770
|
}
|
|
6555
6771
|
|
|
6556
6772
|
/**
|
|
@@ -6570,6 +6786,7 @@ function addCursor(container, root, priority) {
|
|
|
6570
6786
|
position: root,
|
|
6571
6787
|
priority: priority,
|
|
6572
6788
|
promise: null,
|
|
6789
|
+
boundaries: null,
|
|
6573
6790
|
};
|
|
6574
6791
|
setCursorData(root, cursorData);
|
|
6575
6792
|
const cursor = root;
|
|
@@ -6613,7 +6830,7 @@ function _executeSsrChores(container, ssrNode) {
|
|
|
6613
6830
|
if (ssrNode.dirty & 16 /* ChoreBits.COMPUTE */) {
|
|
6614
6831
|
executeCompute(ssrNode, container);
|
|
6615
6832
|
}
|
|
6616
|
-
if (ssrNode.dirty & 511 /* ChoreBits.DIRTY_MASK */) {
|
|
6833
|
+
if (isDev && ssrNode.dirty & 511 /* ChoreBits.DIRTY_MASK */) {
|
|
6617
6834
|
// We are running on the server.
|
|
6618
6835
|
// On server we can't schedule task for a different host!
|
|
6619
6836
|
// Server is SSR, and therefore scheduling for anything but the current host
|
|
@@ -6736,14 +6953,23 @@ function propagatePath(target) {
|
|
|
6736
6953
|
* Propagates dirty bits from vNode up to the specified cursorRoot. Used during diff when we know
|
|
6737
6954
|
* the cursor root to merge with. Also updates cursor position if we pass through any cursors.
|
|
6738
6955
|
*/
|
|
6739
|
-
function propagateToCursorRoot(vNode, cursorRoot) {
|
|
6956
|
+
function propagateToCursorRoot(container, vNode, cursorRoot) {
|
|
6740
6957
|
reusablePath.push(vNode);
|
|
6958
|
+
let cursorBoundary = getOwnCursorBoundary(container, vNode);
|
|
6741
6959
|
let current = vNode.slotParent || vNode.parent;
|
|
6742
6960
|
while (current) {
|
|
6743
6961
|
const isDirty = current.dirty & 511 /* ChoreBits.DIRTY_MASK */;
|
|
6744
6962
|
const currentIsCursor = isCursor(current);
|
|
6963
|
+
if (__EXPERIMENTAL__.suspense) {
|
|
6964
|
+
cursorBoundary ||=
|
|
6965
|
+
getOwnCursorBoundary(container, current) ||
|
|
6966
|
+
(isDirty ? getNearestCursorBoundary(container, current) : null);
|
|
6967
|
+
}
|
|
6745
6968
|
// Stop when we reach the cursor root or a dirty ancestor
|
|
6746
6969
|
if (current === cursorRoot || isDirty) {
|
|
6970
|
+
// Known cursor root / dirty ancestor case: cache the boundary discovered while walking
|
|
6971
|
+
// before attaching this dirty vnode to the existing scheduled subtree.
|
|
6972
|
+
setNearestCursorBoundary(vNode, cursorBoundary);
|
|
6747
6973
|
propagatePath(current);
|
|
6748
6974
|
// Update cursor position if current is a cursor
|
|
6749
6975
|
if (currentIsCursor) {
|
|
@@ -6772,12 +6998,23 @@ function propagateToCursorRoot(vNode, cursorRoot) {
|
|
|
6772
6998
|
* Finds a blocking cursor or dirty ancestor and propagates dirty bits to it. Returns true if found
|
|
6773
6999
|
* and attached, false if a new cursor should be created.
|
|
6774
7000
|
*/
|
|
6775
|
-
function findAndPropagateToBlockingCursor(vNode) {
|
|
7001
|
+
function findAndPropagateToBlockingCursor(container, vNode) {
|
|
6776
7002
|
reusablePath.push(vNode);
|
|
7003
|
+
let cursorBoundary = __EXPERIMENTAL__.suspense
|
|
7004
|
+
? getOwnCursorBoundary(container, vNode)
|
|
7005
|
+
: null;
|
|
6777
7006
|
let current = vNode.slotParent || vNode.parent;
|
|
6778
7007
|
while (current) {
|
|
6779
7008
|
const currentIsCursor = isCursor(current);
|
|
7009
|
+
if (__EXPERIMENTAL__.suspense) {
|
|
7010
|
+
cursorBoundary ||=
|
|
7011
|
+
getOwnCursorBoundary(container, current) ||
|
|
7012
|
+
(currentIsCursor ? getNearestCursorBoundary(container, current) : null);
|
|
7013
|
+
}
|
|
6780
7014
|
if (currentIsCursor) {
|
|
7015
|
+
// Existing cursor case: attach this dirty vnode to the blocking cursor found above it and
|
|
7016
|
+
// remember that cursor's nearest boundary for async/suspense bookkeeping.
|
|
7017
|
+
setNearestCursorBoundary(vNode, cursorBoundary);
|
|
6781
7018
|
propagatePath(current);
|
|
6782
7019
|
reusablePath.length = 0;
|
|
6783
7020
|
return true;
|
|
@@ -6785,11 +7022,14 @@ function findAndPropagateToBlockingCursor(vNode) {
|
|
|
6785
7022
|
reusablePath.push(current);
|
|
6786
7023
|
current = current.slotParent || current.parent;
|
|
6787
7024
|
}
|
|
7025
|
+
// New cursor case: no blocking cursor was found above this vnode, so cache the nearest boundary
|
|
7026
|
+
// before the caller creates a cursor rooted at this vnode.
|
|
7027
|
+
setNearestCursorBoundary(vNode, cursorBoundary);
|
|
6788
7028
|
reusablePath.length = 0;
|
|
6789
7029
|
return false;
|
|
6790
7030
|
}
|
|
6791
7031
|
function isSsrNodeGuard(_vNode) {
|
|
6792
|
-
return
|
|
7032
|
+
return qTest ? isServerPlatform() : isServer;
|
|
6793
7033
|
}
|
|
6794
7034
|
/**
|
|
6795
7035
|
* Marks a vNode as dirty and propagates dirty bits up the tree.
|
|
@@ -6820,11 +7060,14 @@ function markVNodeDirty(container, vNode, bits, cursorRoot = null) {
|
|
|
6820
7060
|
const parent = vNode.slotParent || vNode.parent;
|
|
6821
7061
|
// If cursorRoot is provided, propagate up to it
|
|
6822
7062
|
if (cursorRoot && isRealDirty && parent && !parent.dirty) {
|
|
6823
|
-
propagateToCursorRoot(vNode, cursorRoot);
|
|
7063
|
+
propagateToCursorRoot(container, vNode, cursorRoot);
|
|
6824
7064
|
return;
|
|
6825
7065
|
}
|
|
6826
7066
|
// We must attach to a cursor subtree if it exists
|
|
6827
7067
|
if (parent && parent.dirty & 511 /* ChoreBits.DIRTY_MASK */) {
|
|
7068
|
+
// Dirty parent case: this vnode joins an already scheduled subtree, so inherit the parent's
|
|
7069
|
+
// nearest boundary unless this vnode owns a boundary itself.
|
|
7070
|
+
setNearestCursorBoundary(vNode, getOwnCursorBoundary(container, vNode) || getNearestCursorBoundary(container, parent));
|
|
6828
7071
|
if (isRealDirty) {
|
|
6829
7072
|
parent.dirty |= 32 /* ChoreBits.CHILDREN */;
|
|
6830
7073
|
}
|
|
@@ -6856,11 +7099,16 @@ function markVNodeDirty(container, vNode, bits, cursorRoot = null) {
|
|
|
6856
7099
|
else if (!isCursor(vNode)) {
|
|
6857
7100
|
// Check if there's an existing cursor that is blocking (executing a render-blocking task)
|
|
6858
7101
|
// If so, merge with it instead of creating a new cursor (single-pass find + propagate)
|
|
6859
|
-
if (!findAndPropagateToBlockingCursor(vNode)) {
|
|
7102
|
+
if (!findAndPropagateToBlockingCursor(container, vNode)) {
|
|
6860
7103
|
// No blocking cursor found, create a new one
|
|
6861
7104
|
addCursor(container, vNode, 0);
|
|
6862
7105
|
}
|
|
6863
7106
|
}
|
|
7107
|
+
else {
|
|
7108
|
+
// Existing cursor-root case: the vnode is already the scheduled cursor, so only its own
|
|
7109
|
+
// boundary can be authoritative here.
|
|
7110
|
+
setNearestCursorBoundary(vNode, getOwnCursorBoundary(container, vNode));
|
|
7111
|
+
}
|
|
6864
7112
|
}
|
|
6865
7113
|
function addVNodeOperation(journal, operation) {
|
|
6866
7114
|
journal.push(operation);
|
|
@@ -7049,6 +7297,7 @@ const vnode_newText = (textNode, textContent) => {
|
|
|
7049
7297
|
isDev && assertFalse(vnode_isVirtualVNode(vnode), 'Incorrect format of TextVNode.');
|
|
7050
7298
|
return vnode;
|
|
7051
7299
|
};
|
|
7300
|
+
/** @internal */
|
|
7052
7301
|
const vnode_newVirtual = () => {
|
|
7053
7302
|
const vnode = new VirtualVNode(null, 2 /* VNodeFlags.Virtual */ | (-1 << 12 /* VNodeFlagsIndex.shift */), // Flags
|
|
7054
7303
|
null, null, null, null, null, null);
|
|
@@ -7061,6 +7310,7 @@ const vnode_newVirtual = () => {
|
|
|
7061
7310
|
const vnode_isVNode = (vNode) => {
|
|
7062
7311
|
return vNode instanceof VNode;
|
|
7063
7312
|
};
|
|
7313
|
+
/** @internal */
|
|
7064
7314
|
const vnode_isElementVNode = (vNode) => {
|
|
7065
7315
|
return (vNode.flags & 1 /* VNodeFlags.Element */) === 1 /* VNodeFlags.Element */;
|
|
7066
7316
|
};
|
|
@@ -7119,6 +7369,7 @@ const vnode_getNodeTypeName = (vNode) => {
|
|
|
7119
7369
|
}
|
|
7120
7370
|
return '<unknown>';
|
|
7121
7371
|
};
|
|
7372
|
+
/** @internal */
|
|
7122
7373
|
const vnode_getProp = (vNode, key, getObject) => {
|
|
7123
7374
|
if (vnode_isElementVNode(vNode) || vnode_isVirtualVNode(vNode)) {
|
|
7124
7375
|
const value = vNode.props?.[key] ?? null;
|
|
@@ -7131,6 +7382,7 @@ const vnode_getProp = (vNode, key, getObject) => {
|
|
|
7131
7382
|
}
|
|
7132
7383
|
return null;
|
|
7133
7384
|
};
|
|
7385
|
+
/** @internal */
|
|
7134
7386
|
const vnode_setProp = (vNode, key, value) => {
|
|
7135
7387
|
if (value == null && vNode.props) {
|
|
7136
7388
|
delete vNode.props[key];
|
|
@@ -7142,7 +7394,7 @@ const vnode_setProp = (vNode, key, value) => {
|
|
|
7142
7394
|
};
|
|
7143
7395
|
const vnode_setAttr = (journal, vNode, key, value, scopedStyleIdPrefix = null) => {
|
|
7144
7396
|
if (vnode_isElementVNode(vNode)) {
|
|
7145
|
-
|
|
7397
|
+
qTest &&
|
|
7146
7398
|
scopedStyleIdPrefix &&
|
|
7147
7399
|
vnode_setProp(vNode, debugStyleScopeIdPrefixAttr, scopedStyleIdPrefix);
|
|
7148
7400
|
vnode_setProp(vNode, key, value);
|
|
@@ -7522,6 +7774,7 @@ const vnode_getChildWithIdx = (vNode, childIdx) => {
|
|
|
7522
7774
|
return child;
|
|
7523
7775
|
};
|
|
7524
7776
|
const vNodeStack = [];
|
|
7777
|
+
/** @internal */
|
|
7525
7778
|
const vnode_getVNodeForChildNode = (vNode, childElement) => {
|
|
7526
7779
|
ensureElementVNode(vNode);
|
|
7527
7780
|
let child = vnode_getFirstChild(vNode);
|
|
@@ -7835,6 +8088,7 @@ const vnode_inflateProjectionTrailingText = (journal, projection) => {
|
|
|
7835
8088
|
vnode_ensureTextInflated(journal, last);
|
|
7836
8089
|
}
|
|
7837
8090
|
};
|
|
8091
|
+
/** @internal */
|
|
7838
8092
|
const vnode_insertBefore = (journal, parent, newChild, insertBefore) => {
|
|
7839
8093
|
if (vnode_isElementOrTextVNode(newChild)) {
|
|
7840
8094
|
vnode_insertElementBefore(journal, parent, newChild, insertBefore);
|
|
@@ -7858,6 +8112,7 @@ const vnode_getDomParentVNode = (vnode, includeProjection) => {
|
|
|
7858
8112
|
}
|
|
7859
8113
|
return vnode;
|
|
7860
8114
|
};
|
|
8115
|
+
/** @internal */
|
|
7861
8116
|
const vnode_remove = (journal, vParent, vToRemove, removeDOM) => {
|
|
7862
8117
|
isDev && assertEqual(vParent, vToRemove.parent, 'Parent mismatch.');
|
|
7863
8118
|
if (vnode_isTextVNode(vToRemove)) {
|
|
@@ -7926,6 +8181,7 @@ const vnode_truncate = (journal, vParent, vDelete, removeDOM = true) => {
|
|
|
7926
8181
|
vParent.lastChild = vPrevious;
|
|
7927
8182
|
};
|
|
7928
8183
|
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
8184
|
+
/** @internal */
|
|
7929
8185
|
const vnode_getElementName = (vnode) => {
|
|
7930
8186
|
const elementVNode = ensureElementVNode(vnode);
|
|
7931
8187
|
let elementName = elementVNode.elementName;
|
|
@@ -8727,41 +8983,6 @@ function clearStoreOrProps(producer, effect) {
|
|
|
8727
8983
|
}
|
|
8728
8984
|
}
|
|
8729
8985
|
|
|
8730
|
-
/**
|
|
8731
|
-
* @internal
|
|
8732
|
-
* The storage provider for hooks. Each invocation increases index i. Data is stored in an array.
|
|
8733
|
-
*/
|
|
8734
|
-
const useSequentialScope = () => {
|
|
8735
|
-
const iCtx = useInvokeContext();
|
|
8736
|
-
const hostElement = iCtx.$hostElement$;
|
|
8737
|
-
const host = hostElement;
|
|
8738
|
-
let seq = iCtx.$container$.getHostProp(host, ELEMENT_SEQ);
|
|
8739
|
-
if (seq === null) {
|
|
8740
|
-
seq = [];
|
|
8741
|
-
iCtx.$container$.setHostProp(host, ELEMENT_SEQ, seq);
|
|
8742
|
-
}
|
|
8743
|
-
let seqIdx = iCtx.$container$.getHostProp(host, ELEMENT_SEQ_IDX);
|
|
8744
|
-
if (seqIdx === null) {
|
|
8745
|
-
seqIdx = 0;
|
|
8746
|
-
}
|
|
8747
|
-
iCtx.$container$.setHostProp(host, ELEMENT_SEQ_IDX, seqIdx + 1);
|
|
8748
|
-
while (seq.length <= seqIdx) {
|
|
8749
|
-
seq.push(undefined);
|
|
8750
|
-
}
|
|
8751
|
-
const set = (value) => {
|
|
8752
|
-
if (qDev) {
|
|
8753
|
-
verifySerializable(value);
|
|
8754
|
-
}
|
|
8755
|
-
return (seq[seqIdx] = value);
|
|
8756
|
-
};
|
|
8757
|
-
return {
|
|
8758
|
-
val: seq[seqIdx],
|
|
8759
|
-
set,
|
|
8760
|
-
i: seqIdx,
|
|
8761
|
-
iCtx,
|
|
8762
|
-
};
|
|
8763
|
-
};
|
|
8764
|
-
|
|
8765
8986
|
/** @internal */
|
|
8766
8987
|
const useTaskQrl = (qrl, opts) => {
|
|
8767
8988
|
const { val, set, iCtx, i } = useSequentialScope();
|
|
@@ -8907,7 +9128,7 @@ const addQrlToSerializationCtx = (effectSubscriber, container) => {
|
|
|
8907
9128
|
}
|
|
8908
9129
|
};
|
|
8909
9130
|
const scheduleEffects = (container, signal, effects) => {
|
|
8910
|
-
const
|
|
9131
|
+
const isRunningOnBrowser = qTest ? !isServerPlatform() : isBrowser$1;
|
|
8911
9132
|
if (effects) {
|
|
8912
9133
|
const scheduleEffect = (effectSubscription) => {
|
|
8913
9134
|
const consumer = effectSubscription.consumer;
|
|
@@ -8924,7 +9145,7 @@ const scheduleEffects = (container, signal, effects) => {
|
|
|
8924
9145
|
markVNodeDirty(container, consumer, 4 /* ChoreBits.COMPONENT */);
|
|
8925
9146
|
}
|
|
8926
9147
|
else if (property === "." /* EffectProperty.VNODE */) {
|
|
8927
|
-
if (
|
|
9148
|
+
if (isRunningOnBrowser) {
|
|
8928
9149
|
setNodeDiffPayload(consumer, signal);
|
|
8929
9150
|
markVNodeDirty(container, consumer, 2 /* ChoreBits.NODE_DIFF */);
|
|
8930
9151
|
}
|
|
@@ -8938,7 +9159,7 @@ const scheduleEffects = (container, signal, effects) => {
|
|
|
8938
9159
|
scopedStyleIdPrefix: data.$scopedStyleIdPrefix$,
|
|
8939
9160
|
value: signal,
|
|
8940
9161
|
};
|
|
8941
|
-
if (
|
|
9162
|
+
if (isRunningOnBrowser) {
|
|
8942
9163
|
setNodePropData(consumer, property, payload);
|
|
8943
9164
|
}
|
|
8944
9165
|
else {
|
|
@@ -9294,7 +9515,7 @@ function addStoreEffect(target, prop, store, effectSubscription) {
|
|
|
9294
9515
|
// to this signal.
|
|
9295
9516
|
ensureContainsBackRef(effectSubscription, target);
|
|
9296
9517
|
// TODO is this needed with the preloader?
|
|
9297
|
-
(
|
|
9518
|
+
(qTest ? !isDomContainer(store.$container$) : isServer) &&
|
|
9298
9519
|
addQrlToSerializationCtx(effectSubscription, store.$container$);
|
|
9299
9520
|
}
|
|
9300
9521
|
function setNewValueAndTriggerEffects(prop, value, target, currentStore) {
|
|
@@ -10398,7 +10619,9 @@ DomRefConstructor, symbolToChunkResolver, setProp, storeProxyMap, writer) => {
|
|
|
10398
10619
|
if (!writer) {
|
|
10399
10620
|
const buffer = [];
|
|
10400
10621
|
writer = {
|
|
10401
|
-
write: (text) =>
|
|
10622
|
+
write: (text) => {
|
|
10623
|
+
buffer.push(text);
|
|
10624
|
+
},
|
|
10402
10625
|
toString: () => buffer.join(''),
|
|
10403
10626
|
};
|
|
10404
10627
|
}
|
|
@@ -10933,19 +11156,29 @@ const _noopQrl = (symbolName, lexicalScopeCapture) => {
|
|
|
10933
11156
|
/** @internal */
|
|
10934
11157
|
const _noopQrlDEV = (symbolName, opts, lexicalScopeCapture) => {
|
|
10935
11158
|
const newQrl = _noopQrl(symbolName, lexicalScopeCapture);
|
|
11159
|
+
qDev && newQrl.$setDev$(opts);
|
|
11160
|
+
return newQrl;
|
|
11161
|
+
};
|
|
11162
|
+
/** @internal */
|
|
11163
|
+
const _qrlWithChunk = (chunk, importer, symbol, lexicalScopeCapture) => {
|
|
11164
|
+
return createQRL(chunk, symbol, null, importer, lexicalScopeCapture);
|
|
11165
|
+
};
|
|
11166
|
+
/** @internal */
|
|
11167
|
+
const _qrlWithChunkDEV = (chunk, importer, symbol, opts, lexicalScopeCapture) => {
|
|
11168
|
+
const newQrl = _qrlWithChunk(chunk, importer, symbol, lexicalScopeCapture);
|
|
10936
11169
|
newQrl.$setDev$(opts);
|
|
10937
11170
|
return newQrl;
|
|
10938
11171
|
};
|
|
10939
11172
|
/** @internal */
|
|
10940
11173
|
const qrlDEV = (chunkOrFn, symbol, opts, lexicalScopeCapture) => {
|
|
10941
11174
|
const newQrl = qrl(chunkOrFn, symbol, lexicalScopeCapture, 1);
|
|
10942
|
-
newQrl.$setDev$(opts);
|
|
11175
|
+
qDev && newQrl.$setDev$(opts);
|
|
10943
11176
|
return newQrl;
|
|
10944
11177
|
};
|
|
10945
11178
|
/** @internal */
|
|
10946
11179
|
const inlinedQrlDEV = (symbol, symbolName, opts, lexicalScopeCapture) => {
|
|
10947
11180
|
const qrl = inlinedQrl(symbol, symbolName, lexicalScopeCapture);
|
|
10948
|
-
qrl.$setDev$(opts);
|
|
11181
|
+
qDev && qrl.$setDev$(opts);
|
|
10949
11182
|
return qrl;
|
|
10950
11183
|
};
|
|
10951
11184
|
/**
|
|
@@ -10962,6 +11195,12 @@ const _regSymbol = (symbol, hash) => {
|
|
|
10962
11195
|
return symbol;
|
|
10963
11196
|
};
|
|
10964
11197
|
|
|
11198
|
+
/** @internal */
|
|
11199
|
+
const getAsyncLocalStorage = () => {
|
|
11200
|
+
const process = globalThis.process;
|
|
11201
|
+
return process?.getBuiltinModule?.('node:async_hooks')?.AsyncLocalStorage;
|
|
11202
|
+
};
|
|
11203
|
+
|
|
10965
11204
|
/** @file Shared types */
|
|
10966
11205
|
/** @internal */
|
|
10967
11206
|
function isStringifiable(value) {
|
|
@@ -11051,23 +11290,31 @@ async function _walkJSX(ssr, value, options) {
|
|
|
11051
11290
|
const enqueue = (value) => stack.push(value);
|
|
11052
11291
|
const drain = async () => {
|
|
11053
11292
|
while (stack.length) {
|
|
11054
|
-
|
|
11055
|
-
|
|
11056
|
-
|
|
11057
|
-
|
|
11058
|
-
|
|
11059
|
-
|
|
11060
|
-
|
|
11061
|
-
if (typeof value === 'function') {
|
|
11062
|
-
if (value === Promise) {
|
|
11063
|
-
stack.push(await stack.pop());
|
|
11293
|
+
try {
|
|
11294
|
+
const value = stack.pop();
|
|
11295
|
+
// Reference equality first (no prototype walk), then typeof
|
|
11296
|
+
if (value === MaybeAsyncSignal) {
|
|
11297
|
+
const trackFn = stack.pop();
|
|
11298
|
+
await retryOnPromise(() => stack.push(trackFn()));
|
|
11299
|
+
continue;
|
|
11064
11300
|
}
|
|
11065
|
-
|
|
11066
|
-
|
|
11301
|
+
if (typeof value === 'function') {
|
|
11302
|
+
if (value === Promise) {
|
|
11303
|
+
stack.push(await stack.pop());
|
|
11304
|
+
}
|
|
11305
|
+
else {
|
|
11306
|
+
await value.apply(ssr);
|
|
11307
|
+
}
|
|
11308
|
+
continue;
|
|
11309
|
+
}
|
|
11310
|
+
processJSXNode(ssr, enqueue, value, options);
|
|
11311
|
+
}
|
|
11312
|
+
finally {
|
|
11313
|
+
const pendingFlush = ssr.streamHandler.waitForPendingFlush();
|
|
11314
|
+
if (isPromise(pendingFlush)) {
|
|
11315
|
+
await pendingFlush;
|
|
11067
11316
|
}
|
|
11068
|
-
continue;
|
|
11069
11317
|
}
|
|
11070
|
-
processJSXNode(ssr, enqueue, value, options);
|
|
11071
11318
|
}
|
|
11072
11319
|
};
|
|
11073
11320
|
await drain();
|
|
@@ -11115,7 +11362,7 @@ function processJSXNode(ssr, enqueue, value, options) {
|
|
|
11115
11362
|
currentStyleScoped: options.currentStyleScoped,
|
|
11116
11363
|
parentComponentFrame: options.parentComponentFrame,
|
|
11117
11364
|
});
|
|
11118
|
-
ssr.streamHandler.flush();
|
|
11365
|
+
await ssr.streamHandler.flush();
|
|
11119
11366
|
}
|
|
11120
11367
|
});
|
|
11121
11368
|
}
|
|
@@ -11169,9 +11416,11 @@ function processJSXNode(ssr, enqueue, value, options) {
|
|
|
11169
11416
|
const componentFrame = options.parentComponentFrame;
|
|
11170
11417
|
if (componentFrame) {
|
|
11171
11418
|
const compId = componentFrame.componentNode.id || '';
|
|
11172
|
-
const projectionAttrs = isDev
|
|
11173
|
-
|
|
11174
|
-
|
|
11419
|
+
const projectionAttrs = isDev ? { [DEBUG_TYPE]: "P" /* VirtualType.Projection */ } : {};
|
|
11420
|
+
const cursorBoundary = directGetPropsProxyProp(jsx, QCursorBoundary);
|
|
11421
|
+
if (cursorBoundary) {
|
|
11422
|
+
projectionAttrs[QCursorBoundary] = cursorBoundary;
|
|
11423
|
+
}
|
|
11175
11424
|
projectionAttrs[QSlotParent] = compId;
|
|
11176
11425
|
ssr.openProjection(projectionAttrs);
|
|
11177
11426
|
const host = componentFrame.componentNode;
|
|
@@ -11212,7 +11461,7 @@ function processJSXNode(ssr, enqueue, value, options) {
|
|
|
11212
11461
|
currentStyleScoped: options.currentStyleScoped,
|
|
11213
11462
|
parentComponentFrame: options.parentComponentFrame,
|
|
11214
11463
|
});
|
|
11215
|
-
ssr.streamHandler.flush();
|
|
11464
|
+
await ssr.streamHandler.flush();
|
|
11216
11465
|
},
|
|
11217
11466
|
});
|
|
11218
11467
|
}
|
|
@@ -12091,7 +12340,7 @@ function inflateWrappedSignalValue(signal) {
|
|
|
12091
12340
|
}
|
|
12092
12341
|
}
|
|
12093
12342
|
function restoreEffectBackRefForConsumer(effect) {
|
|
12094
|
-
const isServerSide =
|
|
12343
|
+
const isServerSide = qTest ? isServerPlatform() : isServer;
|
|
12095
12344
|
const consumerBackRef = effect.consumer;
|
|
12096
12345
|
if (isServerSide && !consumerBackRef) {
|
|
12097
12346
|
// on browser, we don't serialize for example VNodes, so then on server side we don't have consumer
|
|
@@ -12239,6 +12488,7 @@ function getObjectById(id, stateData) {
|
|
|
12239
12488
|
isDev && assertTrue(id < stateData.length, `Invalid reference ${id} >= ${stateData.length}`);
|
|
12240
12489
|
return stateData[id];
|
|
12241
12490
|
}
|
|
12491
|
+
/** @internal */
|
|
12242
12492
|
function _createDeserializeContainer(stateData) {
|
|
12243
12493
|
// eslint-disable-next-line prefer-const
|
|
12244
12494
|
let state;
|
|
@@ -12281,6 +12531,14 @@ const _verifySerializable = (value, seen, ctx, preMessage) => {
|
|
|
12281
12531
|
if (canSerialize(unwrapped)) {
|
|
12282
12532
|
return value;
|
|
12283
12533
|
}
|
|
12534
|
+
// Framework-internal branded values (e.g. route loaders/actions, validators)
|
|
12535
|
+
// are callables or objects that stamp __brand / __brand__ to opt out of the
|
|
12536
|
+
// serializer walking their internals. Honor that for both objects and
|
|
12537
|
+
// functions — loader/action refs are functions with __brand = 'server_loader'
|
|
12538
|
+
// / 'server_action' and should not be rejected as unserializable.
|
|
12539
|
+
if (unwrapped.__brand || unwrapped.__brand__) {
|
|
12540
|
+
return value;
|
|
12541
|
+
}
|
|
12284
12542
|
const typeObj = typeof unwrapped;
|
|
12285
12543
|
switch (typeObj) {
|
|
12286
12544
|
case 'object':
|
|
@@ -12310,10 +12568,6 @@ const _verifySerializable = (value, seen, ctx, preMessage) => {
|
|
|
12310
12568
|
if (unwrapped instanceof VNode) {
|
|
12311
12569
|
return value;
|
|
12312
12570
|
}
|
|
12313
|
-
// We have .__brand and .__brand__
|
|
12314
|
-
if (unwrapped.__brand || unwrapped.__brand__) {
|
|
12315
|
-
return value;
|
|
12316
|
-
}
|
|
12317
12571
|
if (isSerializableObject(unwrapped)) {
|
|
12318
12572
|
for (const [key, item] of Object.entries(unwrapped)) {
|
|
12319
12573
|
_verifySerializable(item, seen, ctx + '.' + key);
|
|
@@ -13137,6 +13391,7 @@ class DomContainer extends _SharedContainer {
|
|
|
13137
13391
|
case OnRenderProp:
|
|
13138
13392
|
case QCtxAttr:
|
|
13139
13393
|
case QBackRefs:
|
|
13394
|
+
case QCursorBoundary:
|
|
13140
13395
|
getObjectById = this.$getObjectById$;
|
|
13141
13396
|
break;
|
|
13142
13397
|
case ELEMENT_SEQ_IDX:
|
|
@@ -13217,13 +13472,10 @@ class DomContainer extends _SharedContainer {
|
|
|
13217
13472
|
let _locale = undefined;
|
|
13218
13473
|
let localAsyncStore;
|
|
13219
13474
|
if (isServer) {
|
|
13220
|
-
|
|
13221
|
-
|
|
13222
|
-
localAsyncStore = new
|
|
13223
|
-
}
|
|
13224
|
-
.catch(() => {
|
|
13225
|
-
// ignore if AsyncLocalStorage is not available
|
|
13226
|
-
});
|
|
13475
|
+
const AsyncLocalStorage = getAsyncLocalStorage();
|
|
13476
|
+
if (AsyncLocalStorage) {
|
|
13477
|
+
localAsyncStore = new AsyncLocalStorage();
|
|
13478
|
+
}
|
|
13227
13479
|
}
|
|
13228
13480
|
/**
|
|
13229
13481
|
* Retrieve the current locale.
|
|
@@ -14157,6 +14409,25 @@ const component$ = (onMount) => {
|
|
|
14157
14409
|
/** @public */
|
|
14158
14410
|
const event$ = implicit$FirstArg(eventQrl);
|
|
14159
14411
|
|
|
14412
|
+
/**
|
|
14413
|
+
* Returns the client build manifest, which includes the mappings from symbols to bundles, the
|
|
14414
|
+
* bundlegraph etc.
|
|
14415
|
+
*
|
|
14416
|
+
* @public
|
|
14417
|
+
*/
|
|
14418
|
+
const getClientManifest = () => {
|
|
14419
|
+
// Keep this first because the magic-string first replaces the `!...` version and it can't replace after that.
|
|
14420
|
+
const manifest = globalThis.__QWIK_MANIFEST__;
|
|
14421
|
+
/**
|
|
14422
|
+
* Keep as-is, this is replaced verbatim with `false` by the qwikVite plugin, so this function
|
|
14423
|
+
* only throws if the build was not done correctly + no manifest was provided on globalThis.
|
|
14424
|
+
*/
|
|
14425
|
+
if (!globalThis.__QWIK_MANIFEST__) {
|
|
14426
|
+
throw new Error(`Client manifest is not available. It should have been automatically injected during the build process. Make sure that @qwik.dev/core is internal to the build.`);
|
|
14427
|
+
}
|
|
14428
|
+
return manifest;
|
|
14429
|
+
};
|
|
14430
|
+
|
|
14160
14431
|
/**
|
|
14161
14432
|
* Render JSX.
|
|
14162
14433
|
*
|
|
@@ -14727,7 +14998,7 @@ const useStylesScopedQrl = (styles) => {
|
|
|
14727
14998
|
*/
|
|
14728
14999
|
// </docs>
|
|
14729
15000
|
const useStylesScoped$ = /*#__PURE__*/ implicit$FirstArg(useStylesScopedQrl);
|
|
14730
|
-
const liveUpdate = isDev && ((import.meta.hot && typeof document !== 'undefined') ||
|
|
15001
|
+
const liveUpdate = isDev && ((import.meta.hot && typeof document !== 'undefined') || qTest);
|
|
14731
15002
|
const _useStyles = (styleQrl, transform, scoped) => {
|
|
14732
15003
|
assertQrl(styleQrl);
|
|
14733
15004
|
// eslint-disable-next-line prefer-const
|
|
@@ -14779,93 +15050,6 @@ const _useStyles = (styleQrl, transform, scoped) => {
|
|
|
14779
15050
|
return styleId;
|
|
14780
15051
|
};
|
|
14781
15052
|
|
|
14782
|
-
const getSignal = (initialState) => {
|
|
14783
|
-
const value = isFunction(initialState) && !isQwikComponent(initialState)
|
|
14784
|
-
? invoke(undefined, initialState)
|
|
14785
|
-
: initialState;
|
|
14786
|
-
return createSignal(value);
|
|
14787
|
-
};
|
|
14788
|
-
// <docs markdown="../readme.md#useSignal">
|
|
14789
|
-
// !!DO NOT EDIT THIS COMMENT DIRECTLY!!!
|
|
14790
|
-
// (edit ../readme.md#useSignal instead and run `pnpm docs.sync`)
|
|
14791
|
-
/**
|
|
14792
|
-
* Creates an object with a single reactive `.value` property, that Qwik can track across
|
|
14793
|
-
* serializations.
|
|
14794
|
-
*
|
|
14795
|
-
* Use it to create state for your application. The object has a getter and setter to track reads
|
|
14796
|
-
* and writes of the `.value` property. When the value changes, any functions that read from it will
|
|
14797
|
-
* re-run.
|
|
14798
|
-
*
|
|
14799
|
-
* Prefer `useSignal` over `useStore` when possible, as it is more efficient.
|
|
14800
|
-
*
|
|
14801
|
-
* ### Example
|
|
14802
|
-
*
|
|
14803
|
-
* ```tsx
|
|
14804
|
-
* const Signals = component$(() => {
|
|
14805
|
-
* const counter = useSignal(1);
|
|
14806
|
-
* const text = useSignal('changeme');
|
|
14807
|
-
* const toggle = useSignal(false);
|
|
14808
|
-
*
|
|
14809
|
-
* // useSignal() can also accept a function to calculate the initial value
|
|
14810
|
-
* const state = useSignal(() => {
|
|
14811
|
-
* return expensiveInitialValue();
|
|
14812
|
-
* });
|
|
14813
|
-
*
|
|
14814
|
-
* return (
|
|
14815
|
-
* <div>
|
|
14816
|
-
* <button onClick$={() => counter.value++}>Counter: {counter.value}</button>
|
|
14817
|
-
* {
|
|
14818
|
-
* // pass signal values as the value, the optimizer will make it pass the signal
|
|
14819
|
-
* }
|
|
14820
|
-
* <Child state={state.value} />
|
|
14821
|
-
* {
|
|
14822
|
-
* // signals can be bound to inputs. A property named `bind:x` implies that the property
|
|
14823
|
-
* is a signal
|
|
14824
|
-
* }
|
|
14825
|
-
* <input type="text" bind:value={text} />
|
|
14826
|
-
* <input type="checkbox" bind:checked={toggle} />
|
|
14827
|
-
* </div>
|
|
14828
|
-
* );
|
|
14829
|
-
* });
|
|
14830
|
-
* ```
|
|
14831
|
-
*
|
|
14832
|
-
* @public
|
|
14833
|
-
*/
|
|
14834
|
-
// </docs>
|
|
14835
|
-
const useSignal = (initialState) => {
|
|
14836
|
-
return useConstant((getSignal), initialState);
|
|
14837
|
-
};
|
|
14838
|
-
/**
|
|
14839
|
-
* Stores a value which is retained for the lifetime of the component. Subsequent calls to
|
|
14840
|
-
* `useConstant` will always return the first value given.
|
|
14841
|
-
*
|
|
14842
|
-
* If the value is a function, the function is invoked once to calculate the actual value. You can
|
|
14843
|
-
* then also pass arguments to call the function with, so that you don't need to create a new
|
|
14844
|
-
* function on every render.
|
|
14845
|
-
*
|
|
14846
|
-
* @example
|
|
14847
|
-
*
|
|
14848
|
-
* ```tsx
|
|
14849
|
-
* const fixedRandomValue = useConstant(() => Math.random);
|
|
14850
|
-
* const otherFixedRandomValue = useConstant(Math.random);
|
|
14851
|
-
*
|
|
14852
|
-
* const getConfig = (env: string) => { ... }
|
|
14853
|
-
* const config = useConstant(getConfig, environment);
|
|
14854
|
-
* ```
|
|
14855
|
-
*
|
|
14856
|
-
* @public
|
|
14857
|
-
*/
|
|
14858
|
-
const useConstant = (value, ...args) => {
|
|
14859
|
-
const { val, set } = useSequentialScope();
|
|
14860
|
-
if (val != null) {
|
|
14861
|
-
return val;
|
|
14862
|
-
}
|
|
14863
|
-
// We don't want to create a subscription since we only run this once
|
|
14864
|
-
// Note: We are not using `invoke` here because we don't want to clear the context
|
|
14865
|
-
value = isFunction(value) && !isQwikComponent(value) ? untrack(value, ...args) : value;
|
|
14866
|
-
return set(value);
|
|
14867
|
-
};
|
|
14868
|
-
|
|
14869
15053
|
const creator$2 = (qrl, options) => {
|
|
14870
15054
|
qrl.resolve();
|
|
14871
15055
|
return createComputedSignal(qrl, options);
|
|
@@ -15167,7 +15351,7 @@ const eachCmpTask = async ({ track }) => {
|
|
|
15167
15351
|
const host = context.$hostElement$;
|
|
15168
15352
|
const container = context.$container$;
|
|
15169
15353
|
markVNodeDirty(container, host, 128 /* ChoreBits.RECONCILE */);
|
|
15170
|
-
const isSsr =
|
|
15354
|
+
const isSsr = qTest ? isServerPlatform() : isServer;
|
|
15171
15355
|
if (isSsr) {
|
|
15172
15356
|
await container.$renderPromise$;
|
|
15173
15357
|
}
|
|
@@ -15184,6 +15368,173 @@ const eachCmp = (props) => {
|
|
|
15184
15368
|
const Each = /*#__PURE__*/ componentQrl(
|
|
15185
15369
|
/*#__PURE__*/ inlinedQrl(eachCmp, '_eaC'));
|
|
15186
15370
|
|
|
15371
|
+
const RevealContext = /*#__PURE__*/ createContextId('qk-reveal');
|
|
15372
|
+
const createRevealContext = (props) => {
|
|
15373
|
+
return {
|
|
15374
|
+
order: props.order ?? 'parallel',
|
|
15375
|
+
collapsed: props.collapsed === true,
|
|
15376
|
+
items: [],
|
|
15377
|
+
version: createSignal(0),
|
|
15378
|
+
};
|
|
15379
|
+
};
|
|
15380
|
+
/** @internal */
|
|
15381
|
+
const revealCanReveal = () => {
|
|
15382
|
+
const registration = _captures[0];
|
|
15383
|
+
if (registration === null) {
|
|
15384
|
+
return true;
|
|
15385
|
+
}
|
|
15386
|
+
const reveal = registration.reveal;
|
|
15387
|
+
const current = registration.item;
|
|
15388
|
+
const items = reveal.items;
|
|
15389
|
+
// `version` is monotonic; the branch keeps the subscription read from being dropped by minifiers.
|
|
15390
|
+
if (reveal.version.value < 0) {
|
|
15391
|
+
return false;
|
|
15392
|
+
}
|
|
15393
|
+
switch (reveal.order) {
|
|
15394
|
+
case 'together':
|
|
15395
|
+
for (let i = 0; i < items.length; i++) {
|
|
15396
|
+
if (items[i].boundary.pending.untrackedValue > 0) {
|
|
15397
|
+
return false;
|
|
15398
|
+
}
|
|
15399
|
+
}
|
|
15400
|
+
return true;
|
|
15401
|
+
case 'sequential':
|
|
15402
|
+
for (let i = 0; i < items.length; i++) {
|
|
15403
|
+
const item = items[i];
|
|
15404
|
+
if (item === current) {
|
|
15405
|
+
return true;
|
|
15406
|
+
}
|
|
15407
|
+
if (item.boundary.pending.untrackedValue > 0) {
|
|
15408
|
+
return false;
|
|
15409
|
+
}
|
|
15410
|
+
}
|
|
15411
|
+
return true;
|
|
15412
|
+
case 'reverse':
|
|
15413
|
+
for (let i = items.length - 1; i >= 0; i--) {
|
|
15414
|
+
const item = items[i];
|
|
15415
|
+
if (item === current) {
|
|
15416
|
+
return true;
|
|
15417
|
+
}
|
|
15418
|
+
if (item.boundary.pending.untrackedValue > 0) {
|
|
15419
|
+
return false;
|
|
15420
|
+
}
|
|
15421
|
+
}
|
|
15422
|
+
return true;
|
|
15423
|
+
default:
|
|
15424
|
+
return true;
|
|
15425
|
+
}
|
|
15426
|
+
};
|
|
15427
|
+
/** @internal */
|
|
15428
|
+
const revealCleanupTask = ({ cleanup }) => {
|
|
15429
|
+
const registration = _captures[0];
|
|
15430
|
+
cleanup(() => {
|
|
15431
|
+
// Keep the SSR registry intact so `reveal.items` serializes for resume.
|
|
15432
|
+
if (qTest ? isServerPlatform() : !isBrowser$1) {
|
|
15433
|
+
return;
|
|
15434
|
+
}
|
|
15435
|
+
const items = registration.reveal.items;
|
|
15436
|
+
const index = items.indexOf(registration.item);
|
|
15437
|
+
if (index !== -1) {
|
|
15438
|
+
items.splice(index, 1);
|
|
15439
|
+
registration.reveal.version.value++;
|
|
15440
|
+
}
|
|
15441
|
+
});
|
|
15442
|
+
};
|
|
15443
|
+
const useRevealBoundary = (boundary) => {
|
|
15444
|
+
const reveal = useContext(RevealContext, null);
|
|
15445
|
+
const registration = useConstant(() => {
|
|
15446
|
+
if (reveal === null) {
|
|
15447
|
+
return null;
|
|
15448
|
+
}
|
|
15449
|
+
const item = { boundary };
|
|
15450
|
+
reveal.items.push(item);
|
|
15451
|
+
return { reveal, item };
|
|
15452
|
+
});
|
|
15453
|
+
if (registration !== null) {
|
|
15454
|
+
useTaskQrl(/*#__PURE__*/ inlinedQrl(revealCleanupTask, '_reT', [registration]), {
|
|
15455
|
+
deferUpdates: false,
|
|
15456
|
+
});
|
|
15457
|
+
}
|
|
15458
|
+
return registration;
|
|
15459
|
+
};
|
|
15460
|
+
/** @internal */
|
|
15461
|
+
const revealCmp = (props) => {
|
|
15462
|
+
if (!__EXPERIMENTAL__.suspense) {
|
|
15463
|
+
throw new Error('Reveal is experimental and must be enabled with `experimental: ["suspense"]` in the `qwikVite` plugin.');
|
|
15464
|
+
}
|
|
15465
|
+
const reveal = useConstant(createRevealContext, props);
|
|
15466
|
+
useContextProvider(RevealContext, reveal);
|
|
15467
|
+
return /*#__PURE__*/ _jsxSorted(Slot, null, null, null, 0, 'u7_0');
|
|
15468
|
+
};
|
|
15469
|
+
/** @public @experimental */
|
|
15470
|
+
const Reveal = /*#__PURE__*/ componentQrl(
|
|
15471
|
+
/*#__PURE__*/ inlinedQrl(revealCmp, '_reC'));
|
|
15472
|
+
|
|
15473
|
+
const _hf0 = (p0, p1, p2, p3) => ({
|
|
15474
|
+
display: p1.value === 'fallback' &&
|
|
15475
|
+
p0.fallback != null &&
|
|
15476
|
+
p0.fallback !== false &&
|
|
15477
|
+
(p2 === null || p2.value || !p3.reveal.collapsed)
|
|
15478
|
+
? 'contents'
|
|
15479
|
+
: 'none',
|
|
15480
|
+
});
|
|
15481
|
+
const _hf0_str = '{display:p1.value==="fallback"&&p0.fallback!=null&&p0.fallback!==false&&(p2===null||p2.value||!p3.reveal.collapsed)?"contents":"none"}';
|
|
15482
|
+
const _hf1 = (p0, p1, p2) => ({
|
|
15483
|
+
display: (p2 === null || p2.value) && (p1.value === 'content' || p0.showStale) ? 'contents' : 'none',
|
|
15484
|
+
});
|
|
15485
|
+
const _hf1_str = '{display:(p2===null||p2.value)&&(p1.value==="content"||p0.showStale)?"contents":"none"}';
|
|
15486
|
+
/** @internal */
|
|
15487
|
+
const suspenseTask = ({ track, cleanup }) => {
|
|
15488
|
+
const cursorBoundary = _captures[0], props = _captures[1], state = _captures[2], revealRegistration = _captures[3];
|
|
15489
|
+
const pendingCount = track(cursorBoundary.pending);
|
|
15490
|
+
const isBrowserEnv = qTest ? !isServerPlatform() : isBrowser$1;
|
|
15491
|
+
if (revealRegistration !== null && isBrowserEnv) {
|
|
15492
|
+
revealRegistration.reveal.version.value++;
|
|
15493
|
+
}
|
|
15494
|
+
if (!isBrowserEnv || pendingCount === 0) {
|
|
15495
|
+
state.value = 'content';
|
|
15496
|
+
return;
|
|
15497
|
+
}
|
|
15498
|
+
const delayTimer = setTimeout(() => {
|
|
15499
|
+
if (cursorBoundary.pending.value > 0) {
|
|
15500
|
+
state.value = 'fallback';
|
|
15501
|
+
}
|
|
15502
|
+
}, props.delay ?? 0);
|
|
15503
|
+
cleanup(() => clearTimeout(delayTimer));
|
|
15504
|
+
};
|
|
15505
|
+
/** @internal */
|
|
15506
|
+
const suspenseCmp = (props) => {
|
|
15507
|
+
if (!__EXPERIMENTAL__.suspense) {
|
|
15508
|
+
throw new Error('Suspense is experimental and must be enabled with `experimental: ["suspense"]` in the `qwikVite` plugin.');
|
|
15509
|
+
}
|
|
15510
|
+
const state = useSignal('content');
|
|
15511
|
+
const cursorBoundary = useCursorBoundary();
|
|
15512
|
+
const revealRegistration = useRevealBoundary(cursorBoundary);
|
|
15513
|
+
const canReveal = useComputedQrl(
|
|
15514
|
+
/*#__PURE__*/ inlinedQrl(revealCanReveal, '_reR', [revealRegistration]));
|
|
15515
|
+
useTaskQrl(
|
|
15516
|
+
/*#__PURE__*/ inlinedQrl(suspenseTask, '_suT', [
|
|
15517
|
+
cursorBoundary,
|
|
15518
|
+
props,
|
|
15519
|
+
state,
|
|
15520
|
+
revealRegistration,
|
|
15521
|
+
]));
|
|
15522
|
+
return /*#__PURE__*/ _jsxSorted(Fragment, null, null, [
|
|
15523
|
+
/*#__PURE__*/ _jsxSorted('div', {
|
|
15524
|
+
style: _fnSignal(_hf0, [props, state, canReveal, revealRegistration], _hf0_str),
|
|
15525
|
+
}, null, _wrapProp(props, 'fallback'), 1, null),
|
|
15526
|
+
/*#__PURE__*/ _jsxSorted('div', null, {
|
|
15527
|
+
style: _fnSignal(_hf1, [props, state, canReveal], _hf1_str),
|
|
15528
|
+
},
|
|
15529
|
+
/*#__PURE__*/ _jsxSorted(Slot, {
|
|
15530
|
+
[QCursorBoundary]: cursorBoundary,
|
|
15531
|
+
}, null, null, 3, 'u6_0'), 1, null),
|
|
15532
|
+
], 1, 'u6_1');
|
|
15533
|
+
};
|
|
15534
|
+
/** @public @experimental */
|
|
15535
|
+
const Suspense = /*#__PURE__*/ componentQrl(
|
|
15536
|
+
/*#__PURE__*/ inlinedQrl(suspenseCmp, '_suC'));
|
|
15537
|
+
|
|
15187
15538
|
// keep this import from core/build so the cjs build works
|
|
15188
15539
|
/**
|
|
15189
15540
|
* @deprecated This is no longer needed as the preloading happens automatically in qrl-class.ts.
|
|
@@ -15192,7 +15543,7 @@ const Each = /*#__PURE__*/ componentQrl(
|
|
|
15192
15543
|
* @alpha
|
|
15193
15544
|
*/
|
|
15194
15545
|
const PrefetchServiceWorker = (opts) => {
|
|
15195
|
-
const isTest =
|
|
15546
|
+
const isTest = qTest;
|
|
15196
15547
|
if (isDev && !isTest) {
|
|
15197
15548
|
const props = {
|
|
15198
15549
|
dangerouslySetInnerHTML: '<!-- PrefetchServiceWorker is disabled in dev mode. -->',
|
|
@@ -15201,7 +15552,7 @@ const PrefetchServiceWorker = (opts) => {
|
|
|
15201
15552
|
}
|
|
15202
15553
|
// if an MFE app has a custom BASE_URL then this will be the correct value
|
|
15203
15554
|
// if you're not using MFE from another codebase then you want to override this value to your custom setup
|
|
15204
|
-
const baseUrl = import.meta.env
|
|
15555
|
+
const baseUrl = import.meta.env?.BASE_URL || '/';
|
|
15205
15556
|
const resolvedOpts = {
|
|
15206
15557
|
path: 'qwik-prefetch-service-worker.js',
|
|
15207
15558
|
...opts,
|
|
@@ -15279,5 +15630,5 @@ if (import.meta.hot) {
|
|
|
15279
15630
|
});
|
|
15280
15631
|
}
|
|
15281
15632
|
|
|
15282
|
-
export { $, Each, Fragment, NoSerializeSymbol, PrefetchGraph, PrefetchServiceWorker, RenderOnce, Resource, SSRComment, SSRRaw, SSRStream, SSRStreamBlock, SerializerSymbol, SkipRender, Slot, _CONST_PROPS, DomContainer as _DomContainer, _EFFECT_BACK_REF, EMPTY_ARRAY as _EMPTY_ARRAY, EMPTY_OBJ as _EMPTY_OBJ, _IMMUTABLE, _SharedContainer, SubscriptionData as _SubscriptionData, _UNINITIALIZED, _VAR_PROPS, _addProjection, _captures, _chk, createQRL as _createQRL, _deserialize, _dumpState, eachCmp as _eaC, eachCmpTask as _eaT, _executeSsrChores, _fnSignal, _getConstProps, _getContextContainer, _getContextEvent, _getContextHostElement, getDomContainer as _getDomContainer, _getQContainerElement, _getVarProps, _hasStoreEffects, _hmr, isJSXNode as _isJSXNode, isStore as _isStore, isStringifiable as _isStringifiable, isTask as _isTask, _jsxBranch, _jsxC, _jsxQ, _jsxS, _jsxSorted, _jsxSplit, mapApp_findIndx as _mapApp_findIndx, mapArray_get as _mapArray_get, mapArray_set as _mapArray_set, _noopQrl, _noopQrlDEV, preprocessState as _preprocessState, _qrlSync, qrlToString as _qrlToString, _regSymbol, _removeProjection, _res, _resolveContextWithoutSequentialScope, _restProps, _rsc, _run, _serialize, setEvent as _setEvent, _setProjectionTarget, scheduleTask as _task, _updateProjectionProps, _useHmr, _val, verifySerializable as _verifySerializable, vnode_ensureElementInflated as _vnode_ensureElementInflated, vnode_getAttrKeys as _vnode_getAttrKeys, vnode_getFirstChild as _vnode_getFirstChild, vnode_isMaterialized as _vnode_isMaterialized, vnode_isTextVNode as _vnode_isTextVNode, vnode_isVirtualVNode as _vnode_isVirtualVNode, vnode_toString as _vnode_toString, _waitUntilRendered, _walkJSX, _wrapProp, _wrapSignal, component$, componentQrl, createAsync$, createAsyncSignal as createAsyncQrl, createComputed$, createComputedSignal as createComputedQrl, createContextId, h as createElement, createSerializer$, createSerializerSignal as createSerializerQrl, createSignal, event$, eventQrl, forceStoreEffects, getDomContainer, getLocale, getPlatform, h, implicit$FirstArg, inlinedQrl, inlinedQrlDEV, isSignal, jsx, jsxDEV, jsxs, noSerialize, qrl, qrlDEV, render, setPlatform, sync$, untrack, unwrapStore, useAsync$, useAsyncQrl, useComputed$, useComputedQrl, useConstant, useContext, useContextProvider, useErrorBoundary, useId, useLexicalScope, useOn, useOnDocument, useOnWindow, useResource$, useResourceQrl, useSerializer$, useSerializerQrl, useServerData, useSignal, useStore, useStyles$, useStylesQrl, useStylesScoped$, useStylesScopedQrl, useTask$, useTaskQrl, useVisibleTask$, useVisibleTaskQrl, version, withLocale };
|
|
15633
|
+
export { $, Each, Fragment, NoSerializeSymbol, PrefetchGraph, PrefetchServiceWorker, RenderOnce, Resource, Reveal, SSRComment, SSRRaw, SSRStream, SSRStreamBlock, SerializerSymbol, SkipRender, Slot, Suspense, _CONST_PROPS, DomContainer as _DomContainer, _EFFECT_BACK_REF, EMPTY_ARRAY as _EMPTY_ARRAY, EMPTY_OBJ as _EMPTY_OBJ, _IMMUTABLE, _SharedContainer, SubscriptionData as _SubscriptionData, _UNINITIALIZED, _VAR_PROPS, _addProjection, _captures, _chk, _createDeserializeContainer, createQRL as _createQRL, _deserialize, _dumpState, eachCmp as _eaC, eachCmpTask as _eaT, _executeSsrChores, _fnSignal, getAsyncLocalStorage as _getAsyncLocalStorage, _getConstProps, _getContextContainer, _getContextEvent, _getContextHostElement, getDomContainer as _getDomContainer, _getQContainerElement, _getVarProps, _hasStoreEffects, _hmr, isJSXNode as _isJSXNode, isStore as _isStore, isStringifiable as _isStringifiable, isTask as _isTask, _jsxBranch, _jsxC, _jsxQ, _jsxS, _jsxSorted, _jsxSplit, mapApp_findIndx as _mapApp_findIndx, mapArray_get as _mapArray_get, mapArray_set as _mapArray_set, _noopQrl, _noopQrlDEV, preprocessState as _preprocessState, _qrlSync, qrlToString as _qrlToString, _qrlWithChunk, _qrlWithChunkDEV, revealCmp as _reC, revealCanReveal as _reR, revealCleanupTask as _reT, _regSymbol, _removeProjection, _res, _resolveContextWithoutSequentialScope, _restProps, _rsc, _run, _serialize, setEvent as _setEvent, _setProjectionTarget, suspenseCmp as _suC, suspenseTask as _suT, scheduleTask as _task, _updateProjectionProps, _useHmr, _val, verifySerializable as _verifySerializable, vnode_ensureElementInflated as _vnode_ensureElementInflated, vnode_getAttrKeys as _vnode_getAttrKeys, vnode_getElementName as _vnode_getElementName, vnode_getFirstChild as _vnode_getFirstChild, vnode_getProp as _vnode_getProp, vnode_getVNodeForChildNode as _vnode_getVNodeForChildNode, vnode_insertBefore as _vnode_insertBefore, vnode_isElementVNode as _vnode_isElementVNode, vnode_isMaterialized as _vnode_isMaterialized, vnode_isTextVNode as _vnode_isTextVNode, vnode_isVirtualVNode as _vnode_isVirtualVNode, vnode_newVirtual as _vnode_newVirtual, vnode_remove as _vnode_remove, vnode_setProp as _vnode_setProp, vnode_toString as _vnode_toString, _waitUntilRendered, _walkJSX, _wrapProp, _wrapSignal, component$, componentQrl, createAsync$, createAsyncSignal as createAsyncQrl, createComputed$, createComputedSignal as createComputedQrl, createContextId, h as createElement, createSerializer$, createSerializerSignal as createSerializerQrl, createSignal, event$, eventQrl, forceStoreEffects, getClientManifest, getDomContainer, getLocale, getPlatform, h, implicit$FirstArg, inlinedQrl, inlinedQrlDEV, isSignal, jsx, jsxDEV, jsxs, noSerialize, qrl, qrlDEV, render, setPlatform, sync$, untrack, unwrapStore, useAsync$, useAsyncQrl, useComputed$, useComputedQrl, useConstant, useContext, useContextProvider, useErrorBoundary, useId, useLexicalScope, useOn, useOnDocument, useOnWindow, useResource$, useResourceQrl, useSerializer$, useSerializerQrl, useServerData, useSignal, useStore, useStyles$, useStylesQrl, useStylesScoped$, useStylesScopedQrl, useTask$, useTaskQrl, useVisibleTask$, useVisibleTaskQrl, version, withLocale };
|
|
15283
15634
|
//# sourceMappingURL=core.mjs.map
|