@qwik.dev/core 2.0.0-beta.2 → 2.0.0-beta.3

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/core.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @license
3
- * @qwik.dev/core 2.0.0-beta.2-dev+3ddc6c7
3
+ * @qwik.dev/core 2.0.0-beta.3-dev+aa098fc
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
@@ -642,8 +642,6 @@ class WrappedSignalImpl extends SignalImpl {
642
642
  $invalidate$() {
643
643
  this.$flags$ |= 1 /* SignalFlags.INVALID */;
644
644
  this.$forceRunEffects$ = false;
645
- // We should only call subscribers if the calculation actually changed.
646
- // Therefore, we need to calculate the value now.
647
645
  this.$container$?.$scheduler$(7 /* ChoreType.RECOMPUTE_AND_SCHEDULE_EFFECTS */, this.$hostElement$, this, this.$effects$);
648
646
  }
649
647
  /**
@@ -1230,7 +1228,7 @@ const isRecoverable = (err) => {
1230
1228
  *
1231
1229
  * @public
1232
1230
  */
1233
- const version = "2.0.0-beta.2-dev+3ddc6c7";
1231
+ const version = "2.0.0-beta.3-dev+aa098fc";
1234
1232
 
1235
1233
  /** @internal */
1236
1234
  const EMPTY_ARRAY = [];
@@ -2421,7 +2419,6 @@ const executeComponent = (container, renderHost, subscriptionHost, componentQRL,
2421
2419
  if (!isInlineComponent) {
2422
2420
  container.setHostProp(renderHost, ELEMENT_SEQ_IDX, null);
2423
2421
  container.setHostProp(renderHost, USE_ON_LOCAL_SEQ_IDX, null);
2424
- container.setHostProp(renderHost, ELEMENT_PROPS, props);
2425
2422
  }
2426
2423
  if (vnode_isVNode(renderHost)) {
2427
2424
  clearAllEffects(container, renderHost);
@@ -4540,16 +4537,36 @@ const vnode_diff = (container, jsxNode, vStartNode, scopedStyleIdPrefix) => {
4540
4537
  shouldRender = true;
4541
4538
  }
4542
4539
  if (host) {
4543
- const vNodeProps = vnode_getProp(host, ELEMENT_PROPS, container.$getObjectById$);
4544
- shouldRender = shouldRender || propsDiffer(jsxProps, vNodeProps);
4540
+ let vNodeProps = vnode_getProp(host, ELEMENT_PROPS, container.$getObjectById$);
4541
+ const propsAreDifferent = propsDiffer(jsxProps, vNodeProps);
4542
+ shouldRender = shouldRender || propsAreDifferent;
4545
4543
  if (shouldRender) {
4544
+ if (propsAreDifferent) {
4545
+ if (vNodeProps) {
4546
+ // Reuse the same props instance, qrls can use the current props instance
4547
+ // as a capture ref, so we can't change it.
4548
+ // We need to do this directly, because normally we would subscribe to the signals
4549
+ // if any signal is there.
4550
+ vNodeProps[_CONST_PROPS] = jsxProps[_CONST_PROPS];
4551
+ vNodeProps[_VAR_PROPS] = jsxProps[_VAR_PROPS];
4552
+ }
4553
+ else if (jsxProps) {
4554
+ // If there is no props instance, create a new one.
4555
+ // We can do this because we are not using the props instance for anything else.
4556
+ vnode_setProp(host, ELEMENT_PROPS, jsxProps);
4557
+ vNodeProps = jsxProps;
4558
+ }
4559
+ }
4560
+ // Assign the new QRL instance to the host.
4561
+ // Unfortunately it is created every time, something to fix in the optimizer.
4562
+ vnode_setProp(host, OnRenderProp, componentQRL);
4546
4563
  /**
4547
4564
  * Mark host as not deleted. The host could have been marked as deleted if it there was a
4548
4565
  * cleanup run. Now we found it and want to reuse it, so we need to mark it as not
4549
4566
  * deleted.
4550
4567
  */
4551
4568
  host[0 /* VNodeProps.flags */] &= -33 /* VNodeFlags.Deleted */;
4552
- container.$scheduler$(6 /* ChoreType.COMPONENT */, host, componentQRL, jsxProps);
4569
+ container.$scheduler$(6 /* ChoreType.COMPONENT */, host, componentQRL, vNodeProps);
4553
4570
  }
4554
4571
  }
4555
4572
  descendContentToProject(jsxNode.children, host);
@@ -5509,22 +5526,23 @@ const createScheduler = (container, scheduleDrain, journalFlush) => {
5509
5526
  {
5510
5527
  const target = chore.$target$;
5511
5528
  const effects = chore.$payload$;
5529
+ const ctx = newInvokeContext();
5530
+ ctx.$container$ = container;
5512
5531
  if (target instanceof ComputedSignalImpl || target instanceof WrappedSignalImpl) {
5513
5532
  const forceRunEffects = target.$forceRunEffects$;
5514
5533
  target.$forceRunEffects$ = false;
5515
- if (!target.$effects$?.size) {
5534
+ if (!effects?.size) {
5516
5535
  break;
5517
5536
  }
5518
- returnValue = retryOnPromise(() => {
5519
- if (target.$computeIfNeeded$() || forceRunEffects) {
5520
- triggerEffects(container, target, effects);
5537
+ // needed for computed signals and throwing QRLs
5538
+ returnValue = maybeThen(retryOnPromise(() => invoke.call(target, ctx, target.$computeIfNeeded$)), (didChange) => {
5539
+ if (didChange || forceRunEffects) {
5540
+ return retryOnPromise(() => triggerEffects(container, target, effects));
5521
5541
  }
5522
5542
  });
5523
5543
  }
5524
5544
  else {
5525
- returnValue = retryOnPromise(() => {
5526
- triggerEffects(container, target, effects);
5527
- });
5545
+ returnValue = retryOnPromise(() => triggerEffects(container, target, effects));
5528
5546
  }
5529
5547
  }
5530
5548
  break;
@@ -5606,7 +5624,10 @@ const createScheduler = (container, scheduleDrain, journalFlush) => {
5606
5624
  return idxDiff;
5607
5625
  }
5608
5626
  // If the host is the same (or missing), and the type is the same, we need to compare the target.
5609
- if (a.$target$ !== b.$target$ || a.$payload$ !== b.$payload$) {
5627
+ if (a.$target$ !== b.$target$) {
5628
+ if (isQrl(a.$target$) && isQrl(b.$target$) && a.$target$.$hash$ === b.$target$.$hash$) {
5629
+ return 0;
5630
+ }
5610
5631
  // 1 means that we are going to process chores as FIFO
5611
5632
  return 1;
5612
5633
  }
@@ -5654,7 +5675,7 @@ const createScheduler = (container, scheduleDrain, journalFlush) => {
5654
5675
  * multiple times during component execution. For this reason it is necessary for us to update
5655
5676
  * the chore with the latest result of the signal.
5656
5677
  */
5657
- if (existing.$type$ === 4 /* ChoreType.NODE_DIFF */) {
5678
+ if (existing.$payload$ !== value.$payload$) {
5658
5679
  existing.$payload$ = value.$payload$;
5659
5680
  }
5660
5681
  if (existing.$executed$) {
@@ -7786,12 +7807,15 @@ const processVNodeData = (vData, callback) => {
7786
7807
  let nextToConsumeIdx = 0;
7787
7808
  let ch = 0;
7788
7809
  let peekCh = 0;
7810
+ const getChar = (idx) => {
7811
+ return idx < vData.length ? vData.charCodeAt(idx) : 0;
7812
+ };
7789
7813
  const peek = () => {
7790
7814
  if (peekCh !== 0) {
7791
7815
  return peekCh;
7792
7816
  }
7793
7817
  else {
7794
- return (peekCh = nextToConsumeIdx < vData.length ? vData.charCodeAt(nextToConsumeIdx) : 0);
7818
+ return (peekCh = getChar(nextToConsumeIdx));
7795
7819
  }
7796
7820
  };
7797
7821
  const consume = () => {
@@ -7812,7 +7836,7 @@ const processVNodeData = (vData, callback) => {
7812
7836
  return vData.substring(start, nextToConsumeIdx);
7813
7837
  };
7814
7838
  while (peek() !== 0) {
7815
- callback(peek, consumeValue, consume, nextToConsumeIdx);
7839
+ callback(peek, consumeValue, consume, getChar, nextToConsumeIdx);
7816
7840
  }
7817
7841
  };
7818
7842
  const vnode_getNextSibling = (vnode) => {
@@ -8026,21 +8050,19 @@ function materializeFromVNodeData(vParent, vData, element, child) {
8026
8050
  let textIdx = 0;
8027
8051
  let combinedText = null;
8028
8052
  let container = null;
8029
- processVNodeData(vData, (peek, consumeValue, consume, nextToConsumeIdx) => {
8053
+ processVNodeData(vData, (peek, consumeValue, consume, getChar, nextToConsumeIdx) => {
8030
8054
  if (isNumber(peek())) {
8031
8055
  // Element counts get encoded as numbers.
8032
- while (!isElement(child)) {
8056
+ while (!isElement(child) ||
8057
+ // We pretend that style element's don't exist as they can get moved out.
8058
+ // skip over style elements, as those need to be moved to the head
8059
+ // and are not included in the counts.
8060
+ isQStyleElement(child)) {
8033
8061
  child = fastNextSibling(child);
8034
8062
  if (!child) {
8035
8063
  throw qError(27 /* QError.materializeVNodeDataError */, [vData, peek(), nextToConsumeIdx]);
8036
8064
  }
8037
8065
  }
8038
- // We pretend that style element's don't exist as they can get moved out.
8039
- while (isQStyleElement(child)) {
8040
- // skip over style elements, as those need to be moved to the head
8041
- // and are not included in the counts.
8042
- child = fastNextSibling(child);
8043
- }
8044
8066
  combinedText = null;
8045
8067
  previousTextNode = null;
8046
8068
  let value = 0;
@@ -8072,7 +8094,17 @@ function materializeFromVNodeData(vParent, vData, element, child) {
8072
8094
  vnode_setAttr(null, vParent, ELEMENT_PROPS, consumeValue());
8073
8095
  }
8074
8096
  else if (peek() === VNodeDataChar.KEY) {
8075
- vnode_setAttr(null, vParent, ELEMENT_KEY, consumeValue());
8097
+ const isEscapedValue = getChar(nextToConsumeIdx + 1) === VNodeDataChar.SEPARATOR;
8098
+ let value;
8099
+ if (isEscapedValue) {
8100
+ consume();
8101
+ value = decodeURI(consumeValue());
8102
+ consume();
8103
+ }
8104
+ else {
8105
+ value = consumeValue();
8106
+ }
8107
+ vnode_setAttr(null, vParent, ELEMENT_KEY, value);
8076
8108
  }
8077
8109
  else if (peek() === VNodeDataChar.SEQ) {
8078
8110
  vnode_setAttr(null, vParent, ELEMENT_SEQ, consumeValue());
@@ -8118,6 +8150,10 @@ function materializeFromVNodeData(vParent, vData, element, child) {
8118
8150
  vnode_setAttr(null, vParent, QSlot, consumeValue());
8119
8151
  }
8120
8152
  else {
8153
+ // skip over style elements in front of text nodes, where text node is the first child (except the style node)
8154
+ while (isQStyleElement(child)) {
8155
+ child = fastNextSibling(child);
8156
+ }
8121
8157
  const textNode = child && fastNodeType(child) === /* Node.TEXT_NODE */ 3 ? child : null;
8122
8158
  // must be alphanumeric
8123
8159
  if (combinedText === null) {
@@ -10076,6 +10112,7 @@ const NoSerializeSymbol = Symbol('noSerialize');
10076
10112
  const SerializerSymbol = Symbol('serialize');
10077
10113
 
10078
10114
  // keep these imports above the rest to prevent circular dep issues
10115
+ const resolvedSymbol = Symbol('resolved');
10079
10116
  const createQRL = (chunk, symbol, symbolRef, symbolFn, capture, captureRef) => {
10080
10117
  if (qDev && qSerialize) {
10081
10118
  if (captureRef) {
@@ -10128,9 +10165,6 @@ const createQRL = (chunk, symbol, symbolRef, symbolFn, capture, captureRef) => {
10128
10165
  };
10129
10166
  return bound;
10130
10167
  }
10131
- const resolveLazy = (containerEl) => {
10132
- return symbolRef !== null ? symbolRef : resolve(containerEl);
10133
- };
10134
10168
  // Wrap functions to provide their lexical scope
10135
10169
  const wrapFn = (fn) => {
10136
10170
  if (typeof fn !== 'function' || (!capture?.length && !captureRef?.length)) {
@@ -10159,45 +10193,58 @@ const createQRL = (chunk, symbol, symbolRef, symbolFn, capture, captureRef) => {
10159
10193
  return invoke.call(this, context, fn, ...args);
10160
10194
  };
10161
10195
  };
10162
- const resolve = async (containerEl) => {
10163
- if (symbolRef !== null) {
10164
- // Resolving (Promise) or already resolved (value)
10196
+ // Retrieve memoized result from symbolFn
10197
+ if (symbolFn && resolvedSymbol in symbolFn) {
10198
+ symbolRef = symbolFn[resolvedSymbol];
10199
+ }
10200
+ const resolve = symbolRef
10201
+ ? async () => symbolRef
10202
+ : async (containerEl) => {
10203
+ if (symbolRef !== null) {
10204
+ // Resolving (Promise) or already resolved (value)
10205
+ return symbolRef;
10206
+ }
10207
+ if (containerEl) {
10208
+ setContainer(containerEl);
10209
+ }
10210
+ if (chunk === '') {
10211
+ // Sync QRL
10212
+ assertDefined(_containerEl, 'Sync QRL must have container element');
10213
+ const hash = _containerEl.getAttribute(QInstanceAttr);
10214
+ const doc = _containerEl.ownerDocument;
10215
+ const qFuncs = getQFuncs(doc, hash);
10216
+ // No need to wrap, syncQRLs can't have captured scope
10217
+ return (qrl.resolved = symbolRef = qFuncs[Number(symbol)]);
10218
+ }
10219
+ if (isBrowser && chunk) {
10220
+ /** We run the QRL, so now the probability of the chunk is 100% */
10221
+ p(chunk, 1);
10222
+ }
10223
+ const start = now();
10224
+ const ctx = tryGetInvokeContext();
10225
+ if (symbolFn !== null) {
10226
+ symbolRef = symbolFn().then((module) => {
10227
+ const resolved = wrapFn((symbolRef = module[symbol]));
10228
+ // We memoize the result on the symbolFn
10229
+ symbolFn[resolvedSymbol] = resolved;
10230
+ qrl.resolved = resolved;
10231
+ return resolved;
10232
+ });
10233
+ }
10234
+ else {
10235
+ // TODO cache the imported symbol but watch out for dev mode
10236
+ const imported = getPlatform().importSymbol(_containerEl, chunk, symbol);
10237
+ symbolRef = maybeThen(imported, (ref) => (qrl.resolved = wrapFn((symbolRef = ref))));
10238
+ }
10239
+ if (isPromise(symbolRef)) {
10240
+ symbolRef.then(() => emitUsedSymbol(symbol, ctx?.$element$, start), (err) => {
10241
+ console.error(`qrl ${symbol} failed to load`, err);
10242
+ // We shouldn't cache rejections, we can try again later
10243
+ symbolRef = null;
10244
+ });
10245
+ }
10165
10246
  return symbolRef;
10166
- }
10167
- if (containerEl) {
10168
- setContainer(containerEl);
10169
- }
10170
- if (chunk === '') {
10171
- // Sync QRL
10172
- assertDefined(_containerEl, 'Sync QRL must have container element');
10173
- const hash = _containerEl.getAttribute(QInstanceAttr);
10174
- const doc = _containerEl.ownerDocument;
10175
- const qFuncs = getQFuncs(doc, hash);
10176
- // No need to wrap, syncQRLs can't have captured scope
10177
- return (qrl.resolved = symbolRef = qFuncs[Number(symbol)]);
10178
- }
10179
- if (isBrowser && chunk) {
10180
- /** We run the QRL, so now the probability of the chunk is 100% */
10181
- p(chunk, 1);
10182
- }
10183
- const start = now();
10184
- const ctx = tryGetInvokeContext();
10185
- if (symbolFn !== null) {
10186
- symbolRef = symbolFn().then((module) => (qrl.resolved = wrapFn((symbolRef = module[symbol]))));
10187
- }
10188
- else {
10189
- const imported = getPlatform().importSymbol(_containerEl, chunk, symbol);
10190
- symbolRef = maybeThen(imported, (ref) => (qrl.resolved = wrapFn((symbolRef = ref))));
10191
- }
10192
- if (typeof symbolRef === 'object' && isPromise(symbolRef)) {
10193
- symbolRef.then(() => emitUsedSymbol(symbol, ctx?.$element$, start), (err) => {
10194
- console.error(`qrl ${symbol} failed to load`, err);
10195
- // We shouldn't cache rejections, we can try again later
10196
- symbolRef = null;
10197
- });
10198
- }
10199
- return symbolRef;
10200
- };
10247
+ };
10201
10248
  const createOrReuseInvocationContext = (invoke) => {
10202
10249
  if (invoke == null) {
10203
10250
  return newInvokeContext();
@@ -10215,7 +10262,6 @@ const createQRL = (chunk, symbol, symbolRef, symbolFn, capture, captureRef) => {
10215
10262
  getHash: () => hash,
10216
10263
  getCaptured: () => captureRef,
10217
10264
  resolve,
10218
- $resolveLazy$: resolveLazy,
10219
10265
  $setContainer$: setContainer,
10220
10266
  $chunk$: chunk,
10221
10267
  $symbol$: symbol,
@@ -11056,13 +11102,13 @@ const _useStyles = (styleQrl, transform, scoped) => {
11056
11102
  const styleId = styleKey(styleQrl, i);
11057
11103
  const host = iCtx.$hostElement$;
11058
11104
  set(styleId);
11059
- const value = styleQrl.$resolveLazy$(iCtx.$element$);
11060
- if (isPromise(value)) {
11061
- value.then((val) => iCtx.$container$.$appendStyle$(transform(val, styleId), styleId, host, scoped));
11062
- throw value;
11105
+ if (styleQrl.resolved) {
11106
+ iCtx.$container$.$appendStyle$(transform(styleQrl.resolved, styleId), styleId, host, scoped);
11063
11107
  }
11064
11108
  else {
11065
- iCtx.$container$.$appendStyle$(transform(value, styleId), styleId, host, scoped);
11109
+ throw styleQrl
11110
+ .resolve()
11111
+ .then((val) => iCtx.$container$.$appendStyle$(transform(val, styleId), styleId, host, scoped));
11066
11112
  }
11067
11113
  return styleId;
11068
11114
  };
@@ -11353,7 +11399,7 @@ const useVisibleTaskQrl = (qrl, opts) => {
11353
11399
  set(task);
11354
11400
  useRunTask(task, eagerness);
11355
11401
  if (!isServerPlatform()) {
11356
- qrl.$resolveLazy$(iCtx.$element$);
11402
+ qrl.resolve(iCtx.$element$);
11357
11403
  iCtx.$container$.$scheduler$(32 /* ChoreType.VISIBLE */, task);
11358
11404
  }
11359
11405
  };