@qwik.dev/core 2.0.0-beta.13 → 2.0.0-beta.15
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/package.json +1 -1
- package/dist/build/package.json +1 -1
- package/dist/cli.mjs +5633 -0
- package/dist/core-internal.d.ts +123 -65
- package/dist/core.min.mjs +1 -1
- package/dist/core.mjs +548 -246
- package/dist/core.mjs.map +1 -1
- package/dist/core.prod.mjs +349 -198
- package/dist/loader/index.mjs +2 -2
- package/dist/loader/package.json +1 -1
- package/dist/optimizer.mjs +1290 -1294
- package/dist/qwikloader.debug.js +43 -10
- package/dist/qwikloader.js +1 -1
- package/dist/server.mjs +5 -5
- package/dist/starters/adapters/aws-lambda/package.json +2 -1
- package/dist/starters/adapters/azure-swa/package.json +2 -1
- package/dist/starters/adapters/bun/package.json +2 -1
- package/dist/starters/adapters/cloud-run/package.json +2 -1
- package/dist/starters/adapters/cloudflare-pages/package.json +2 -1
- package/dist/starters/adapters/deno/package.json +2 -1
- package/dist/starters/adapters/express/package.json +2 -1
- package/dist/starters/adapters/fastify/package.json +2 -1
- package/dist/starters/adapters/firebase/package.json +2 -1
- package/dist/starters/adapters/netlify-edge/package.json +2 -1
- package/dist/starters/adapters/node-server/package.json +2 -1
- package/dist/starters/adapters/ssg/package.json +2 -1
- package/dist/starters/adapters/vercel-edge/package.json +2 -1
- package/dist/starters/features/csr/package.json +1 -1
- package/dist/starters/features/storybook/.storybook/tsconfig.json +0 -1
- package/dist/starters/features/styled-vanilla-extract/package.json +2 -1
- package/dist/testing/index.d.ts +8 -9
- package/dist/testing/index.mjs +483 -222
- package/dist/testing/package.json +1 -1
- package/package.json +14 -48
- package/{qwik-cli.cjs → qwik-cli.mjs} +1 -1
- package/dist/backpatch/index.cjs +0 -6
- package/dist/build/index.cjs +0 -35
- package/dist/build/index.cjs.map +0 -7
- package/dist/build/index.dev.cjs +0 -37
- package/dist/build/index.dev.cjs.map +0 -7
- package/dist/build/index.prod.cjs +0 -37
- package/dist/build/index.prod.cjs.map +0 -7
- package/dist/cli.cjs +0 -12956
- package/dist/core.cjs +0 -13036
- package/dist/core.cjs.map +0 -1
- package/dist/core.prod.cjs +0 -6377
- package/dist/insights/index.qwik.cjs +0 -1
- package/dist/insights/vite/index.cjs +0 -1
- package/dist/loader/index.cjs +0 -4
- package/dist/optimizer.cjs +0 -217
- package/dist/preloader.cjs +0 -266
- package/dist/server.cjs +0 -3294
- package/dist/testing/index.cjs +0 -36225
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.15-dev+920f1a4
|
|
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
|
|
@@ -14,7 +14,7 @@ import { p } from '@qwik.dev/core/preloader';
|
|
|
14
14
|
*
|
|
15
15
|
* @public
|
|
16
16
|
*/
|
|
17
|
-
const version = "2.0.0-beta.
|
|
17
|
+
const version = "2.0.0-beta.15-dev+920f1a4";
|
|
18
18
|
|
|
19
19
|
// same as isDev but separate so we can test
|
|
20
20
|
const qDev = globalThis.qDev !== false;
|
|
@@ -251,7 +251,6 @@ const ELEMENT_KEY = 'q:key';
|
|
|
251
251
|
const ELEMENT_PROPS = 'q:props';
|
|
252
252
|
const ELEMENT_SEQ = 'q:seq';
|
|
253
253
|
const ELEMENT_SEQ_IDX = 'q:seqIdx';
|
|
254
|
-
const Q_PREFIX = 'q:';
|
|
255
254
|
/** Non serializable markers - always begins with `:` character */
|
|
256
255
|
const NON_SERIALIZABLE_MARKER_PREFIX = ':';
|
|
257
256
|
const USE_ON_LOCAL = NON_SERIALIZABLE_MARKER_PREFIX + 'on';
|
|
@@ -916,7 +915,7 @@ const STORE_ALL_PROPS = Symbol('store.all');
|
|
|
916
915
|
class SignalImpl {
|
|
917
916
|
$untrackedValue$;
|
|
918
917
|
/** Store a list of effects which are dependent on this signal. */
|
|
919
|
-
$effects$ =
|
|
918
|
+
$effects$ = undefined;
|
|
920
919
|
$container$ = null;
|
|
921
920
|
$wrappedSignal$ = null;
|
|
922
921
|
constructor(container, value) {
|
|
@@ -928,7 +927,7 @@ class SignalImpl {
|
|
|
928
927
|
* remained the same object
|
|
929
928
|
*/
|
|
930
929
|
force() {
|
|
931
|
-
this.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */,
|
|
930
|
+
this.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */, undefined, this, this.$effects$);
|
|
932
931
|
}
|
|
933
932
|
get untrackedValue() {
|
|
934
933
|
return this.$untrackedValue$;
|
|
@@ -943,7 +942,7 @@ class SignalImpl {
|
|
|
943
942
|
set value(value) {
|
|
944
943
|
if (value !== this.$untrackedValue$) {
|
|
945
944
|
this.$untrackedValue$ = value;
|
|
946
|
-
this.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */,
|
|
945
|
+
this.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */, undefined, this, this.$effects$);
|
|
947
946
|
}
|
|
948
947
|
}
|
|
949
948
|
// prevent accidental use as value
|
|
@@ -1005,6 +1004,8 @@ const _CONST_PROPS = Symbol('CONST');
|
|
|
1005
1004
|
const _VAR_PROPS = Symbol('VAR');
|
|
1006
1005
|
/** @internal */
|
|
1007
1006
|
const _OWNER = Symbol('OWNER');
|
|
1007
|
+
/** @internal */
|
|
1008
|
+
const _PROPS_HANDLER = Symbol('PROPS_HANDLER');
|
|
1008
1009
|
/** @internal @deprecated v1 compat */
|
|
1009
1010
|
const _IMMUTABLE = Symbol('IMMUTABLE');
|
|
1010
1011
|
/** @internal */
|
|
@@ -1080,6 +1081,13 @@ const getEventDataFromHtmlAttribute = (htmlKey) => {
|
|
|
1080
1081
|
}
|
|
1081
1082
|
return ['document', htmlKey.substring(12)];
|
|
1082
1083
|
};
|
|
1084
|
+
const getScopedEventName = (scope, eventName) => {
|
|
1085
|
+
const suffix = ':' + eventName;
|
|
1086
|
+
return scope ? scope + suffix : suffix;
|
|
1087
|
+
};
|
|
1088
|
+
const getLoaderScopedEventName = (scope, scopedEvent) => {
|
|
1089
|
+
return scope ? '-' + scopedEvent : scopedEvent;
|
|
1090
|
+
};
|
|
1083
1091
|
|
|
1084
1092
|
/** @internal */
|
|
1085
1093
|
const EMPTY_ARRAY = [];
|
|
@@ -1093,6 +1101,8 @@ function createPropsProxy(owner) {
|
|
|
1093
1101
|
}
|
|
1094
1102
|
class PropsProxyHandler {
|
|
1095
1103
|
owner;
|
|
1104
|
+
$effects$ = undefined;
|
|
1105
|
+
$container$ = null;
|
|
1096
1106
|
constructor(owner) {
|
|
1097
1107
|
this.owner = owner;
|
|
1098
1108
|
}
|
|
@@ -1101,12 +1111,15 @@ class PropsProxyHandler {
|
|
|
1101
1111
|
if (prop === _CONST_PROPS) {
|
|
1102
1112
|
return this.owner.constProps;
|
|
1103
1113
|
}
|
|
1104
|
-
if (prop === _VAR_PROPS) {
|
|
1114
|
+
else if (prop === _VAR_PROPS) {
|
|
1105
1115
|
return this.owner.varProps;
|
|
1106
1116
|
}
|
|
1107
|
-
if (prop === _OWNER) {
|
|
1117
|
+
else if (prop === _OWNER) {
|
|
1108
1118
|
return this.owner;
|
|
1109
1119
|
}
|
|
1120
|
+
else if (prop === _PROPS_HANDLER) {
|
|
1121
|
+
return this;
|
|
1122
|
+
}
|
|
1110
1123
|
let value;
|
|
1111
1124
|
if (prop === 'children') {
|
|
1112
1125
|
value = this.owner.children;
|
|
@@ -1119,6 +1132,9 @@ class PropsProxyHandler {
|
|
|
1119
1132
|
}
|
|
1120
1133
|
}
|
|
1121
1134
|
value = directGetPropsProxyProp(this.owner, prop);
|
|
1135
|
+
if (prop in this.owner.varProps) {
|
|
1136
|
+
addPropsProxyEffect(this, prop);
|
|
1137
|
+
}
|
|
1122
1138
|
}
|
|
1123
1139
|
// a proxied value that the optimizer made
|
|
1124
1140
|
return value instanceof WrappedSignalImpl && value.$flags$ & 4 /* WrappedSignalFlags.UNWRAP */
|
|
@@ -1133,6 +1149,12 @@ class PropsProxyHandler {
|
|
|
1133
1149
|
else if (prop === 'children') {
|
|
1134
1150
|
this.owner.children = value;
|
|
1135
1151
|
}
|
|
1152
|
+
else if (prop === _CONST_PROPS) {
|
|
1153
|
+
this.owner.constProps = value;
|
|
1154
|
+
}
|
|
1155
|
+
else if (prop === _VAR_PROPS) {
|
|
1156
|
+
this.owner.varProps = value;
|
|
1157
|
+
}
|
|
1136
1158
|
else {
|
|
1137
1159
|
if (typeof prop === 'string' && typeof this.owner.type === 'string') {
|
|
1138
1160
|
const attr = jsxEventToHtmlAttribute(prop);
|
|
@@ -1141,28 +1163,27 @@ class PropsProxyHandler {
|
|
|
1141
1163
|
}
|
|
1142
1164
|
}
|
|
1143
1165
|
if (this.owner.constProps && prop in this.owner.constProps) {
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
this.owner.toSort = true;
|
|
1147
|
-
}
|
|
1148
|
-
this.owner.varProps[prop] = value;
|
|
1166
|
+
// delete the prop from the const props first
|
|
1167
|
+
delete this.owner.constProps[prop];
|
|
1149
1168
|
}
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
}
|
|
1158
|
-
}
|
|
1169
|
+
if (this.owner.varProps === EMPTY_OBJ) {
|
|
1170
|
+
this.owner.varProps = {};
|
|
1171
|
+
}
|
|
1172
|
+
else if (!(prop in this.owner.varProps)) {
|
|
1173
|
+
this.owner.toSort = true;
|
|
1174
|
+
}
|
|
1175
|
+
if (this.owner.varProps[prop] !== value) {
|
|
1159
1176
|
this.owner.varProps[prop] = value;
|
|
1177
|
+
triggerPropsProxyEffect(this, prop);
|
|
1160
1178
|
}
|
|
1161
1179
|
}
|
|
1162
1180
|
return true;
|
|
1163
1181
|
}
|
|
1164
1182
|
deleteProperty(_, prop) {
|
|
1165
1183
|
let didDelete = delete this.owner.varProps[prop];
|
|
1184
|
+
if (didDelete) {
|
|
1185
|
+
triggerPropsProxyEffect(this, prop);
|
|
1186
|
+
}
|
|
1166
1187
|
if (this.owner.constProps) {
|
|
1167
1188
|
didDelete = delete this.owner.constProps[prop] || didDelete;
|
|
1168
1189
|
}
|
|
@@ -1179,13 +1200,19 @@ class PropsProxyHandler {
|
|
|
1179
1200
|
else if (prop === _CONST_PROPS || prop === _VAR_PROPS) {
|
|
1180
1201
|
return true;
|
|
1181
1202
|
}
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
if (
|
|
1185
|
-
prop
|
|
1203
|
+
const inVarProps = prop in this.owner.varProps;
|
|
1204
|
+
if (typeof prop === 'string') {
|
|
1205
|
+
if (inVarProps) {
|
|
1206
|
+
addPropsProxyEffect(this, prop);
|
|
1207
|
+
}
|
|
1208
|
+
if (typeof this.owner.type === 'string') {
|
|
1209
|
+
const attr = jsxEventToHtmlAttribute(prop);
|
|
1210
|
+
if (attr) {
|
|
1211
|
+
prop = attr;
|
|
1212
|
+
}
|
|
1186
1213
|
}
|
|
1187
1214
|
}
|
|
1188
|
-
return
|
|
1215
|
+
return inVarProps || (this.owner.constProps ? prop in this.owner.constProps : false);
|
|
1189
1216
|
}
|
|
1190
1217
|
getOwnPropertyDescriptor(_, p) {
|
|
1191
1218
|
const value = p === 'children'
|
|
@@ -1214,6 +1241,34 @@ class PropsProxyHandler {
|
|
|
1214
1241
|
return out;
|
|
1215
1242
|
}
|
|
1216
1243
|
}
|
|
1244
|
+
const addPropsProxyEffect = (propsProxy, prop) => {
|
|
1245
|
+
// Lazily grab the container from the invoke context
|
|
1246
|
+
const ctx = tryGetInvokeContext();
|
|
1247
|
+
if (ctx) {
|
|
1248
|
+
if (propsProxy.$container$ === null) {
|
|
1249
|
+
if (ctx.$container$) {
|
|
1250
|
+
propsProxy.$container$ = ctx.$container$;
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
else {
|
|
1254
|
+
assertTrue(!ctx.$container$ || ctx.$container$ === propsProxy.$container$, 'Do not use props across containers');
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
const effectSubscriber = ctx?.$effectSubscriber$;
|
|
1258
|
+
if (effectSubscriber) {
|
|
1259
|
+
addStoreEffect(propsProxy.owner._proxy, prop, propsProxy, effectSubscriber);
|
|
1260
|
+
}
|
|
1261
|
+
};
|
|
1262
|
+
const triggerPropsProxyEffect = (propsProxy, prop) => {
|
|
1263
|
+
const effects = getEffects$1(propsProxy.$effects$, prop);
|
|
1264
|
+
if (effects) {
|
|
1265
|
+
propsProxy.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */, undefined, propsProxy, effects);
|
|
1266
|
+
}
|
|
1267
|
+
};
|
|
1268
|
+
function getEffects$1(effects, prop) {
|
|
1269
|
+
// TODO: Handle STORE_ALL_PROPS
|
|
1270
|
+
return effects?.get(prop);
|
|
1271
|
+
}
|
|
1217
1272
|
/**
|
|
1218
1273
|
* Instead of using PropsProxyHandler getter (which could create a component-level subscription).
|
|
1219
1274
|
* Use this function to get the props directly from a const or var props.
|
|
@@ -1245,6 +1300,19 @@ const isPropsProxy = (obj) => {
|
|
|
1245
1300
|
return obj && _VAR_PROPS in obj;
|
|
1246
1301
|
};
|
|
1247
1302
|
|
|
1303
|
+
const cleanupDestroyable = (destroyable) => {
|
|
1304
|
+
const destroy = destroyable.$destroy$;
|
|
1305
|
+
if (destroy) {
|
|
1306
|
+
destroyable.$destroy$ = null;
|
|
1307
|
+
try {
|
|
1308
|
+
destroy();
|
|
1309
|
+
}
|
|
1310
|
+
catch (err) {
|
|
1311
|
+
logError(err);
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
};
|
|
1315
|
+
|
|
1248
1316
|
function getSubscriber(effect, prop, data) {
|
|
1249
1317
|
if (!effect[_EFFECT_BACK_REF]) {
|
|
1250
1318
|
if (isServer && isSsrNode(effect)) {
|
|
@@ -1284,6 +1352,7 @@ const trackFn = (target, container) => (obj, prop) => {
|
|
|
1284
1352
|
return obj.value;
|
|
1285
1353
|
}
|
|
1286
1354
|
else if (isObject(obj) && isStore(obj)) {
|
|
1355
|
+
// TODO: handle props proxy
|
|
1287
1356
|
// track whole store
|
|
1288
1357
|
addStoreEffect(getStoreTarget(obj), STORE_ALL_PROPS, getStoreHandler(obj), ctx.$effectSubscriber$);
|
|
1289
1358
|
return obj;
|
|
@@ -1301,14 +1370,14 @@ const cleanupFn = (target, handleError) => {
|
|
|
1301
1370
|
cleanupFns = [];
|
|
1302
1371
|
target.$destroy$ = noSerialize(() => {
|
|
1303
1372
|
target.$destroy$ = null;
|
|
1304
|
-
|
|
1373
|
+
for (const fn of cleanupFns) {
|
|
1305
1374
|
try {
|
|
1306
1375
|
fn();
|
|
1307
1376
|
}
|
|
1308
1377
|
catch (err) {
|
|
1309
1378
|
handleError(err);
|
|
1310
1379
|
}
|
|
1311
|
-
}
|
|
1380
|
+
}
|
|
1312
1381
|
});
|
|
1313
1382
|
}
|
|
1314
1383
|
cleanupFns.push(fn);
|
|
@@ -1334,7 +1403,7 @@ class ComputedSignalImpl extends SignalImpl {
|
|
|
1334
1403
|
*/
|
|
1335
1404
|
$computeQrl$;
|
|
1336
1405
|
$flags$;
|
|
1337
|
-
[_EFFECT_BACK_REF] =
|
|
1406
|
+
[_EFFECT_BACK_REF] = undefined;
|
|
1338
1407
|
constructor(container, fn,
|
|
1339
1408
|
// We need a separate flag to know when the computation needs running because
|
|
1340
1409
|
// we need the old value to know if effects need running after computation
|
|
@@ -1348,7 +1417,7 @@ class ComputedSignalImpl extends SignalImpl {
|
|
|
1348
1417
|
}
|
|
1349
1418
|
invalidate() {
|
|
1350
1419
|
this.$flags$ |= 1 /* SignalFlags.INVALID */;
|
|
1351
|
-
this.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */,
|
|
1420
|
+
this.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */, undefined, this, this.$effects$);
|
|
1352
1421
|
}
|
|
1353
1422
|
/**
|
|
1354
1423
|
* Use this to force running subscribers, for example when the calculated value has mutated but
|
|
@@ -1416,12 +1485,13 @@ class ComputedSignalImpl extends SignalImpl {
|
|
|
1416
1485
|
*/
|
|
1417
1486
|
class AsyncComputedSignalImpl extends ComputedSignalImpl {
|
|
1418
1487
|
$untrackedLoading$ = false;
|
|
1419
|
-
$untrackedError$ =
|
|
1420
|
-
$loadingEffects$ =
|
|
1421
|
-
$errorEffects$ =
|
|
1488
|
+
$untrackedError$ = undefined;
|
|
1489
|
+
$loadingEffects$ = undefined;
|
|
1490
|
+
$errorEffects$ = undefined;
|
|
1422
1491
|
$destroy$;
|
|
1423
1492
|
$promiseValue$ = NEEDS_COMPUTATION;
|
|
1424
|
-
|
|
1493
|
+
$promise$ = null;
|
|
1494
|
+
[_EFFECT_BACK_REF] = undefined;
|
|
1425
1495
|
constructor(container, fn, flags = 1 /* SignalFlags.INVALID */) {
|
|
1426
1496
|
super(container, fn, flags);
|
|
1427
1497
|
}
|
|
@@ -1435,7 +1505,7 @@ class AsyncComputedSignalImpl extends ComputedSignalImpl {
|
|
|
1435
1505
|
set untrackedLoading(value) {
|
|
1436
1506
|
if (value !== this.$untrackedLoading$) {
|
|
1437
1507
|
this.$untrackedLoading$ = value;
|
|
1438
|
-
this.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */,
|
|
1508
|
+
this.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */, undefined, this, this.$loadingEffects$);
|
|
1439
1509
|
}
|
|
1440
1510
|
}
|
|
1441
1511
|
get untrackedLoading() {
|
|
@@ -1448,7 +1518,7 @@ class AsyncComputedSignalImpl extends ComputedSignalImpl {
|
|
|
1448
1518
|
set untrackedError(value) {
|
|
1449
1519
|
if (value !== this.$untrackedError$) {
|
|
1450
1520
|
this.$untrackedError$ = value;
|
|
1451
|
-
this.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */,
|
|
1521
|
+
this.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */, undefined, this, this.$errorEffects$);
|
|
1452
1522
|
}
|
|
1453
1523
|
}
|
|
1454
1524
|
get untrackedError() {
|
|
@@ -1456,9 +1526,12 @@ class AsyncComputedSignalImpl extends ComputedSignalImpl {
|
|
|
1456
1526
|
}
|
|
1457
1527
|
invalidate() {
|
|
1458
1528
|
super.invalidate();
|
|
1459
|
-
|
|
1529
|
+
// clear the promise, we need to get function again
|
|
1530
|
+
this.$promise$ = null;
|
|
1460
1531
|
}
|
|
1461
|
-
async
|
|
1532
|
+
async promise() {
|
|
1533
|
+
// make sure we get a new promise during the next computation
|
|
1534
|
+
this.$promise$ = null;
|
|
1462
1535
|
await retryOnPromise(() => this.$computeIfNeeded$());
|
|
1463
1536
|
return this.$untrackedValue$;
|
|
1464
1537
|
}
|
|
@@ -1466,34 +1539,69 @@ class AsyncComputedSignalImpl extends ComputedSignalImpl {
|
|
|
1466
1539
|
if (!(this.$flags$ & 1 /* SignalFlags.INVALID */)) {
|
|
1467
1540
|
return;
|
|
1468
1541
|
}
|
|
1469
|
-
const
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1542
|
+
const untrackedValue =
|
|
1543
|
+
// first time
|
|
1544
|
+
this.$promiseValue$ === NEEDS_COMPUTATION ||
|
|
1545
|
+
// or after invalidation
|
|
1546
|
+
this.$promise$ === null
|
|
1547
|
+
? this.$promiseComputation$()
|
|
1475
1548
|
: this.$promiseValue$;
|
|
1476
1549
|
if (isPromise(untrackedValue)) {
|
|
1550
|
+
const isFirstComputation = this.$promiseValue$ === NEEDS_COMPUTATION;
|
|
1477
1551
|
this.untrackedLoading = true;
|
|
1478
|
-
this.untrackedError =
|
|
1479
|
-
|
|
1552
|
+
this.untrackedError = undefined;
|
|
1553
|
+
if (this.$promiseValue$ !== NEEDS_COMPUTATION) {
|
|
1554
|
+
// skip cleanup after resuming
|
|
1555
|
+
cleanupDestroyable(this);
|
|
1556
|
+
}
|
|
1557
|
+
const promise = untrackedValue
|
|
1480
1558
|
.then((promiseValue) => {
|
|
1481
1559
|
this.$promiseValue$ = promiseValue;
|
|
1482
1560
|
this.untrackedLoading = false;
|
|
1483
|
-
this.untrackedError =
|
|
1561
|
+
this.untrackedError = undefined;
|
|
1562
|
+
if (this.setValue(promiseValue)) {
|
|
1563
|
+
scheduleEffects(this.$container$, this, this.$effects$);
|
|
1564
|
+
}
|
|
1484
1565
|
})
|
|
1485
1566
|
.catch((err) => {
|
|
1567
|
+
if (isPromise(err)) {
|
|
1568
|
+
// ignore promise errors, they will be handled
|
|
1569
|
+
return;
|
|
1570
|
+
}
|
|
1486
1571
|
this.$promiseValue$ = err;
|
|
1487
1572
|
this.untrackedLoading = false;
|
|
1488
1573
|
this.untrackedError = err;
|
|
1489
1574
|
});
|
|
1575
|
+
if (isFirstComputation) {
|
|
1576
|
+
// we want to throw only the first time
|
|
1577
|
+
// the next time we will return stale value
|
|
1578
|
+
throw promise;
|
|
1579
|
+
}
|
|
1580
|
+
else {
|
|
1581
|
+
// Return the promise so the scheduler can track it as a running chore
|
|
1582
|
+
return promise;
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1585
|
+
else {
|
|
1586
|
+
this.setValue(untrackedValue);
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
async $promiseComputation$() {
|
|
1590
|
+
if (!this.$promise$) {
|
|
1591
|
+
const [cleanup] = cleanupFn(this, (err) => this.$container$?.handleError(err, null));
|
|
1592
|
+
this.$promise$ = this.$computeQrl$.getFn()({
|
|
1593
|
+
track: trackFn(this, this.$container$),
|
|
1594
|
+
cleanup,
|
|
1595
|
+
});
|
|
1490
1596
|
}
|
|
1491
|
-
this.$
|
|
1597
|
+
return this.$promise$;
|
|
1598
|
+
}
|
|
1599
|
+
setValue(value) {
|
|
1492
1600
|
this.$flags$ &= -2 /* SignalFlags.INVALID */;
|
|
1493
|
-
const didChange =
|
|
1601
|
+
const didChange = value !== this.$untrackedValue$;
|
|
1494
1602
|
if (didChange) {
|
|
1603
|
+
this.$untrackedValue$ = value;
|
|
1495
1604
|
this.$flags$ |= 2 /* SignalFlags.RUN_EFFECTS */;
|
|
1496
|
-
this.$untrackedValue$ = untrackedValue;
|
|
1497
1605
|
}
|
|
1498
1606
|
return didChange;
|
|
1499
1607
|
}
|
|
@@ -1683,25 +1791,32 @@ const _wrapProp = (...args) => {
|
|
|
1683
1791
|
}
|
|
1684
1792
|
if (isPropsProxy(obj)) {
|
|
1685
1793
|
const constProps = obj[_CONST_PROPS];
|
|
1794
|
+
const varProps = obj[_VAR_PROPS];
|
|
1686
1795
|
if (constProps && prop in constProps) {
|
|
1687
1796
|
// Const props don't need wrapping
|
|
1688
1797
|
return constProps[prop];
|
|
1689
1798
|
}
|
|
1799
|
+
else if (prop in varProps) {
|
|
1800
|
+
const value = varProps[prop];
|
|
1801
|
+
return wrapIfNotSignal(value, args);
|
|
1802
|
+
}
|
|
1690
1803
|
}
|
|
1691
1804
|
else {
|
|
1692
1805
|
const target = getStoreTarget(obj);
|
|
1693
1806
|
if (target) {
|
|
1694
1807
|
const value = target[prop];
|
|
1695
|
-
|
|
1696
|
-
? // If the value is already a signal, we don't need to wrap it again
|
|
1697
|
-
value
|
|
1698
|
-
: getWrapped(args);
|
|
1699
|
-
return wrappedValue;
|
|
1808
|
+
return wrapIfNotSignal(value, args);
|
|
1700
1809
|
}
|
|
1701
1810
|
}
|
|
1702
1811
|
// the object is not reactive, so we can just return the value
|
|
1703
1812
|
return obj[prop];
|
|
1704
1813
|
};
|
|
1814
|
+
const wrapIfNotSignal = (value, args) => {
|
|
1815
|
+
return (isSignal(value)
|
|
1816
|
+
? // If the value is already a signal, we don't need to wrap it again
|
|
1817
|
+
value
|
|
1818
|
+
: getWrapped(args));
|
|
1819
|
+
};
|
|
1705
1820
|
/** @internal @deprecated v1 compat */
|
|
1706
1821
|
const _wrapSignal = (obj, prop) => {
|
|
1707
1822
|
const r = _wrapProp(obj, prop);
|
|
@@ -1716,8 +1831,8 @@ class WrappedSignalImpl extends SignalImpl {
|
|
|
1716
1831
|
$func$;
|
|
1717
1832
|
$funcStr$;
|
|
1718
1833
|
$flags$;
|
|
1719
|
-
$hostElement$ =
|
|
1720
|
-
[_EFFECT_BACK_REF] =
|
|
1834
|
+
$hostElement$ = undefined;
|
|
1835
|
+
[_EFFECT_BACK_REF] = undefined;
|
|
1721
1836
|
constructor(container, fn, args, fnStr,
|
|
1722
1837
|
// We need a separate flag to know when the computation needs running because
|
|
1723
1838
|
// we need the old value to know if effects need running after computation
|
|
@@ -1793,7 +1908,7 @@ class WrappedSignalImpl extends SignalImpl {
|
|
|
1793
1908
|
|
|
1794
1909
|
/** Class for back reference to the EffectSubscription */
|
|
1795
1910
|
let BackRef$1 = class BackRef {
|
|
1796
|
-
[_EFFECT_BACK_REF] =
|
|
1911
|
+
[_EFFECT_BACK_REF] = undefined;
|
|
1797
1912
|
};
|
|
1798
1913
|
function clearAllEffects(container, consumer) {
|
|
1799
1914
|
if (vnode_isVNode(consumer) && vnode_isElementVNode(consumer)) {
|
|
@@ -1806,6 +1921,7 @@ function clearAllEffects(container, consumer) {
|
|
|
1806
1921
|
for (const [, effect] of effects) {
|
|
1807
1922
|
clearEffectSubscription(container, effect);
|
|
1808
1923
|
}
|
|
1924
|
+
effects.clear();
|
|
1809
1925
|
}
|
|
1810
1926
|
function clearEffectSubscription(container, effect) {
|
|
1811
1927
|
const backRefs = effect[2 /* EffectSubscriptionProp.BACK_REF */];
|
|
@@ -1819,12 +1935,17 @@ function clearEffectSubscription(container, effect) {
|
|
|
1819
1935
|
else if (producer instanceof AsyncComputedSignalImpl) {
|
|
1820
1936
|
clearAsyncComputedSignal(producer, effect);
|
|
1821
1937
|
}
|
|
1938
|
+
else if (isPropsProxy(producer)) {
|
|
1939
|
+
const propsHandler = producer[_PROPS_HANDLER];
|
|
1940
|
+
clearStoreOrProps(propsHandler, effect);
|
|
1941
|
+
}
|
|
1822
1942
|
else if (container.$storeProxyMap$.has(producer)) {
|
|
1823
1943
|
const target = container.$storeProxyMap$.get(producer);
|
|
1824
1944
|
const storeHandler = getStoreHandler(target);
|
|
1825
|
-
|
|
1945
|
+
clearStoreOrProps(storeHandler, effect);
|
|
1826
1946
|
}
|
|
1827
1947
|
}
|
|
1948
|
+
backRefs.clear();
|
|
1828
1949
|
}
|
|
1829
1950
|
function clearSignal(container, producer, effect) {
|
|
1830
1951
|
const effects = producer.$effects$;
|
|
@@ -1832,7 +1953,7 @@ function clearSignal(container, producer, effect) {
|
|
|
1832
1953
|
effects.delete(effect);
|
|
1833
1954
|
}
|
|
1834
1955
|
if (producer instanceof WrappedSignalImpl) {
|
|
1835
|
-
producer.$hostElement$ =
|
|
1956
|
+
producer.$hostElement$ = undefined;
|
|
1836
1957
|
clearAllEffects(container, producer);
|
|
1837
1958
|
}
|
|
1838
1959
|
}
|
|
@@ -1846,12 +1967,15 @@ function clearAsyncComputedSignal(producer, effect) {
|
|
|
1846
1967
|
pendingEffects.delete(effect);
|
|
1847
1968
|
}
|
|
1848
1969
|
}
|
|
1849
|
-
function
|
|
1970
|
+
function clearStoreOrProps(producer, effect) {
|
|
1850
1971
|
const effects = producer?.$effects$;
|
|
1851
1972
|
if (effects) {
|
|
1852
|
-
for (const propEffects of effects.
|
|
1973
|
+
for (const [prop, propEffects] of effects.entries()) {
|
|
1853
1974
|
if (propEffects.has(effect)) {
|
|
1854
1975
|
propEffects.delete(effect);
|
|
1976
|
+
if (propEffects.size === 0) {
|
|
1977
|
+
effects.delete(prop);
|
|
1978
|
+
}
|
|
1855
1979
|
}
|
|
1856
1980
|
}
|
|
1857
1981
|
}
|
|
@@ -2663,23 +2787,22 @@ const vnode_applyJournal = (journal) => {
|
|
|
2663
2787
|
key = 'class';
|
|
2664
2788
|
}
|
|
2665
2789
|
const value = journal[idx++];
|
|
2790
|
+
const shouldRemove = value == null || value === false;
|
|
2666
2791
|
if (isBooleanAttr(element, key)) {
|
|
2667
2792
|
element[key] = parseBoolean(value);
|
|
2668
2793
|
}
|
|
2669
|
-
else if (key === 'value' && key in element) {
|
|
2670
|
-
element.value = String(value);
|
|
2671
|
-
}
|
|
2672
2794
|
else if (key === dangerouslySetInnerHTML) {
|
|
2673
2795
|
element.innerHTML = value;
|
|
2674
2796
|
element.setAttribute(QContainerAttr, "html" /* QContainerValue.HTML */);
|
|
2675
2797
|
}
|
|
2798
|
+
else if (shouldRemove) {
|
|
2799
|
+
element.removeAttribute(key);
|
|
2800
|
+
}
|
|
2801
|
+
else if (key === 'value' && key in element) {
|
|
2802
|
+
element.value = String(value);
|
|
2803
|
+
}
|
|
2676
2804
|
else {
|
|
2677
|
-
|
|
2678
|
-
element.removeAttribute(key);
|
|
2679
|
-
}
|
|
2680
|
-
else {
|
|
2681
|
-
element.setAttribute(key, String(value));
|
|
2682
|
-
}
|
|
2805
|
+
element.setAttribute(key, String(value));
|
|
2683
2806
|
}
|
|
2684
2807
|
break;
|
|
2685
2808
|
case 3 /* VNodeJournalOpCode.HoistStyles */:
|
|
@@ -3419,6 +3542,7 @@ function materializeFromVNodeData(vParent, vData, element, child) {
|
|
|
3419
3542
|
const nodeIsElement = isElement(node);
|
|
3420
3543
|
return !nodeIsElement || (nodeIsElement && shouldSkipElement(node));
|
|
3421
3544
|
};
|
|
3545
|
+
let components = null;
|
|
3422
3546
|
processVNodeData$1(vData, (peek, consumeValue, consume, getChar, nextToConsumeIdx) => {
|
|
3423
3547
|
if (isNumber(peek())) {
|
|
3424
3548
|
// Element counts get encoded as numbers.
|
|
@@ -3445,6 +3569,7 @@ function materializeFromVNodeData(vParent, vData, element, child) {
|
|
|
3445
3569
|
vParent.setAttr(QScopedStyle, consumeValue(), null);
|
|
3446
3570
|
}
|
|
3447
3571
|
else if (peek() === VNodeDataChar.RENDER_FN) {
|
|
3572
|
+
(components ||= []).push(vParent);
|
|
3448
3573
|
vParent.setAttr(OnRenderProp, consumeValue(), null);
|
|
3449
3574
|
}
|
|
3450
3575
|
else if (peek() === VNodeDataChar.ID) {
|
|
@@ -3540,6 +3665,15 @@ function materializeFromVNodeData(vParent, vData, element, child) {
|
|
|
3540
3665
|
// Text nodes get encoded as alphanumeric characters.
|
|
3541
3666
|
}
|
|
3542
3667
|
});
|
|
3668
|
+
if (components) {
|
|
3669
|
+
if (!container) {
|
|
3670
|
+
container = getDomContainer(element);
|
|
3671
|
+
}
|
|
3672
|
+
for (const component of components) {
|
|
3673
|
+
container.ensureProjectionResolved(component);
|
|
3674
|
+
}
|
|
3675
|
+
components = null;
|
|
3676
|
+
}
|
|
3543
3677
|
vParent.lastChild = vLast;
|
|
3544
3678
|
return vFirst;
|
|
3545
3679
|
}
|
|
@@ -4290,14 +4424,14 @@ const _jsxSplit = (type, varProps, constProps, children, flags, key, dev) => {
|
|
|
4290
4424
|
for (const k in varProps) {
|
|
4291
4425
|
if (k === 'children') {
|
|
4292
4426
|
children ||= varProps.children;
|
|
4293
|
-
varProps.children
|
|
4427
|
+
delete varProps.children;
|
|
4294
4428
|
}
|
|
4295
4429
|
else if (k === 'key') {
|
|
4296
4430
|
key ||= varProps.key;
|
|
4297
|
-
varProps.key
|
|
4431
|
+
delete varProps.key;
|
|
4298
4432
|
}
|
|
4299
4433
|
else if (constProps && k in constProps) {
|
|
4300
|
-
varProps[k]
|
|
4434
|
+
delete varProps[k];
|
|
4301
4435
|
}
|
|
4302
4436
|
}
|
|
4303
4437
|
}
|
|
@@ -4370,14 +4504,17 @@ const RenderOnce = (props, key) => {
|
|
|
4370
4504
|
};
|
|
4371
4505
|
|
|
4372
4506
|
/** @internal */
|
|
4373
|
-
const useTaskQrl = (qrl) => {
|
|
4507
|
+
const useTaskQrl = (qrl, opts) => {
|
|
4374
4508
|
const { val, set, iCtx, i } = useSequentialScope();
|
|
4375
4509
|
if (val) {
|
|
4376
4510
|
return;
|
|
4377
4511
|
}
|
|
4378
4512
|
assertQrl(qrl);
|
|
4379
4513
|
set(1);
|
|
4380
|
-
const
|
|
4514
|
+
const taskFlags =
|
|
4515
|
+
// enabled by default
|
|
4516
|
+
opts?.deferUpdates === false ? 0 : 16 /* TaskFlags.RENDER_BLOCKING */;
|
|
4517
|
+
const task = new Task(8 /* TaskFlags.DIRTY */ | 2 /* TaskFlags.TASK */ | taskFlags, i, iCtx.$hostElement$, qrl, undefined, null);
|
|
4381
4518
|
// In V2 we add the task to the sequential scope. We need to do this
|
|
4382
4519
|
// in order to be able to retrieve it later when the parent element is
|
|
4383
4520
|
// deleted and we need to be able to release the task subscriptions.
|
|
@@ -4390,7 +4527,7 @@ const useTaskQrl = (qrl) => {
|
|
|
4390
4527
|
};
|
|
4391
4528
|
const runTask = (task, container, host) => {
|
|
4392
4529
|
task.$flags$ &= -9 /* TaskFlags.DIRTY */;
|
|
4393
|
-
|
|
4530
|
+
cleanupDestroyable(task);
|
|
4394
4531
|
const iCtx = newInvokeContext(container.$locale$, host, undefined, TaskEvent);
|
|
4395
4532
|
iCtx.$container$ = container;
|
|
4396
4533
|
const taskFn = task.$qrl$.getFn(iCtx, () => clearAllEffects(container, task));
|
|
@@ -4407,18 +4544,6 @@ const runTask = (task, container, host) => {
|
|
|
4407
4544
|
}
|
|
4408
4545
|
});
|
|
4409
4546
|
};
|
|
4410
|
-
const cleanupTask = (task) => {
|
|
4411
|
-
const destroy = task.$destroy$;
|
|
4412
|
-
if (destroy) {
|
|
4413
|
-
task.$destroy$ = null;
|
|
4414
|
-
try {
|
|
4415
|
-
destroy();
|
|
4416
|
-
}
|
|
4417
|
-
catch (err) {
|
|
4418
|
-
logError(err);
|
|
4419
|
-
}
|
|
4420
|
-
}
|
|
4421
|
-
};
|
|
4422
4547
|
class Task extends BackRef$1 {
|
|
4423
4548
|
$flags$;
|
|
4424
4549
|
$index$;
|
|
@@ -4587,7 +4712,7 @@ const isResourceReturn = (obj) => {
|
|
|
4587
4712
|
};
|
|
4588
4713
|
const runResource = (task, container, host) => {
|
|
4589
4714
|
task.$flags$ &= -9 /* TaskFlags.DIRTY */;
|
|
4590
|
-
|
|
4715
|
+
cleanupDestroyable(task);
|
|
4591
4716
|
const iCtx = newInvokeContext(container.$locale$, host, undefined, ResourceEvent);
|
|
4592
4717
|
iCtx.$container$ = container;
|
|
4593
4718
|
const taskFn = task.$qrl$.getFn(iCtx, () => clearAllEffects(container, task));
|
|
@@ -4676,7 +4801,7 @@ const runResource = (task, container, host) => {
|
|
|
4676
4801
|
promise,
|
|
4677
4802
|
delay(timeout).then(() => {
|
|
4678
4803
|
if (setState(false, new Error('timeout'))) {
|
|
4679
|
-
|
|
4804
|
+
cleanupDestroyable(task);
|
|
4680
4805
|
}
|
|
4681
4806
|
}),
|
|
4682
4807
|
]);
|
|
@@ -4814,16 +4939,17 @@ function qrlToString(serializationContext, value, raw) {
|
|
|
4814
4939
|
// TODO test that provided stringified fn is used
|
|
4815
4940
|
symbol = String(serializationContext.$addSyncFn$(null, 0, fn));
|
|
4816
4941
|
}
|
|
4817
|
-
|
|
4942
|
+
let capturedIds = null;
|
|
4943
|
+
if (Array.isArray(value.$captureRef$) && value.$captureRef$.length > 0) {
|
|
4818
4944
|
// We refer by id so every capture needs to be a root
|
|
4819
|
-
|
|
4945
|
+
capturedIds = value.$captureRef$.map((ref) => `${serializationContext.$addRoot$(ref)}`);
|
|
4820
4946
|
}
|
|
4821
4947
|
if (raw) {
|
|
4822
|
-
return [chunk, symbol,
|
|
4948
|
+
return [chunk, symbol, capturedIds];
|
|
4823
4949
|
}
|
|
4824
4950
|
let qrlStringInline = `${chunk}#${symbol}`;
|
|
4825
|
-
if (
|
|
4826
|
-
qrlStringInline += `[${
|
|
4951
|
+
if (capturedIds && capturedIds.length > 0) {
|
|
4952
|
+
qrlStringInline += `[${capturedIds.join(' ')}]`;
|
|
4827
4953
|
}
|
|
4828
4954
|
return qrlStringInline;
|
|
4829
4955
|
}
|
|
@@ -5664,6 +5790,7 @@ const vnode_diff = (container, jsxNode, vStartNode, scopedStyleIdPrefix) => {
|
|
|
5664
5790
|
*/
|
|
5665
5791
|
const stack = [];
|
|
5666
5792
|
const asyncQueue = [];
|
|
5793
|
+
const asyncAttributePromises = [];
|
|
5667
5794
|
////////////////////////////////
|
|
5668
5795
|
//// Traverse state variables
|
|
5669
5796
|
////////////////////////////////
|
|
@@ -5730,8 +5857,9 @@ const vnode_diff = (container, jsxNode, vStartNode, scopedStyleIdPrefix) => {
|
|
|
5730
5857
|
else if (isSignal(jsxValue)) {
|
|
5731
5858
|
expectVirtual("S" /* VirtualType.WrappedSignal */, null);
|
|
5732
5859
|
const unwrappedSignal = jsxValue instanceof WrappedSignalImpl ? jsxValue.$unwrapIfSignal$() : jsxValue;
|
|
5733
|
-
const
|
|
5734
|
-
|
|
5860
|
+
const hasUnwrappedSignal = vCurrent?.[_EFFECT_BACK_REF]
|
|
5861
|
+
?.get("." /* EffectProperty.VNODE */)?.[2 /* EffectSubscriptionProp.BACK_REF */]?.has(unwrappedSignal);
|
|
5862
|
+
if (!hasUnwrappedSignal) {
|
|
5735
5863
|
const vHost = (vNewNode || vCurrent);
|
|
5736
5864
|
descend(resolveSignalAndDescend(() => trackSignalAndAssignHost(unwrappedSignal, vHost, "." /* EffectProperty.VNODE */, container)), true);
|
|
5737
5865
|
}
|
|
@@ -6077,6 +6205,14 @@ const vnode_diff = (container, jsxNode, vStartNode, scopedStyleIdPrefix) => {
|
|
|
6077
6205
|
diff(jsxNode, vHostNode);
|
|
6078
6206
|
}
|
|
6079
6207
|
}
|
|
6208
|
+
// Wait for all async attribute promises to complete, then check for more work
|
|
6209
|
+
if (asyncAttributePromises.length) {
|
|
6210
|
+
const promises = asyncAttributePromises.splice(0);
|
|
6211
|
+
return Promise.all(promises).then(() => {
|
|
6212
|
+
// After attributes are set, check if there's more work in the queue
|
|
6213
|
+
return drainAsyncQueue();
|
|
6214
|
+
});
|
|
6215
|
+
}
|
|
6080
6216
|
}
|
|
6081
6217
|
function expectNoChildren() {
|
|
6082
6218
|
const vFirstChild = vCurrent && vnode_getFirstChild(vCurrent);
|
|
@@ -6128,11 +6264,11 @@ const vnode_diff = (container, jsxNode, vStartNode, scopedStyleIdPrefix) => {
|
|
|
6128
6264
|
// only svg elements can have namespace attributes
|
|
6129
6265
|
const namespace = getAttributeNamespace(key);
|
|
6130
6266
|
if (namespace) {
|
|
6131
|
-
element.setAttributeNS(namespace, key,
|
|
6267
|
+
element.setAttributeNS(namespace, key, value);
|
|
6132
6268
|
return;
|
|
6133
6269
|
}
|
|
6134
6270
|
}
|
|
6135
|
-
element.setAttribute(key,
|
|
6271
|
+
element.setAttribute(key, value);
|
|
6136
6272
|
}
|
|
6137
6273
|
}
|
|
6138
6274
|
const { constProps } = jsx;
|
|
@@ -6146,15 +6282,17 @@ const vnode_diff = (container, jsxNode, vStartNode, scopedStyleIdPrefix) => {
|
|
|
6146
6282
|
if (isHtmlAttributeAnEventName(key)) {
|
|
6147
6283
|
const data = getEventDataFromHtmlAttribute(key);
|
|
6148
6284
|
if (data) {
|
|
6149
|
-
const scope = data
|
|
6150
|
-
const
|
|
6285
|
+
const [scope, eventName] = data;
|
|
6286
|
+
const scopedEvent = getScopedEventName(scope, eventName);
|
|
6287
|
+
const loaderScopedEvent = getLoaderScopedEventName(scope, scopedEvent);
|
|
6151
6288
|
if (eventName) {
|
|
6152
|
-
vNewNode.setProp(HANDLER_PREFIX + ':' +
|
|
6289
|
+
vNewNode.setProp(HANDLER_PREFIX + ':' + scopedEvent, value);
|
|
6153
6290
|
if (scope) {
|
|
6154
6291
|
// window and document need attrs so qwik loader can find them
|
|
6155
6292
|
vNewNode.setAttr(key, '', journal);
|
|
6156
6293
|
}
|
|
6157
|
-
|
|
6294
|
+
// register an event for qwik loader (window/document prefixed with '-')
|
|
6295
|
+
registerQwikLoaderEvent(loaderScopedEvent);
|
|
6158
6296
|
}
|
|
6159
6297
|
}
|
|
6160
6298
|
needsQDispatchEventPatch = true;
|
|
@@ -6183,7 +6321,8 @@ const vnode_diff = (container, jsxNode, vStartNode, scopedStyleIdPrefix) => {
|
|
|
6183
6321
|
}
|
|
6184
6322
|
if (isPromise(value)) {
|
|
6185
6323
|
const vHost = vNewNode;
|
|
6186
|
-
value.then((resolvedValue) => setAttribute(key, resolvedValue, vHost));
|
|
6324
|
+
const attributePromise = value.then((resolvedValue) => setAttribute(key, resolvedValue, vHost));
|
|
6325
|
+
asyncAttributePromises.push(attributePromise);
|
|
6187
6326
|
continue;
|
|
6188
6327
|
}
|
|
6189
6328
|
if (key === dangerouslySetInnerHTML) {
|
|
@@ -6307,10 +6446,37 @@ const vnode_diff = (container, jsxNode, vStartNode, scopedStyleIdPrefix) => {
|
|
|
6307
6446
|
let srcIdx = 0;
|
|
6308
6447
|
let dstIdx = 0;
|
|
6309
6448
|
let patchEventDispatch = false;
|
|
6310
|
-
|
|
6311
|
-
|
|
6449
|
+
/**
|
|
6450
|
+
* Optimized setAttribute that bypasses redundant checks when we already know:
|
|
6451
|
+
*
|
|
6452
|
+
* - The index in dstAttrs (no need for binary search)
|
|
6453
|
+
* - The vnode is ElementVNode (no instanceof check)
|
|
6454
|
+
* - The value has changed (no comparison needed)
|
|
6455
|
+
*/
|
|
6456
|
+
const setAttributeDirect = (vnode, key, value, dstIdx, isNewKey) => {
|
|
6457
|
+
const serializedValue = value != null ? serializeAttribute(key, value, scopedStyleIdPrefix) : null;
|
|
6458
|
+
if (isNewKey) {
|
|
6459
|
+
// Adding new key - splice into sorted position
|
|
6460
|
+
if (serializedValue != null) {
|
|
6461
|
+
dstAttrs.splice(dstIdx, 0, key, serializedValue);
|
|
6462
|
+
journal.push(2 /* VNodeJournalOpCode.SetAttribute */, vnode.element, key, serializedValue);
|
|
6463
|
+
}
|
|
6464
|
+
}
|
|
6465
|
+
else {
|
|
6466
|
+
// Updating or removing existing key at dstIdx
|
|
6467
|
+
if (serializedValue != null) {
|
|
6468
|
+
// Update existing value
|
|
6469
|
+
dstAttrs[dstIdx + 1] = serializedValue;
|
|
6470
|
+
journal.push(2 /* VNodeJournalOpCode.SetAttribute */, vnode.element, key, serializedValue);
|
|
6471
|
+
}
|
|
6472
|
+
else {
|
|
6473
|
+
// Remove key (value is null)
|
|
6474
|
+
dstAttrs.splice(dstIdx, 2);
|
|
6475
|
+
journal.push(2 /* VNodeJournalOpCode.SetAttribute */, vnode.element, key, null);
|
|
6476
|
+
}
|
|
6477
|
+
}
|
|
6312
6478
|
};
|
|
6313
|
-
const record = (key, value) => {
|
|
6479
|
+
const record = (key, value, dstIdx, isNewKey) => {
|
|
6314
6480
|
if (key.startsWith(':')) {
|
|
6315
6481
|
vnode.setProp(key, value);
|
|
6316
6482
|
return;
|
|
@@ -6354,19 +6520,31 @@ const vnode_diff = (container, jsxNode, vStartNode, scopedStyleIdPrefix) => {
|
|
|
6354
6520
|
}
|
|
6355
6521
|
}
|
|
6356
6522
|
if (isPromise(value)) {
|
|
6523
|
+
// For async values, we can't use the known index since it will be stale by the time
|
|
6524
|
+
// the promise resolves. Do a binary search to find the current index.
|
|
6357
6525
|
const vHost = vnode;
|
|
6358
|
-
value.then((resolvedValue) =>
|
|
6526
|
+
const attributePromise = value.then((resolvedValue) => {
|
|
6527
|
+
const idx = mapApp_findIndx(dstAttrs, key, 0);
|
|
6528
|
+
const isNewKey = idx < 0;
|
|
6529
|
+
const currentDstIdx = isNewKey ? idx ^ -1 : idx;
|
|
6530
|
+
setAttributeDirect(vHost, key, resolvedValue, currentDstIdx, isNewKey);
|
|
6531
|
+
});
|
|
6532
|
+
asyncAttributePromises.push(attributePromise);
|
|
6359
6533
|
return;
|
|
6360
6534
|
}
|
|
6361
|
-
|
|
6535
|
+
// Always use optimized direct path - we know the index from the merge algorithm
|
|
6536
|
+
setAttributeDirect(vnode, key, value, dstIdx, isNewKey);
|
|
6362
6537
|
};
|
|
6363
6538
|
const recordJsxEvent = (key, value) => {
|
|
6364
6539
|
const data = getEventDataFromHtmlAttribute(key);
|
|
6365
6540
|
if (data) {
|
|
6366
6541
|
const [scope, eventName] = data;
|
|
6367
|
-
|
|
6368
|
-
|
|
6369
|
-
|
|
6542
|
+
const scopedEvent = getScopedEventName(scope, eventName);
|
|
6543
|
+
const loaderScopedEvent = getLoaderScopedEventName(scope, scopedEvent);
|
|
6544
|
+
// Pass dummy index values since ':' prefixed keys take early return via setProp
|
|
6545
|
+
record(':' + scopedEvent, value, 0, false);
|
|
6546
|
+
// register an event for qwik loader (window/document prefixed with '-')
|
|
6547
|
+
registerQwikLoaderEvent(loaderScopedEvent);
|
|
6370
6548
|
patchEventDispatch = true;
|
|
6371
6549
|
}
|
|
6372
6550
|
};
|
|
@@ -6375,8 +6553,8 @@ const vnode_diff = (container, jsxNode, vStartNode, scopedStyleIdPrefix) => {
|
|
|
6375
6553
|
while (srcIdx < srcAttrs.length || dstIdx < dstAttrs.length) {
|
|
6376
6554
|
const srcKey = srcIdx < srcAttrs.length ? srcAttrs[srcIdx] : undefined;
|
|
6377
6555
|
const dstKey = dstIdx < dstAttrs.length ? dstAttrs[dstIdx] : undefined;
|
|
6378
|
-
// Skip special keys in destination
|
|
6379
|
-
if (dstKey?.startsWith(HANDLER_PREFIX)
|
|
6556
|
+
// Skip special keys in destination HANDLER_PREFIX
|
|
6557
|
+
if (dstKey?.startsWith(HANDLER_PREFIX)) {
|
|
6380
6558
|
dstIdx += 2; // skip key and value
|
|
6381
6559
|
continue;
|
|
6382
6560
|
}
|
|
@@ -6387,7 +6565,7 @@ const vnode_diff = (container, jsxNode, vStartNode, scopedStyleIdPrefix) => {
|
|
|
6387
6565
|
dstIdx += 2; // skip key and value
|
|
6388
6566
|
}
|
|
6389
6567
|
else {
|
|
6390
|
-
record(dstKey, null);
|
|
6568
|
+
record(dstKey, null, dstIdx, false);
|
|
6391
6569
|
// After removal, dstAttrs shrinks by 2, so don't advance dstIdx
|
|
6392
6570
|
}
|
|
6393
6571
|
}
|
|
@@ -6398,7 +6576,7 @@ const vnode_diff = (container, jsxNode, vStartNode, scopedStyleIdPrefix) => {
|
|
|
6398
6576
|
recordJsxEvent(srcKey, srcValue);
|
|
6399
6577
|
}
|
|
6400
6578
|
else {
|
|
6401
|
-
record(srcKey, srcValue);
|
|
6579
|
+
record(srcKey, srcValue, dstIdx, true);
|
|
6402
6580
|
}
|
|
6403
6581
|
srcIdx += 2; // skip key and value
|
|
6404
6582
|
// After addition, dstAttrs grows by 2 at sorted position, advance dstIdx
|
|
@@ -6414,7 +6592,7 @@ const vnode_diff = (container, jsxNode, vStartNode, scopedStyleIdPrefix) => {
|
|
|
6414
6592
|
recordJsxEvent(srcKey, srcValue);
|
|
6415
6593
|
}
|
|
6416
6594
|
else {
|
|
6417
|
-
record(srcKey, srcValue);
|
|
6595
|
+
record(srcKey, srcValue, dstIdx, false);
|
|
6418
6596
|
}
|
|
6419
6597
|
}
|
|
6420
6598
|
else if (isEventHandler && !vnode.element.qDispatchEvent) {
|
|
@@ -6432,7 +6610,7 @@ const vnode_diff = (container, jsxNode, vStartNode, scopedStyleIdPrefix) => {
|
|
|
6432
6610
|
recordJsxEvent(srcKey, srcValue);
|
|
6433
6611
|
}
|
|
6434
6612
|
else {
|
|
6435
|
-
record(srcKey, srcValue);
|
|
6613
|
+
record(srcKey, srcValue, dstIdx, true);
|
|
6436
6614
|
}
|
|
6437
6615
|
srcIdx += 2; // skip key and value
|
|
6438
6616
|
// After addition, dstAttrs grows at sorted position (before dstIdx), advance dstIdx
|
|
@@ -6445,7 +6623,7 @@ const vnode_diff = (container, jsxNode, vStartNode, scopedStyleIdPrefix) => {
|
|
|
6445
6623
|
dstIdx += 2; // skip key and value
|
|
6446
6624
|
}
|
|
6447
6625
|
else {
|
|
6448
|
-
record(dstKey, null);
|
|
6626
|
+
record(dstKey, null, dstIdx, false);
|
|
6449
6627
|
// After removal, dstAttrs shrinks at dstIdx, so don't advance dstIdx
|
|
6450
6628
|
}
|
|
6451
6629
|
}
|
|
@@ -6647,32 +6825,11 @@ const vnode_diff = (container, jsxNode, vStartNode, scopedStyleIdPrefix) => {
|
|
|
6647
6825
|
deleteFromSideBuffer(null, lookupKey);
|
|
6648
6826
|
}
|
|
6649
6827
|
if (host) {
|
|
6650
|
-
|
|
6651
|
-
let propsAreDifferent = false;
|
|
6828
|
+
const vNodeProps = host.getProp(ELEMENT_PROPS, container.$getObjectById$);
|
|
6652
6829
|
if (!shouldRender) {
|
|
6653
|
-
|
|
6654
|
-
propsDiffer(jsxProps[_CONST_PROPS], vNodeProps?.[_CONST_PROPS]) ||
|
|
6655
|
-
propsDiffer(jsxProps[_VAR_PROPS], vNodeProps?.[_VAR_PROPS]);
|
|
6656
|
-
shouldRender = shouldRender || propsAreDifferent;
|
|
6830
|
+
shouldRender ||= handleProps(host, jsxProps, vNodeProps, container);
|
|
6657
6831
|
}
|
|
6658
6832
|
if (shouldRender) {
|
|
6659
|
-
if (propsAreDifferent) {
|
|
6660
|
-
if (vNodeProps) {
|
|
6661
|
-
// Reuse the same props instance, qrls can use the current props instance
|
|
6662
|
-
// as a capture ref, so we can't change it.
|
|
6663
|
-
// We need to do this directly, because normally we would subscribe to the signals
|
|
6664
|
-
// if any signal is there.
|
|
6665
|
-
vNodeProps[_CONST_PROPS] = jsxProps[_CONST_PROPS];
|
|
6666
|
-
vNodeProps[_VAR_PROPS] = jsxProps[_VAR_PROPS];
|
|
6667
|
-
vNodeProps[_OWNER] = jsxProps[_OWNER];
|
|
6668
|
-
}
|
|
6669
|
-
else if (jsxProps) {
|
|
6670
|
-
// If there is no props instance, create a new one.
|
|
6671
|
-
// We can do this because we are not using the props instance for anything else.
|
|
6672
|
-
host.setProp(ELEMENT_PROPS, jsxProps);
|
|
6673
|
-
vNodeProps = jsxProps;
|
|
6674
|
-
}
|
|
6675
|
-
}
|
|
6676
6833
|
// Assign the new QRL instance to the host.
|
|
6677
6834
|
// Unfortunately it is created every time, something to fix in the optimizer.
|
|
6678
6835
|
host.setProp(OnRenderProp, componentQRL);
|
|
@@ -6809,7 +6966,37 @@ function getComponentHash(vNode, getObject) {
|
|
|
6809
6966
|
* ```
|
|
6810
6967
|
*/
|
|
6811
6968
|
function Projection() { }
|
|
6812
|
-
function
|
|
6969
|
+
function handleProps(host, jsxProps, vNodeProps, container) {
|
|
6970
|
+
let shouldRender = false;
|
|
6971
|
+
let propsAreDifferent = false;
|
|
6972
|
+
if (vNodeProps) {
|
|
6973
|
+
const effects = vNodeProps[_PROPS_HANDLER].$effects$;
|
|
6974
|
+
const constPropsDifferent = handleChangedProps(jsxProps[_CONST_PROPS], vNodeProps[_CONST_PROPS], vNodeProps[_PROPS_HANDLER], container, false);
|
|
6975
|
+
propsAreDifferent = constPropsDifferent;
|
|
6976
|
+
shouldRender ||= constPropsDifferent;
|
|
6977
|
+
if (effects && effects.size > 0) {
|
|
6978
|
+
const varPropsDifferent = handleChangedProps(jsxProps[_VAR_PROPS], vNodeProps[_VAR_PROPS], vNodeProps[_PROPS_HANDLER], container);
|
|
6979
|
+
propsAreDifferent ||= varPropsDifferent;
|
|
6980
|
+
// don't mark as should render, effects will take care of it
|
|
6981
|
+
// shouldRender ||= varPropsDifferent;
|
|
6982
|
+
}
|
|
6983
|
+
}
|
|
6984
|
+
if (propsAreDifferent) {
|
|
6985
|
+
if (vNodeProps) {
|
|
6986
|
+
// Reuse the same props instance, qrls can use the current props instance
|
|
6987
|
+
// as a capture ref, so we can't change it.
|
|
6988
|
+
vNodeProps[_OWNER] = jsxProps[_OWNER];
|
|
6989
|
+
}
|
|
6990
|
+
else if (jsxProps) {
|
|
6991
|
+
// If there is no props instance, create a new one.
|
|
6992
|
+
// We can do this because we are not using the props instance for anything else.
|
|
6993
|
+
host.setProp(ELEMENT_PROPS, jsxProps);
|
|
6994
|
+
vNodeProps = jsxProps;
|
|
6995
|
+
}
|
|
6996
|
+
}
|
|
6997
|
+
return shouldRender;
|
|
6998
|
+
}
|
|
6999
|
+
function handleChangedProps(src, dst, propsHandler, container, triggerEffects = true) {
|
|
6813
7000
|
const srcEmpty = isPropsEmpty(src);
|
|
6814
7001
|
const dstEmpty = isPropsEmpty(dst);
|
|
6815
7002
|
if (srcEmpty && dstEmpty) {
|
|
@@ -6837,15 +7024,23 @@ function propsDiffer(src, dst) {
|
|
|
6837
7024
|
if (srcLen !== dstLen) {
|
|
6838
7025
|
return true;
|
|
6839
7026
|
}
|
|
7027
|
+
let changed = false;
|
|
7028
|
+
propsHandler.$container$ = container;
|
|
6840
7029
|
for (const key of srcKeys) {
|
|
6841
7030
|
if (key === 'children' || key === QBackRefs) {
|
|
6842
7031
|
continue;
|
|
6843
7032
|
}
|
|
6844
7033
|
if (!Object.prototype.hasOwnProperty.call(dst, key) || src[key] !== dst[key]) {
|
|
6845
|
-
|
|
7034
|
+
changed = true;
|
|
7035
|
+
if (triggerEffects) {
|
|
7036
|
+
triggerPropsProxyEffect(propsHandler, key);
|
|
7037
|
+
}
|
|
7038
|
+
else {
|
|
7039
|
+
return true;
|
|
7040
|
+
}
|
|
6846
7041
|
}
|
|
6847
7042
|
}
|
|
6848
|
-
return
|
|
7043
|
+
return changed;
|
|
6849
7044
|
}
|
|
6850
7045
|
function isPropsEmpty(props) {
|
|
6851
7046
|
if (!props) {
|
|
@@ -6877,28 +7072,30 @@ function cleanup(container, vNode) {
|
|
|
6877
7072
|
if (type & 3 /* VNodeFlags.ELEMENT_OR_VIRTUAL_MASK */) {
|
|
6878
7073
|
clearAllEffects(container, vCursor);
|
|
6879
7074
|
markVNodeAsDeleted(vCursor);
|
|
6880
|
-
|
|
6881
|
-
|
|
7075
|
+
const isComponent = type & 2 /* VNodeFlags.Virtual */ &&
|
|
7076
|
+
vCursor.getProp(OnRenderProp, null) !== null;
|
|
7077
|
+
if (isComponent) {
|
|
7078
|
+
// cleanup q:seq content
|
|
6882
7079
|
const seq = container.getHostProp(vCursor, ELEMENT_SEQ);
|
|
6883
7080
|
if (seq) {
|
|
6884
7081
|
for (let i = 0; i < seq.length; i++) {
|
|
6885
7082
|
const obj = seq[i];
|
|
6886
|
-
if (
|
|
6887
|
-
const
|
|
6888
|
-
|
|
6889
|
-
|
|
6890
|
-
|
|
7083
|
+
if (isObject(obj)) {
|
|
7084
|
+
const objIsTask = isTask(obj);
|
|
7085
|
+
if (objIsTask && obj.$flags$ & 1 /* TaskFlags.VISIBLE_TASK */) {
|
|
7086
|
+
container.$scheduler$(32 /* ChoreType.CLEANUP_VISIBLE */, obj);
|
|
7087
|
+
// don't call cleanupDestroyable yet, do it by the scheduler
|
|
7088
|
+
continue;
|
|
6891
7089
|
}
|
|
6892
|
-
else {
|
|
6893
|
-
|
|
7090
|
+
else if (obj instanceof SignalImpl || isStore(obj)) {
|
|
7091
|
+
clearAllEffects(container, obj);
|
|
7092
|
+
}
|
|
7093
|
+
if (objIsTask || obj instanceof AsyncComputedSignalImpl) {
|
|
7094
|
+
cleanupDestroyable(obj);
|
|
6894
7095
|
}
|
|
6895
7096
|
}
|
|
6896
7097
|
}
|
|
6897
7098
|
}
|
|
6898
|
-
}
|
|
6899
|
-
const isComponent = type & 2 /* VNodeFlags.Virtual */ &&
|
|
6900
|
-
vCursor.getProp(OnRenderProp, null) !== null;
|
|
6901
|
-
if (isComponent) {
|
|
6902
7099
|
// SPECIAL CASE: If we are a component, we need to descend into the projected content and release the content.
|
|
6903
7100
|
const attrs = vnode_getProps(vCursor);
|
|
6904
7101
|
for (let i = 0; i < attrs.length; i = i + 2) {
|
|
@@ -7126,7 +7323,8 @@ function findAncestorBlockingChore(chore, type) {
|
|
|
7126
7323
|
if (blockingChore.$type$ < 16 /* ChoreType.VISIBLE */ &&
|
|
7127
7324
|
blockingChore.$type$ !== 3 /* ChoreType.TASK */ &&
|
|
7128
7325
|
blockingChore.$type$ !== 1 /* ChoreType.QRL_RESOLVE */ &&
|
|
7129
|
-
blockingChore.$type$ !== 2 /* ChoreType.RUN_QRL */
|
|
7326
|
+
blockingChore.$type$ !== 2 /* ChoreType.RUN_QRL */ &&
|
|
7327
|
+
blockingChore.$state$ === ChoreState.NONE) {
|
|
7130
7328
|
return blockingChore;
|
|
7131
7329
|
}
|
|
7132
7330
|
}
|
|
@@ -7151,19 +7349,25 @@ function findBlockingChore(chore, choreQueue, blockedChores, runningChores, cont
|
|
|
7151
7349
|
// Check in choreQueue
|
|
7152
7350
|
// TODO(perf): better to iterate in reverse order?
|
|
7153
7351
|
for (const candidate of choreQueue) {
|
|
7154
|
-
if (candidate.$type$ === rule.blockingType &&
|
|
7352
|
+
if (candidate.$type$ === rule.blockingType &&
|
|
7353
|
+
rule.match(chore, candidate, container) &&
|
|
7354
|
+
candidate.$state$ === ChoreState.NONE) {
|
|
7155
7355
|
return candidate;
|
|
7156
7356
|
}
|
|
7157
7357
|
}
|
|
7158
7358
|
// Check in blockedChores
|
|
7159
7359
|
for (const candidate of blockedChores) {
|
|
7160
|
-
if (candidate.$type$ === rule.blockingType &&
|
|
7360
|
+
if (candidate.$type$ === rule.blockingType &&
|
|
7361
|
+
rule.match(chore, candidate, container) &&
|
|
7362
|
+
candidate.$state$ === ChoreState.NONE) {
|
|
7161
7363
|
return candidate;
|
|
7162
7364
|
}
|
|
7163
7365
|
}
|
|
7164
7366
|
// Check in runningChores
|
|
7165
7367
|
for (const candidate of runningChores) {
|
|
7166
|
-
if (candidate.$type$ === rule.blockingType &&
|
|
7368
|
+
if (candidate.$type$ === rule.blockingType &&
|
|
7369
|
+
rule.match(chore, candidate, container) &&
|
|
7370
|
+
candidate.$state$ !== ChoreState.FAILED) {
|
|
7167
7371
|
return candidate;
|
|
7168
7372
|
}
|
|
7169
7373
|
}
|
|
@@ -7189,7 +7393,9 @@ function findBlockingChoreForVisible(chore, runningChores, container) {
|
|
|
7189
7393
|
continue;
|
|
7190
7394
|
}
|
|
7191
7395
|
for (const candidate of runningChores) {
|
|
7192
|
-
if (candidate.$type$ === rule.blockingType &&
|
|
7396
|
+
if (candidate.$type$ === rule.blockingType &&
|
|
7397
|
+
rule.match(chore, candidate, container) &&
|
|
7398
|
+
candidate.$state$ !== ChoreState.FAILED) {
|
|
7193
7399
|
return candidate;
|
|
7194
7400
|
}
|
|
7195
7401
|
}
|
|
@@ -7430,6 +7636,7 @@ function choreComparator(a, b) {
|
|
|
7430
7636
|
if (a.$type$ === 7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */ &&
|
|
7431
7637
|
b.$type$ === 7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */ &&
|
|
7432
7638
|
((a.$target$ instanceof StoreHandler && b.$target$ instanceof StoreHandler) ||
|
|
7639
|
+
(a.$target$ instanceof PropsProxyHandler && b.$target$ instanceof PropsProxyHandler) ||
|
|
7433
7640
|
(a.$target$ instanceof AsyncComputedSignalImpl &&
|
|
7434
7641
|
b.$target$ instanceof AsyncComputedSignalImpl)) &&
|
|
7435
7642
|
a.$payload$ !== b.$payload$) {
|
|
@@ -7547,6 +7754,8 @@ const createScheduler = (container, journalFlush, choreQueue, blockedChores, run
|
|
|
7547
7754
|
let currentTime = performance.now();
|
|
7548
7755
|
const nextTick = createNextTick(drainChoreQueue);
|
|
7549
7756
|
let flushTimerId = null;
|
|
7757
|
+
let blockingChoresCount = 0;
|
|
7758
|
+
let currentChore = null;
|
|
7550
7759
|
function drainInNextTick() {
|
|
7551
7760
|
if (!drainScheduled) {
|
|
7552
7761
|
drainScheduled = true;
|
|
@@ -7620,24 +7829,30 @@ Problematic chore:
|
|
|
7620
7829
|
|
|
7621
7830
|
This is often caused by modifying a signal in an already rendered component during SSR.`;
|
|
7622
7831
|
logWarn(warningMessage);
|
|
7832
|
+
// Decrement counter if this was a blocking chore that we're skipping
|
|
7833
|
+
if (isRenderBlocking(type)) {
|
|
7834
|
+
blockingChoresCount--;
|
|
7835
|
+
}
|
|
7623
7836
|
return chore;
|
|
7624
7837
|
}
|
|
7625
7838
|
}
|
|
7626
7839
|
}
|
|
7627
7840
|
const shouldBlock = chore.$type$ !== 1 /* ChoreType.QRL_RESOLVE */ && chore.$type$ !== 2 /* ChoreType.RUN_QRL */;
|
|
7628
7841
|
if (shouldBlock) {
|
|
7842
|
+
const runningChore = getRunningChore(chore);
|
|
7843
|
+
if (runningChore) {
|
|
7844
|
+
if (isResourceChore(runningChore)) {
|
|
7845
|
+
addBlockedChore(chore, runningChore, blockedChores);
|
|
7846
|
+
}
|
|
7847
|
+
return chore;
|
|
7848
|
+
}
|
|
7629
7849
|
const blockingChore = findBlockingChore(chore, choreQueue, blockedChores, runningChores, container);
|
|
7630
7850
|
if (blockingChore) {
|
|
7631
7851
|
addBlockedChore(chore, blockingChore, blockedChores);
|
|
7632
7852
|
return chore;
|
|
7633
7853
|
}
|
|
7634
|
-
const runningChore = getRunningChore(chore);
|
|
7635
|
-
if (runningChore) {
|
|
7636
|
-
addBlockedChore(chore, runningChore, blockedChores);
|
|
7637
|
-
return chore;
|
|
7638
|
-
}
|
|
7639
7854
|
}
|
|
7640
|
-
|
|
7855
|
+
addChoreAndIncrementBlockingCounter(chore, choreQueue);
|
|
7641
7856
|
const runImmediately = (isServer && type === 6 /* ChoreType.COMPONENT */) || type === 2 /* ChoreType.RUN_QRL */;
|
|
7642
7857
|
if (runImmediately && !isDraining) {
|
|
7643
7858
|
immediateDrain();
|
|
@@ -7686,6 +7901,9 @@ This is often caused by modifying a signal in an already rendered component duri
|
|
|
7686
7901
|
}, delay);
|
|
7687
7902
|
}
|
|
7688
7903
|
function applyJournalFlush() {
|
|
7904
|
+
if (blockingChoresCount > 0) {
|
|
7905
|
+
return;
|
|
7906
|
+
}
|
|
7689
7907
|
if (!isJournalFlushRunning) {
|
|
7690
7908
|
// prevent multiple journal flushes from running at the same time
|
|
7691
7909
|
isJournalFlushRunning = true;
|
|
@@ -7752,7 +7970,7 @@ This is often caused by modifying a signal in an already rendered component duri
|
|
|
7752
7970
|
if (vnode_isVNode(blockedChore.$host$)) {
|
|
7753
7971
|
blockedChore.$host$.blockedChores?.delete(blockedChore);
|
|
7754
7972
|
}
|
|
7755
|
-
|
|
7973
|
+
addChoreAndIncrementBlockingCounter(blockedChore, choreQueue);
|
|
7756
7974
|
blockedChoresScheduled = true;
|
|
7757
7975
|
}
|
|
7758
7976
|
}
|
|
@@ -7762,12 +7980,12 @@ This is often caused by modifying a signal in an already rendered component duri
|
|
|
7762
7980
|
drainInNextTick();
|
|
7763
7981
|
}
|
|
7764
7982
|
};
|
|
7765
|
-
let currentChore = null;
|
|
7766
7983
|
try {
|
|
7767
7984
|
while (choreQueue.length) {
|
|
7768
7985
|
currentTime = performance.now();
|
|
7769
7986
|
const chore = (currentChore = choreQueue.shift());
|
|
7770
7987
|
if (chore.$state$ !== ChoreState.NONE) {
|
|
7988
|
+
// Chore was already processed, counter already decremented in finishChore/handleError
|
|
7771
7989
|
continue;
|
|
7772
7990
|
}
|
|
7773
7991
|
if (vNodeAlreadyDeleted(chore) &&
|
|
@@ -7778,6 +7996,10 @@ This is often caused by modifying a signal in an already rendered component duri
|
|
|
7778
7996
|
if (vnode_isVNode(chore.$host$)) {
|
|
7779
7997
|
chore.$host$.chores?.delete(chore);
|
|
7780
7998
|
}
|
|
7999
|
+
// Decrement counter if this was a blocking chore that we're skipping
|
|
8000
|
+
if (isRenderBlocking(chore.$type$)) {
|
|
8001
|
+
blockingChoresCount--;
|
|
8002
|
+
}
|
|
7781
8003
|
continue;
|
|
7782
8004
|
}
|
|
7783
8005
|
if (chore.$type$ === 16 /* ChoreType.VISIBLE */) {
|
|
@@ -7786,7 +8008,7 @@ This is often caused by modifying a signal in an already rendered component duri
|
|
|
7786
8008
|
applyJournalFlush();
|
|
7787
8009
|
const blockingChore = findBlockingChoreForVisible(chore, runningChores, container);
|
|
7788
8010
|
if (blockingChore && blockingChore.$state$ === ChoreState.RUNNING) {
|
|
7789
|
-
|
|
8011
|
+
(blockingChore.$blockedChores$ ||= new ChoreArray()).add(chore);
|
|
7790
8012
|
continue;
|
|
7791
8013
|
}
|
|
7792
8014
|
}
|
|
@@ -7853,10 +8075,18 @@ This is often caused by modifying a signal in an already rendered component duri
|
|
|
7853
8075
|
if (vnode_isVNode(chore.$host$)) {
|
|
7854
8076
|
chore.$host$.chores?.delete(chore);
|
|
7855
8077
|
}
|
|
8078
|
+
// Decrement blocking counter if this chore was blocking journal flush
|
|
8079
|
+
if (isRenderBlocking(chore.$type$)) {
|
|
8080
|
+
blockingChoresCount--;
|
|
8081
|
+
}
|
|
7856
8082
|
}
|
|
7857
8083
|
function handleError(chore, e) {
|
|
7858
8084
|
chore.$endTime$ = performance.now();
|
|
7859
8085
|
chore.$state$ = ChoreState.FAILED;
|
|
8086
|
+
// Decrement blocking counter if this chore was blocking journal flush
|
|
8087
|
+
if (isRenderBlocking(chore.$type$)) {
|
|
8088
|
+
blockingChoresCount--;
|
|
8089
|
+
}
|
|
7860
8090
|
// If we used the result as promise, this won't exist
|
|
7861
8091
|
chore.$reject$?.(e);
|
|
7862
8092
|
container.handleError(e, chore.$host$);
|
|
@@ -7894,14 +8124,21 @@ This is often caused by modifying a signal in an already rendered component duri
|
|
|
7894
8124
|
returnValue = runResource(payload, container, host);
|
|
7895
8125
|
}
|
|
7896
8126
|
else {
|
|
7897
|
-
|
|
8127
|
+
const task = payload;
|
|
8128
|
+
returnValue = runTask(task, container, host);
|
|
8129
|
+
if (task.$flags$ & 16 /* TaskFlags.RENDER_BLOCKING */) {
|
|
8130
|
+
blockingChoresCount++;
|
|
8131
|
+
returnValue = maybeThen(returnValue, () => {
|
|
8132
|
+
blockingChoresCount--;
|
|
8133
|
+
});
|
|
8134
|
+
}
|
|
7898
8135
|
}
|
|
7899
8136
|
}
|
|
7900
8137
|
break;
|
|
7901
8138
|
case 32 /* ChoreType.CLEANUP_VISIBLE */:
|
|
7902
8139
|
{
|
|
7903
8140
|
const task = chore.$payload$;
|
|
7904
|
-
|
|
8141
|
+
cleanupDestroyable(task);
|
|
7905
8142
|
}
|
|
7906
8143
|
break;
|
|
7907
8144
|
case 4 /* ChoreType.NODE_DIFF */:
|
|
@@ -7995,22 +8232,42 @@ This is often caused by modifying a signal in an already rendered component duri
|
|
|
7995
8232
|
}
|
|
7996
8233
|
return null;
|
|
7997
8234
|
}
|
|
8235
|
+
function addChoreAndIncrementBlockingCounter(chore, choreArray) {
|
|
8236
|
+
if (addChore(chore, choreArray)) {
|
|
8237
|
+
blockingChoresCount++;
|
|
8238
|
+
}
|
|
8239
|
+
}
|
|
7998
8240
|
};
|
|
8241
|
+
function addChore(chore, choreArray) {
|
|
8242
|
+
const idx = choreArray.add(chore);
|
|
8243
|
+
if (idx < 0) {
|
|
8244
|
+
if (vnode_isVNode(chore.$host$)) {
|
|
8245
|
+
(chore.$host$.chores ||= new ChoreArray()).add(chore);
|
|
8246
|
+
}
|
|
8247
|
+
return isRenderBlocking(chore.$type$);
|
|
8248
|
+
}
|
|
8249
|
+
return false;
|
|
8250
|
+
}
|
|
7999
8251
|
function vNodeAlreadyDeleted(chore) {
|
|
8000
8252
|
return !!(chore.$host$ && vnode_isVNode(chore.$host$) && chore.$host$.flags & 32 /* VNodeFlags.Deleted */);
|
|
8001
8253
|
}
|
|
8254
|
+
function isResourceChore(chore) {
|
|
8255
|
+
return (chore.$type$ === 3 /* ChoreType.TASK */ &&
|
|
8256
|
+
!!chore.$payload$ &&
|
|
8257
|
+
!!(chore.$payload$.$flags$ & 4 /* TaskFlags.RESOURCE */));
|
|
8258
|
+
}
|
|
8002
8259
|
function addBlockedChore(blockedChore, blockingChore, blockedChores) {
|
|
8260
|
+
if (!isResourceChore(blockedChore) && choreComparator(blockedChore, blockingChore) === 0) {
|
|
8261
|
+
return;
|
|
8262
|
+
}
|
|
8003
8263
|
(blockingChore.$blockedChores$ ||= new ChoreArray()).add(blockedChore);
|
|
8004
8264
|
blockedChores.add(blockedChore);
|
|
8005
8265
|
if (vnode_isVNode(blockedChore.$host$)) {
|
|
8006
8266
|
(blockedChore.$host$.blockedChores ||= new ChoreArray()).add(blockedChore);
|
|
8007
8267
|
}
|
|
8008
8268
|
}
|
|
8009
|
-
function
|
|
8010
|
-
|
|
8011
|
-
if (idx < 0 && vnode_isVNode(chore.$host$)) {
|
|
8012
|
-
(chore.$host$.chores ||= new ChoreArray()).add(chore);
|
|
8013
|
-
}
|
|
8269
|
+
function isRenderBlocking(type) {
|
|
8270
|
+
return type === 4 /* ChoreType.NODE_DIFF */ || type === 6 /* ChoreType.COMPONENT */;
|
|
8014
8271
|
}
|
|
8015
8272
|
function choreTypeToName(type) {
|
|
8016
8273
|
return ({
|
|
@@ -8101,9 +8358,9 @@ function debugTrace(action, arg, queue, blockedChores) {
|
|
|
8101
8358
|
}
|
|
8102
8359
|
}
|
|
8103
8360
|
// Blocked chores section
|
|
8104
|
-
if (blockedChores && blockedChores.
|
|
8361
|
+
if (blockedChores && blockedChores.length > 0) {
|
|
8105
8362
|
lines.push('');
|
|
8106
|
-
lines.push(`🚫 Blocked Chores (${blockedChores.
|
|
8363
|
+
lines.push(`🚫 Blocked Chores (${blockedChores.length} items):`);
|
|
8107
8364
|
Array.from(blockedChores).forEach((chore, index) => {
|
|
8108
8365
|
const type = debugChoreTypeToString(chore.$type$);
|
|
8109
8366
|
const host = String(chore.$host$).replaceAll(/\n.*/gim, '');
|
|
@@ -8179,16 +8436,16 @@ async function serialize(serializationContext) {
|
|
|
8179
8436
|
let parent;
|
|
8180
8437
|
const qrlMap = new Map();
|
|
8181
8438
|
/** Helper to output an array */
|
|
8182
|
-
const outputArray = (value,
|
|
8439
|
+
const outputArray = (value, keepUndefined, writeFn) => {
|
|
8183
8440
|
$writer$.write('[');
|
|
8184
8441
|
let separator = false;
|
|
8185
8442
|
let length;
|
|
8186
|
-
if (
|
|
8443
|
+
if (keepUndefined) {
|
|
8187
8444
|
length = value.length;
|
|
8188
8445
|
}
|
|
8189
8446
|
else {
|
|
8190
8447
|
length = value.length - 1;
|
|
8191
|
-
while (length >= 0 && value[length] ===
|
|
8448
|
+
while (length >= 0 && value[length] === undefined) {
|
|
8192
8449
|
length--;
|
|
8193
8450
|
}
|
|
8194
8451
|
length++;
|
|
@@ -8205,7 +8462,7 @@ async function serialize(serializationContext) {
|
|
|
8205
8462
|
$writer$.write(']');
|
|
8206
8463
|
};
|
|
8207
8464
|
/** Output a type,value pair. If the value is an array, it calls writeValue on each item. */
|
|
8208
|
-
const output = (type, value,
|
|
8465
|
+
const output = (type, value, keepUndefined) => {
|
|
8209
8466
|
$writer$.write(`${type},`);
|
|
8210
8467
|
if (typeof value === 'number') {
|
|
8211
8468
|
$writer$.write(value.toString());
|
|
@@ -8222,7 +8479,7 @@ async function serialize(serializationContext) {
|
|
|
8222
8479
|
$writer$.write(lastIdx === 0 ? s : s.slice(lastIdx));
|
|
8223
8480
|
}
|
|
8224
8481
|
else {
|
|
8225
|
-
outputArray(value,
|
|
8482
|
+
outputArray(value, !!keepUndefined, (valueItem, idx) => {
|
|
8226
8483
|
writeValue(valueItem, idx);
|
|
8227
8484
|
});
|
|
8228
8485
|
}
|
|
@@ -8413,7 +8670,12 @@ async function serialize(serializationContext) {
|
|
|
8413
8670
|
const writeObjectValue = (value) => {
|
|
8414
8671
|
if (isPropsProxy(value)) {
|
|
8415
8672
|
const owner = value[_OWNER];
|
|
8416
|
-
output(32 /* TypeIds.PropsProxy */, [
|
|
8673
|
+
output(32 /* TypeIds.PropsProxy */, [
|
|
8674
|
+
_serializationWeakRef(owner),
|
|
8675
|
+
owner.varProps,
|
|
8676
|
+
owner.constProps,
|
|
8677
|
+
value[_PROPS_HANDLER].$effects$,
|
|
8678
|
+
]);
|
|
8417
8679
|
}
|
|
8418
8680
|
else if (value instanceof SubscriptionData) {
|
|
8419
8681
|
output(33 /* TypeIds.SubscriptionData */, [value.data.$scopedStyleIdPrefix$, value.data.$isConst$]);
|
|
@@ -8443,7 +8705,7 @@ async function serialize(serializationContext) {
|
|
|
8443
8705
|
}
|
|
8444
8706
|
}
|
|
8445
8707
|
const out = [storeTarget, flags, effects, ...innerStores];
|
|
8446
|
-
while (out[out.length - 1]
|
|
8708
|
+
while (out[out.length - 1] === undefined) {
|
|
8447
8709
|
out.pop();
|
|
8448
8710
|
}
|
|
8449
8711
|
output(29 /* TypeIds.Store */, out);
|
|
@@ -8453,7 +8715,7 @@ async function serialize(serializationContext) {
|
|
|
8453
8715
|
const result = value[SerializerSymbol](value);
|
|
8454
8716
|
if (isPromise(result)) {
|
|
8455
8717
|
const forwardRef = resolvePromise(result, $addRoot$, (resolved, resolvedValue) => {
|
|
8456
|
-
return new PromiseResult(28 /* TypeIds.SerializerSignal */, resolved, resolvedValue,
|
|
8718
|
+
return new PromiseResult(28 /* TypeIds.SerializerSignal */, resolved, resolvedValue, undefined, undefined);
|
|
8457
8719
|
});
|
|
8458
8720
|
output(2 /* TypeIds.ForwardRef */, forwardRef);
|
|
8459
8721
|
}
|
|
@@ -8488,10 +8750,16 @@ async function serialize(serializationContext) {
|
|
|
8488
8750
|
else if (value instanceof SignalImpl) {
|
|
8489
8751
|
if (value instanceof SerializerSignalImpl) {
|
|
8490
8752
|
addPreloadQrl(value.$computeQrl$);
|
|
8491
|
-
const
|
|
8492
|
-
|
|
8493
|
-
|
|
8494
|
-
|
|
8753
|
+
const maybeValue = getCustomSerializerPromise(value, value.$untrackedValue$);
|
|
8754
|
+
if (isPromise(maybeValue)) {
|
|
8755
|
+
const forwardRefId = resolvePromise(maybeValue, $addRoot$, (resolved, resolvedValue) => {
|
|
8756
|
+
return new PromiseResult(28 /* TypeIds.SerializerSignal */, resolved, resolvedValue, value.$effects$, value.$computeQrl$);
|
|
8757
|
+
});
|
|
8758
|
+
output(2 /* TypeIds.ForwardRef */, forwardRefId);
|
|
8759
|
+
}
|
|
8760
|
+
else {
|
|
8761
|
+
output(28 /* TypeIds.SerializerSignal */, [value.$computeQrl$, value.$effects$, maybeValue]);
|
|
8762
|
+
}
|
|
8495
8763
|
return;
|
|
8496
8764
|
}
|
|
8497
8765
|
if (value instanceof WrappedSignalImpl) {
|
|
@@ -8524,13 +8792,28 @@ async function serialize(serializationContext) {
|
|
|
8524
8792
|
if (isAsync) {
|
|
8525
8793
|
out.push(value.$loadingEffects$, value.$errorEffects$, value.$untrackedLoading$, value.$untrackedError$);
|
|
8526
8794
|
}
|
|
8795
|
+
let keepUndefined = false;
|
|
8527
8796
|
if (v !== NEEDS_COMPUTATION) {
|
|
8528
8797
|
out.push(v);
|
|
8798
|
+
if (!isAsync && v === undefined) {
|
|
8799
|
+
/**
|
|
8800
|
+
* If value is undefined, we need to keep it in the output. If we don't do that, later
|
|
8801
|
+
* during resuming, the value will be set to symbol(invalid) with flag invalid, and
|
|
8802
|
+
* thats is incorrect.
|
|
8803
|
+
*/
|
|
8804
|
+
keepUndefined = true;
|
|
8805
|
+
}
|
|
8529
8806
|
}
|
|
8530
|
-
output(isAsync ? 27 /* TypeIds.AsyncComputedSignal */ : 26 /* TypeIds.ComputedSignal */, out);
|
|
8807
|
+
output(isAsync ? 27 /* TypeIds.AsyncComputedSignal */ : 26 /* TypeIds.ComputedSignal */, out, keepUndefined);
|
|
8531
8808
|
}
|
|
8532
8809
|
else {
|
|
8533
|
-
|
|
8810
|
+
const v = value.$untrackedValue$;
|
|
8811
|
+
const keepUndefined = v === undefined;
|
|
8812
|
+
const out = [v];
|
|
8813
|
+
if (value.$effects$) {
|
|
8814
|
+
out.push(...value.$effects$);
|
|
8815
|
+
}
|
|
8816
|
+
output(24 /* TypeIds.Signal */, out, keepUndefined);
|
|
8534
8817
|
}
|
|
8535
8818
|
}
|
|
8536
8819
|
else if (value instanceof URL) {
|
|
@@ -8614,9 +8897,9 @@ async function serialize(serializationContext) {
|
|
|
8614
8897
|
value.varProps,
|
|
8615
8898
|
value.constProps,
|
|
8616
8899
|
value.children,
|
|
8617
|
-
value.toSort ||
|
|
8900
|
+
value.toSort || undefined,
|
|
8618
8901
|
];
|
|
8619
|
-
while (out[out.length - 1]
|
|
8902
|
+
while (out[out.length - 1] === undefined) {
|
|
8620
8903
|
out.pop();
|
|
8621
8904
|
}
|
|
8622
8905
|
output(31 /* TypeIds.JSXNode */, out);
|
|
@@ -8630,7 +8913,7 @@ async function serialize(serializationContext) {
|
|
|
8630
8913
|
value[_EFFECT_BACK_REF],
|
|
8631
8914
|
value.$state$,
|
|
8632
8915
|
];
|
|
8633
|
-
while (out[out.length - 1]
|
|
8916
|
+
while (out[out.length - 1] === undefined) {
|
|
8634
8917
|
out.pop();
|
|
8635
8918
|
}
|
|
8636
8919
|
output(21 /* TypeIds.Task */, out);
|
|
@@ -8757,7 +9040,7 @@ class PromiseResult {
|
|
|
8757
9040
|
$value$;
|
|
8758
9041
|
$effects$;
|
|
8759
9042
|
$qrl$;
|
|
8760
|
-
constructor($type$, $resolved$, $value$, $effects$ =
|
|
9043
|
+
constructor($type$, $resolved$, $value$, $effects$ = undefined, $qrl$ = undefined) {
|
|
8761
9044
|
this.$type$ = $type$;
|
|
8762
9045
|
this.$resolved$ = $resolved$;
|
|
8763
9046
|
this.$value$ = $value$;
|
|
@@ -8766,20 +9049,24 @@ class PromiseResult {
|
|
|
8766
9049
|
}
|
|
8767
9050
|
}
|
|
8768
9051
|
function getCustomSerializerPromise(signal, value) {
|
|
8769
|
-
|
|
8770
|
-
|
|
8771
|
-
|
|
8772
|
-
|
|
8773
|
-
|
|
8774
|
-
|
|
8775
|
-
|
|
8776
|
-
|
|
8777
|
-
|
|
8778
|
-
|
|
8779
|
-
|
|
8780
|
-
|
|
8781
|
-
|
|
8782
|
-
}
|
|
9052
|
+
if (value === NEEDS_COMPUTATION) {
|
|
9053
|
+
return value;
|
|
9054
|
+
}
|
|
9055
|
+
return maybeThen((signal.$computeQrl$.resolved || signal.$computeQrl$.resolve()), (arg) => {
|
|
9056
|
+
let data;
|
|
9057
|
+
if (typeof arg === 'function') {
|
|
9058
|
+
arg = arg();
|
|
9059
|
+
}
|
|
9060
|
+
if (arg.serialize) {
|
|
9061
|
+
data = arg.serialize(value);
|
|
9062
|
+
}
|
|
9063
|
+
else if (typeof value === 'object' && SerializerSymbol in value) {
|
|
9064
|
+
data = value[SerializerSymbol](value);
|
|
9065
|
+
}
|
|
9066
|
+
if (data === undefined) {
|
|
9067
|
+
data = NEEDS_COMPUTATION;
|
|
9068
|
+
}
|
|
9069
|
+
return data;
|
|
8783
9070
|
});
|
|
8784
9071
|
}
|
|
8785
9072
|
const discoverValuesForVNodeData = (vnodeData, callback) => {
|
|
@@ -8830,7 +9117,7 @@ function serializeWrappingFn(serializationContext, value) {
|
|
|
8830
9117
|
return [syncFnId, value.$args$];
|
|
8831
9118
|
}
|
|
8832
9119
|
function filterEffectBackRefs(effectBackRef) {
|
|
8833
|
-
let effectBackRefToSerialize =
|
|
9120
|
+
let effectBackRefToSerialize = undefined;
|
|
8834
9121
|
if (effectBackRef) {
|
|
8835
9122
|
for (const [effectProp, effect] of effectBackRef) {
|
|
8836
9123
|
if (effect[2 /* EffectSubscriptionProp.BACK_REF */]) {
|
|
@@ -9010,7 +9297,7 @@ class _SharedContainer {
|
|
|
9010
9297
|
throw Error('Not implemented');
|
|
9011
9298
|
};
|
|
9012
9299
|
const choreQueue = new ChoreArray();
|
|
9013
|
-
const blockedChores = new
|
|
9300
|
+
const blockedChores = new ChoreArray();
|
|
9014
9301
|
const runningChores = new Set();
|
|
9015
9302
|
this.$scheduler$ = createScheduler(this, journalFlush, choreQueue, blockedChores, runningChores);
|
|
9016
9303
|
}
|
|
@@ -9095,7 +9382,7 @@ async function _walkJSX(ssr, value, options) {
|
|
|
9095
9382
|
}
|
|
9096
9383
|
function processJSXNode(ssr, enqueue, value, options) {
|
|
9097
9384
|
// console.log('processJSXNode', value);
|
|
9098
|
-
if (value
|
|
9385
|
+
if (value == null) {
|
|
9099
9386
|
ssr.textNode('');
|
|
9100
9387
|
}
|
|
9101
9388
|
else if (typeof value === 'boolean') {
|
|
@@ -9152,12 +9439,12 @@ function processJSXNode(ssr, enqueue, value, options) {
|
|
|
9152
9439
|
appendQwikInspectorAttribute(jsx, qwikInspectorAttrValue);
|
|
9153
9440
|
}
|
|
9154
9441
|
}
|
|
9155
|
-
const innerHTML = ssr.openElement(type,
|
|
9442
|
+
const innerHTML = ssr.openElement(type, toSsrAttrs(jsx.varProps, {
|
|
9156
9443
|
serializationCtx: ssr.serializationCtx,
|
|
9157
9444
|
styleScopedId: options.styleScoped,
|
|
9158
9445
|
key: jsx.key,
|
|
9159
9446
|
toSort: jsx.toSort,
|
|
9160
|
-
}),
|
|
9447
|
+
}), toSsrAttrs(jsx.constProps, {
|
|
9161
9448
|
serializationCtx: ssr.serializationCtx,
|
|
9162
9449
|
styleScopedId: options.styleScoped,
|
|
9163
9450
|
}), qwikInspectorAttrValue);
|
|
@@ -9254,12 +9541,22 @@ function processJSXNode(ssr, enqueue, value, options) {
|
|
|
9254
9541
|
const componentFrame = ssr.getParentComponentFrame();
|
|
9255
9542
|
componentFrame.distributeChildrenIntoSlots(jsx.children, options.styleScoped, options.parentComponentFrame);
|
|
9256
9543
|
const jsxOutput = applyQwikComponentBody(ssr, jsx, type);
|
|
9257
|
-
const compStyleComponentId = addComponentStylePrefix(host.getProp(QScopedStyle));
|
|
9258
9544
|
enqueue(new ParentComponentData(options.styleScoped, options.parentComponentFrame));
|
|
9259
9545
|
enqueue(ssr.closeComponent);
|
|
9260
|
-
|
|
9261
|
-
|
|
9262
|
-
|
|
9546
|
+
if (isPromise(jsxOutput)) {
|
|
9547
|
+
// Defer reading QScopedStyle until after the promise resolves
|
|
9548
|
+
enqueue(async () => {
|
|
9549
|
+
const resolvedOutput = await jsxOutput;
|
|
9550
|
+
const compStyleComponentId = addComponentStylePrefix(host.getProp(QScopedStyle));
|
|
9551
|
+
enqueue(resolvedOutput);
|
|
9552
|
+
enqueue(new ParentComponentData(compStyleComponentId, componentFrame));
|
|
9553
|
+
});
|
|
9554
|
+
}
|
|
9555
|
+
else {
|
|
9556
|
+
enqueue(jsxOutput);
|
|
9557
|
+
const compStyleComponentId = addComponentStylePrefix(host.getProp(QScopedStyle));
|
|
9558
|
+
enqueue(new ParentComponentData(compStyleComponentId, componentFrame));
|
|
9559
|
+
}
|
|
9263
9560
|
}
|
|
9264
9561
|
else {
|
|
9265
9562
|
const inlineComponentProps = [ELEMENT_KEY, jsx.key];
|
|
@@ -9276,12 +9573,6 @@ function processJSXNode(ssr, enqueue, value, options) {
|
|
|
9276
9573
|
}
|
|
9277
9574
|
}
|
|
9278
9575
|
}
|
|
9279
|
-
function varPropsToSsrAttrs(varProps, constProps, options) {
|
|
9280
|
-
return toSsrAttrs(varProps, options);
|
|
9281
|
-
}
|
|
9282
|
-
function constPropsToSsrAttrs(constProps, varProps, options) {
|
|
9283
|
-
return toSsrAttrs(constProps, options);
|
|
9284
|
-
}
|
|
9285
9576
|
function toSsrAttrs(record, options) {
|
|
9286
9577
|
if (record == null) {
|
|
9287
9578
|
return null;
|
|
@@ -9344,7 +9635,7 @@ function setEvent(serializationCtx, key, rawValue) {
|
|
|
9344
9635
|
*
|
|
9345
9636
|
* For internal qrls (starting with `_`) we assume that they do the right thing.
|
|
9346
9637
|
*/
|
|
9347
|
-
if (!qrl.$symbol$.startsWith('_') &&
|
|
9638
|
+
if (!qrl.$symbol$.startsWith('_') && qrl.$captureRef$?.length) {
|
|
9348
9639
|
qrl = createQRL(null, '_run', _run, null, null, [qrl]);
|
|
9349
9640
|
}
|
|
9350
9641
|
return qrlToString(serializationCtx, qrl);
|
|
@@ -9375,14 +9666,16 @@ function addQwikEventToSerializationContext(serializationCtx, key, qrl) {
|
|
|
9375
9666
|
// TODO extract window/document too so qwikloader can precisely listen
|
|
9376
9667
|
const data = getEventDataFromHtmlAttribute(key);
|
|
9377
9668
|
if (data) {
|
|
9378
|
-
const eventName = data
|
|
9379
|
-
|
|
9669
|
+
const [scope, eventName] = data;
|
|
9670
|
+
const scopedEvent = getScopedEventName(scope, eventName);
|
|
9671
|
+
const loaderScopedEvent = getLoaderScopedEventName(scope, scopedEvent);
|
|
9672
|
+
serializationCtx.$eventNames$.add(loaderScopedEvent);
|
|
9380
9673
|
serializationCtx.$eventQrls$.add(qrl);
|
|
9381
9674
|
}
|
|
9382
9675
|
}
|
|
9383
9676
|
function addPreventDefaultEventToSerializationContext(serializationCtx, key) {
|
|
9384
|
-
// skip first 15 chars, this is length of the `preventdefault
|
|
9385
|
-
const eventName = key.substring(
|
|
9677
|
+
// skip first 15 chars, this is length of the `preventdefault`, leave the ":"
|
|
9678
|
+
const eventName = key.substring(14);
|
|
9386
9679
|
if (eventName) {
|
|
9387
9680
|
serializationCtx.$eventNames$.add(eventName);
|
|
9388
9681
|
}
|
|
@@ -9520,10 +9813,11 @@ const inflate = (container, target, typeId, data) => {
|
|
|
9520
9813
|
asyncComputed.$loadingEffects$ = new Set(d[2]);
|
|
9521
9814
|
asyncComputed.$errorEffects$ = new Set(d[3]);
|
|
9522
9815
|
asyncComputed.$untrackedLoading$ = d[4];
|
|
9523
|
-
asyncComputed.$untrackedError$ = d[5]
|
|
9816
|
+
asyncComputed.$untrackedError$ = d[5];
|
|
9524
9817
|
const hasValue = d.length > 6;
|
|
9525
9818
|
if (hasValue) {
|
|
9526
9819
|
asyncComputed.$untrackedValue$ = d[6];
|
|
9820
|
+
asyncComputed.$promiseValue$ = d[6];
|
|
9527
9821
|
}
|
|
9528
9822
|
asyncComputed.$flags$ |= 1 /* SignalFlags.INVALID */;
|
|
9529
9823
|
break;
|
|
@@ -9534,7 +9828,9 @@ const inflate = (container, target, typeId, data) => {
|
|
|
9534
9828
|
const computed = target;
|
|
9535
9829
|
const d = data;
|
|
9536
9830
|
computed.$computeQrl$ = d[0];
|
|
9537
|
-
|
|
9831
|
+
if (d[1]) {
|
|
9832
|
+
computed.$effects$ = new Set(d[1]);
|
|
9833
|
+
}
|
|
9538
9834
|
const hasValue = d.length > 2;
|
|
9539
9835
|
if (hasValue) {
|
|
9540
9836
|
computed.$untrackedValue$ = d[2];
|
|
@@ -9629,6 +9925,7 @@ const inflate = (container, target, typeId, data) => {
|
|
|
9629
9925
|
owner._proxy = propsProxy;
|
|
9630
9926
|
}
|
|
9631
9927
|
propsProxy[_OWNER] = owner;
|
|
9928
|
+
propsProxy[_PROPS_HANDLER].$effects$ = d[3];
|
|
9632
9929
|
break;
|
|
9633
9930
|
case 33 /* TypeIds.SubscriptionData */: {
|
|
9634
9931
|
const effectData = target;
|
|
@@ -10185,6 +10482,9 @@ class DomContainer extends _SharedContainer {
|
|
|
10185
10482
|
preprocessState(this.$rawStateData$, this);
|
|
10186
10483
|
this.$stateData$ = wrapDeserializerProxy(this, this.$rawStateData$);
|
|
10187
10484
|
}
|
|
10485
|
+
if (!qTest && element.isConnected) {
|
|
10486
|
+
element.dispatchEvent(new CustomEvent('qresume', { bubbles: true }));
|
|
10487
|
+
}
|
|
10188
10488
|
}
|
|
10189
10489
|
$setRawState$(id, vParent) {
|
|
10190
10490
|
this.$stateData$[id] = vParent;
|
|
@@ -10620,7 +10920,7 @@ const getOrCreateStore = (obj, flags, container) => {
|
|
|
10620
10920
|
class StoreHandler {
|
|
10621
10921
|
$flags$;
|
|
10622
10922
|
$container$;
|
|
10623
|
-
$effects$ =
|
|
10923
|
+
$effects$ = undefined;
|
|
10624
10924
|
constructor($flags$, $container$) {
|
|
10625
10925
|
this.$flags$ = $flags$;
|
|
10626
10926
|
this.$container$ = $container$;
|
|
@@ -10630,7 +10930,7 @@ class StoreHandler {
|
|
|
10630
10930
|
}
|
|
10631
10931
|
force(prop) {
|
|
10632
10932
|
const target = getStoreTarget(this);
|
|
10633
|
-
this.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */,
|
|
10933
|
+
this.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */, undefined, this, getEffects(target, prop, this.$effects$));
|
|
10634
10934
|
}
|
|
10635
10935
|
get(target, prop) {
|
|
10636
10936
|
// TODO(perf): handle better `slice` calls
|
|
@@ -10699,7 +10999,7 @@ class StoreHandler {
|
|
|
10699
10999
|
if (!Array.isArray(target)) {
|
|
10700
11000
|
// If the target is an array, we don't need to trigger effects.
|
|
10701
11001
|
// Changing the length property will trigger effects.
|
|
10702
|
-
this.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */,
|
|
11002
|
+
this.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */, undefined, this, getEffects(target, prop, this.$effects$));
|
|
10703
11003
|
}
|
|
10704
11004
|
return true;
|
|
10705
11005
|
}
|
|
@@ -10755,13 +11055,14 @@ function addStoreEffect(target, prop, store, effectSubscription) {
|
|
|
10755
11055
|
// to unsubscribe from. So we need to store the reference from the effect back
|
|
10756
11056
|
// to this signal.
|
|
10757
11057
|
ensureContainsBackRef(effectSubscription, target);
|
|
11058
|
+
// TODO is this needed with the preloader?
|
|
10758
11059
|
addQrlToSerializationCtx(effectSubscription, store.$container$);
|
|
10759
11060
|
}
|
|
10760
11061
|
function setNewValueAndTriggerEffects(prop, value, target, currentStore) {
|
|
10761
11062
|
target[prop] = value;
|
|
10762
11063
|
const effects = getEffects(target, prop, currentStore.$effects$);
|
|
10763
11064
|
if (effects) {
|
|
10764
|
-
currentStore.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */,
|
|
11065
|
+
currentStore.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */, undefined, currentStore, effects);
|
|
10765
11066
|
}
|
|
10766
11067
|
}
|
|
10767
11068
|
function getEffects(target, prop, storeEffects) {
|
|
@@ -10786,7 +11087,7 @@ function getEffects(target, prop, storeEffects) {
|
|
|
10786
11087
|
effectsToTrigger.add(effect);
|
|
10787
11088
|
}
|
|
10788
11089
|
}
|
|
10789
|
-
return effectsToTrigger
|
|
11090
|
+
return effectsToTrigger;
|
|
10790
11091
|
}
|
|
10791
11092
|
|
|
10792
11093
|
const canSerialize = (value, seen = new WeakSet()) => {
|
|
@@ -12576,21 +12877,22 @@ const useVisibleTaskQrl = (qrl, opts) => {
|
|
|
12576
12877
|
const { val, set, i, iCtx } = useSequentialScope();
|
|
12577
12878
|
const eagerness = opts?.strategy ?? 'intersection-observer';
|
|
12578
12879
|
if (val) {
|
|
12579
|
-
if (isServerPlatform()) {
|
|
12580
|
-
|
|
12880
|
+
if (!(val.$flags$ & 32 /* TaskFlags.EVENTS_REGISTERED */) && !isServerPlatform()) {
|
|
12881
|
+
val.$flags$ |= 32 /* TaskFlags.EVENTS_REGISTERED */;
|
|
12882
|
+
useRegisterTaskEvents(val, eagerness);
|
|
12581
12883
|
}
|
|
12582
12884
|
return;
|
|
12583
12885
|
}
|
|
12584
12886
|
assertQrl(qrl);
|
|
12585
12887
|
const task = new Task(1 /* TaskFlags.VISIBLE_TASK */, i, iCtx.$hostElement$, qrl, undefined, null);
|
|
12586
12888
|
set(task);
|
|
12587
|
-
|
|
12889
|
+
useRegisterTaskEvents(task, eagerness);
|
|
12588
12890
|
if (!isServerPlatform()) {
|
|
12589
12891
|
qrl.resolve(iCtx.$element$);
|
|
12590
12892
|
iCtx.$container$.$scheduler$(16 /* ChoreType.VISIBLE */, task);
|
|
12591
12893
|
}
|
|
12592
12894
|
};
|
|
12593
|
-
const
|
|
12895
|
+
const useRegisterTaskEvents = (task, eagerness) => {
|
|
12594
12896
|
if (eagerness === 'intersection-observer') {
|
|
12595
12897
|
useOn('qvisible', getTaskHandlerQrl(task));
|
|
12596
12898
|
}
|