@qwik.dev/core 2.0.0-beta.25 → 2.0.0-beta.26
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 +2 -2
- package/dist/core-internal.d.ts +1 -1
- package/dist/core.min.mjs +1 -1
- package/dist/core.mjs +116 -38
- package/dist/core.mjs.map +1 -1
- package/dist/core.prod.mjs +85 -62
- package/dist/loader/package.json +1 -1
- package/dist/optimizer.mjs +320 -319
- package/dist/server.mjs +3 -17
- package/dist/starters/adapters/fastify/package.json +1 -1
- package/dist/testing/index.mjs +74 -60
- package/dist/testing/package.json +1 -1
- package/package.json +3 -3
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.26-dev+c693cf5
|
|
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
|
|
@@ -1007,7 +1007,7 @@ const COMMA = ',';
|
|
|
1007
1007
|
*
|
|
1008
1008
|
* @public
|
|
1009
1009
|
*/
|
|
1010
|
-
const version = "2.0.0-beta.
|
|
1010
|
+
const version = "2.0.0-beta.26-dev+c693cf5";
|
|
1011
1011
|
|
|
1012
1012
|
// keep this import from core/build so the cjs build works
|
|
1013
1013
|
const createPlatform = () => {
|
|
@@ -1020,6 +1020,8 @@ const createPlatform = () => {
|
|
|
1020
1020
|
if (regSym) {
|
|
1021
1021
|
return regSym;
|
|
1022
1022
|
}
|
|
1023
|
+
// we never lazy import on the server
|
|
1024
|
+
throw qError(6 /* QError.dynamicImportFailed */, [symbolName]);
|
|
1023
1025
|
}
|
|
1024
1026
|
if (!url) {
|
|
1025
1027
|
throw qError(14 /* QError.qrlMissingChunk */, [symbolName]);
|
|
@@ -3705,7 +3707,14 @@ const cleanupDestroyable = (destroyable) => {
|
|
|
3705
3707
|
* This safely calls an event handler, handling errors and retrying on thrown Promises, and
|
|
3706
3708
|
* providing extra parameters defined on the elements as arguments (used for loop optimization)
|
|
3707
3709
|
*/
|
|
3708
|
-
function runEventHandlerQRL(handler, event, element, ctx
|
|
3710
|
+
function runEventHandlerQRL(handler, event, element, ctx) {
|
|
3711
|
+
if (!element.isConnected) {
|
|
3712
|
+
// ignore events on disconnected elements, this can happen when the event is triggered while the element is being removed
|
|
3713
|
+
return;
|
|
3714
|
+
}
|
|
3715
|
+
if (!ctx) {
|
|
3716
|
+
ctx = newInvokeContextFromDOM(event, element);
|
|
3717
|
+
}
|
|
3709
3718
|
const container = ctx.$container$;
|
|
3710
3719
|
const hostElement = ctx.$hostElement$;
|
|
3711
3720
|
vnode_ensureElementInflated(container, hostElement);
|
|
@@ -3770,8 +3779,8 @@ function setAttribute(journal, vnode, key, value, scopedStyleIdPrefix, originalV
|
|
|
3770
3779
|
vnode_setProp(vnode, key, originalValue);
|
|
3771
3780
|
addVNodeOperation(journal, createSetAttributeOperation(vnode.node, key, value, scopedStyleIdPrefix, (vnode.flags & 512 /* VNodeFlags.NS_svg */) !== 0));
|
|
3772
3781
|
}
|
|
3773
|
-
|
|
3774
|
-
|
|
3782
|
+
function createDiffContext(container, journal, cursor, scopedStyleIdPrefix) {
|
|
3783
|
+
return {
|
|
3775
3784
|
container,
|
|
3776
3785
|
journal,
|
|
3777
3786
|
cursor,
|
|
@@ -3802,6 +3811,9 @@ const vnode_diff = (container, journal, jsxNode, vStartNode, cursor, scopedStyle
|
|
|
3802
3811
|
}),
|
|
3803
3812
|
},
|
|
3804
3813
|
};
|
|
3814
|
+
}
|
|
3815
|
+
const vnode_diff = (container, journal, jsxNode, vStartNode, cursor, scopedStyleIdPrefix) => {
|
|
3816
|
+
const diffContext = createDiffContext(container, journal, cursor, scopedStyleIdPrefix);
|
|
3805
3817
|
////////////////////////////////
|
|
3806
3818
|
diff(diffContext, jsxNode, vStartNode);
|
|
3807
3819
|
const result = drainAsyncQueue(diffContext);
|
|
@@ -4156,6 +4168,7 @@ function expectSlot(diffContext) {
|
|
|
4156
4168
|
vHost && vnode_setProp(vHost, slotNameKey, diffContext.vNewNode);
|
|
4157
4169
|
isDev &&
|
|
4158
4170
|
vnode_setProp(diffContext.vNewNode, DEBUG_TYPE, "P" /* VirtualType.Projection */);
|
|
4171
|
+
vnode_inflateProjectionTrailingText(diffContext.journal, diffContext.vNewNode);
|
|
4159
4172
|
vnode_insertBefore(diffContext.journal, diffContext.vParent, diffContext.vNewNode, diffContext.vCurrent && getInsertBefore(diffContext));
|
|
4160
4173
|
// If we moved from a q:template and it's now empty, remove it
|
|
4161
4174
|
if (oldParent &&
|
|
@@ -4706,26 +4719,34 @@ function expectComponent(diffContext, component) {
|
|
|
4706
4719
|
const vNodeLookupKey = getKey(host) || vNodeComponentHash;
|
|
4707
4720
|
const lookupKeysAreEqual = lookupKey === vNodeLookupKey;
|
|
4708
4721
|
const hashesAreEqual = componentHash === vNodeComponentHash;
|
|
4709
|
-
if (
|
|
4710
|
-
if (
|
|
4722
|
+
if (lookupKeysAreEqual) {
|
|
4723
|
+
if (hashesAreEqual) {
|
|
4724
|
+
deleteFromSideBuffer(diffContext, null, lookupKey);
|
|
4725
|
+
}
|
|
4726
|
+
else {
|
|
4711
4727
|
insertNewComponent(diffContext, host, componentQRL, jsxProps);
|
|
4728
|
+
host = diffContext.vNewNode;
|
|
4712
4729
|
shouldRender = true;
|
|
4713
4730
|
}
|
|
4714
|
-
host = (diffContext.vNewNode || diffContext.vCurrent);
|
|
4715
|
-
}
|
|
4716
|
-
else if (!hashesAreEqual || !jsxNode.key) {
|
|
4717
|
-
insertNewComponent(diffContext, host, componentQRL, jsxProps);
|
|
4718
|
-
host = diffContext.vNewNode;
|
|
4719
|
-
shouldRender = true;
|
|
4720
4731
|
}
|
|
4721
4732
|
else {
|
|
4722
|
-
|
|
4723
|
-
|
|
4733
|
+
if (moveOrCreateKeyedNode(diffContext, null, lookupKey, lookupKey, diffContext.vParent)) {
|
|
4734
|
+
insertNewComponent(diffContext, host, componentQRL, jsxProps);
|
|
4735
|
+
shouldRender = true;
|
|
4736
|
+
}
|
|
4737
|
+
host = (diffContext.vNewNode || diffContext.vCurrent);
|
|
4724
4738
|
}
|
|
4725
4739
|
if (host) {
|
|
4726
4740
|
const vNodeProps = vnode_getProp(host, ELEMENT_PROPS, diffContext.container.$getObjectById$);
|
|
4727
4741
|
if (!shouldRender) {
|
|
4728
|
-
|
|
4742
|
+
const propsChanged = handleProps(host, jsxProps, vNodeProps, diffContext.container);
|
|
4743
|
+
// if props changed but key is null we need to insert a new component, because we need to execute hooks etc
|
|
4744
|
+
if (propsChanged && jsxNode.key == null) {
|
|
4745
|
+
insertNewComponent(diffContext, host, componentQRL, jsxProps);
|
|
4746
|
+
host = diffContext.vNewNode;
|
|
4747
|
+
shouldRender = true;
|
|
4748
|
+
}
|
|
4749
|
+
shouldRender ||= propsChanged;
|
|
4729
4750
|
}
|
|
4730
4751
|
if (shouldRender) {
|
|
4731
4752
|
// Assign the new QRL instance to the host.
|
|
@@ -4747,7 +4768,7 @@ function expectComponent(diffContext, component) {
|
|
|
4747
4768
|
const lookupKeysAreEqual = lookupKey === vNodeLookupKey;
|
|
4748
4769
|
const vNodeComponentHash = getComponentHash(host, diffContext.container.$getObjectById$);
|
|
4749
4770
|
const isInlineComponent = vNodeComponentHash == null;
|
|
4750
|
-
if ((host && !isInlineComponent) ||
|
|
4771
|
+
if ((host && !isInlineComponent) || !host) {
|
|
4751
4772
|
insertNewInlineComponent(diffContext);
|
|
4752
4773
|
host = diffContext.vNewNode;
|
|
4753
4774
|
}
|
|
@@ -5739,7 +5760,7 @@ function walkCursor(cursor, options) {
|
|
|
5739
5760
|
return;
|
|
5740
5761
|
}
|
|
5741
5762
|
// Check time budget (only for DOM, not SSR)
|
|
5742
|
-
if (
|
|
5763
|
+
if (isBrowser) {
|
|
5743
5764
|
const elapsed = performance.now() - startTime;
|
|
5744
5765
|
if (elapsed >= timeBudget) {
|
|
5745
5766
|
// Schedule continuation as macrotask to actually yield to browser
|
|
@@ -5781,10 +5802,27 @@ function tryDescendDirtyChildren(container, cursorData, currentVNode, cursor) {
|
|
|
5781
5802
|
return null;
|
|
5782
5803
|
}
|
|
5783
5804
|
partitionDirtyChildren(dirtyChildren, currentVNode);
|
|
5805
|
+
// Scan dirtyChildren directly instead of going through getNextVNode.
|
|
5806
|
+
// getNextVNode follows the child's parent/slotParent pointer, which for Projection nodes
|
|
5807
|
+
// points to the DOM insertion location rather than currentVNode — that would scan the
|
|
5808
|
+
// wrong dirtyChildren array and potentially cause infinite loops.
|
|
5809
|
+
// const len = dirtyChildren.length;
|
|
5810
|
+
// for (let i = 0; i < len; i++) {
|
|
5811
|
+
// const child = dirtyChildren[i];
|
|
5812
|
+
// if (child.dirty & ChoreBits.DIRTY_MASK) {
|
|
5813
|
+
// currentVNode.nextDirtyChildIndex = (i + 1) % len;
|
|
5814
|
+
// setCursorPosition(container, cursorData, child);
|
|
5815
|
+
// return child;
|
|
5816
|
+
// }
|
|
5817
|
+
// }
|
|
5818
|
+
// // No dirty child found — clean up
|
|
5819
|
+
// currentVNode.dirty &= ~ChoreBits.CHILDREN;
|
|
5820
|
+
// currentVNode.dirtyChildren = null;
|
|
5784
5821
|
currentVNode.nextDirtyChildIndex = 0;
|
|
5785
5822
|
const next = getNextVNode(dirtyChildren[0], cursor);
|
|
5786
5823
|
setCursorPosition(container, cursorData, next);
|
|
5787
5824
|
return next;
|
|
5825
|
+
// return null;
|
|
5788
5826
|
}
|
|
5789
5827
|
/**
|
|
5790
5828
|
* Partitions dirtyChildren array so non-projections come first, projections last. Uses in-place
|
|
@@ -5813,14 +5851,14 @@ function getNextVNode(vNode, cursor) {
|
|
|
5813
5851
|
}
|
|
5814
5852
|
return null;
|
|
5815
5853
|
}
|
|
5816
|
-
// Prefer
|
|
5854
|
+
// Prefer slotParent (logical owner) for Projections, fall back to parent
|
|
5817
5855
|
let parent = null;
|
|
5818
|
-
if (vNode.
|
|
5819
|
-
parent = vNode.parent;
|
|
5820
|
-
}
|
|
5821
|
-
else if (vNode.slotParent && vNode.slotParent.dirty & 32 /* ChoreBits.CHILDREN */) {
|
|
5856
|
+
if (vNode.slotParent && vNode.slotParent.dirty & 32 /* ChoreBits.CHILDREN */) {
|
|
5822
5857
|
parent = vNode.slotParent;
|
|
5823
5858
|
}
|
|
5859
|
+
else if (vNode.parent && vNode.parent.dirty & 32 /* ChoreBits.CHILDREN */) {
|
|
5860
|
+
parent = vNode.parent;
|
|
5861
|
+
}
|
|
5824
5862
|
if (!parent) {
|
|
5825
5863
|
if (cursor.dirty & 127 /* ChoreBits.DIRTY_MASK */) {
|
|
5826
5864
|
return cursor;
|
|
@@ -5992,7 +6030,9 @@ function propagatePath(target) {
|
|
|
5992
6030
|
const parent = reusablePath[i + 1] || target;
|
|
5993
6031
|
parent.dirty |= 32 /* ChoreBits.CHILDREN */;
|
|
5994
6032
|
parent.dirtyChildren ||= [];
|
|
5995
|
-
parent.dirtyChildren.
|
|
6033
|
+
if (!parent.dirtyChildren.includes(child)) {
|
|
6034
|
+
parent.dirtyChildren.push(child);
|
|
6035
|
+
}
|
|
5996
6036
|
}
|
|
5997
6037
|
}
|
|
5998
6038
|
/**
|
|
@@ -6001,7 +6041,7 @@ function propagatePath(target) {
|
|
|
6001
6041
|
*/
|
|
6002
6042
|
function propagateToCursorRoot(vNode, cursorRoot) {
|
|
6003
6043
|
reusablePath.push(vNode);
|
|
6004
|
-
let current = vNode.
|
|
6044
|
+
let current = vNode.slotParent || vNode.parent;
|
|
6005
6045
|
while (current) {
|
|
6006
6046
|
const isDirty = current.dirty & 127 /* ChoreBits.DIRTY_MASK */;
|
|
6007
6047
|
const currentIsCursor = isCursor(current);
|
|
@@ -6026,7 +6066,7 @@ function propagateToCursorRoot(vNode, cursorRoot) {
|
|
|
6026
6066
|
}
|
|
6027
6067
|
}
|
|
6028
6068
|
reusablePath.push(current);
|
|
6029
|
-
current = current.
|
|
6069
|
+
current = current.slotParent || current.parent;
|
|
6030
6070
|
}
|
|
6031
6071
|
reusablePath.length = 0;
|
|
6032
6072
|
throwErrorAndStop('Cursor root not found in current path!');
|
|
@@ -6037,7 +6077,7 @@ function propagateToCursorRoot(vNode, cursorRoot) {
|
|
|
6037
6077
|
*/
|
|
6038
6078
|
function findAndPropagateToBlockingCursor(vNode) {
|
|
6039
6079
|
reusablePath.push(vNode);
|
|
6040
|
-
let current = vNode.
|
|
6080
|
+
let current = vNode.slotParent || vNode.parent;
|
|
6041
6081
|
while (current) {
|
|
6042
6082
|
const currentIsCursor = isCursor(current);
|
|
6043
6083
|
if (currentIsCursor) {
|
|
@@ -6046,7 +6086,7 @@ function findAndPropagateToBlockingCursor(vNode) {
|
|
|
6046
6086
|
return true;
|
|
6047
6087
|
}
|
|
6048
6088
|
reusablePath.push(current);
|
|
6049
|
-
current = current.
|
|
6089
|
+
current = current.slotParent || current.parent;
|
|
6050
6090
|
}
|
|
6051
6091
|
reusablePath.length = 0;
|
|
6052
6092
|
return false;
|
|
@@ -6080,7 +6120,7 @@ function markVNodeDirty(container, vNode, bits, cursorRoot = null) {
|
|
|
6080
6120
|
if ((isRealDirty ? prevDirty & 127 /* ChoreBits.DIRTY_MASK */ : prevDirty) || vNode === cursorRoot) {
|
|
6081
6121
|
return;
|
|
6082
6122
|
}
|
|
6083
|
-
const parent = vNode.
|
|
6123
|
+
const parent = vNode.slotParent || vNode.parent;
|
|
6084
6124
|
// If cursorRoot is provided, propagate up to it
|
|
6085
6125
|
if (cursorRoot && isRealDirty && parent && !parent.dirty) {
|
|
6086
6126
|
propagateToCursorRoot(vNode, cursorRoot);
|
|
@@ -6092,7 +6132,9 @@ function markVNodeDirty(container, vNode, bits, cursorRoot = null) {
|
|
|
6092
6132
|
parent.dirty |= 32 /* ChoreBits.CHILDREN */;
|
|
6093
6133
|
}
|
|
6094
6134
|
parent.dirtyChildren ||= [];
|
|
6095
|
-
parent.dirtyChildren.
|
|
6135
|
+
if (!parent.dirtyChildren.includes(vNode)) {
|
|
6136
|
+
parent.dirtyChildren.push(vNode);
|
|
6137
|
+
}
|
|
6096
6138
|
if (isRealDirty && vNode.dirtyChildren) {
|
|
6097
6139
|
// this node is maybe an ancestor of the current cursor position
|
|
6098
6140
|
// if so we must restart from here
|
|
@@ -6103,7 +6145,7 @@ function markVNodeDirty(container, vNode, bits, cursorRoot = null) {
|
|
|
6103
6145
|
if (cursorPosition) {
|
|
6104
6146
|
// find the ancestor of the cursor position that is current vNode
|
|
6105
6147
|
while (cursorPosition !== cursor) {
|
|
6106
|
-
cursorPosition = cursorPosition.
|
|
6148
|
+
cursorPosition = cursorPosition.slotParent || cursorPosition.parent;
|
|
6107
6149
|
if (cursorPosition === vNode) {
|
|
6108
6150
|
// set cursor position to this node
|
|
6109
6151
|
cursorData.position = vNode;
|
|
@@ -6487,7 +6529,7 @@ function vnode_walkVNode(vNode, callback) {
|
|
|
6487
6529
|
let vCursor = vNode;
|
|
6488
6530
|
// Depth first traversal
|
|
6489
6531
|
if (vnode_isTextVNode(vNode)) {
|
|
6490
|
-
|
|
6532
|
+
callback?.(vNode, null);
|
|
6491
6533
|
return;
|
|
6492
6534
|
}
|
|
6493
6535
|
let vParent = null;
|
|
@@ -6635,11 +6677,6 @@ const vnode_getDomSibling = (vNode, nextDirection, descend) => {
|
|
|
6635
6677
|
}
|
|
6636
6678
|
return null;
|
|
6637
6679
|
};
|
|
6638
|
-
const vnode_ensureInflatedIfText = (journal, vNode) => {
|
|
6639
|
-
if (vnode_isTextVNode(vNode)) {
|
|
6640
|
-
vnode_ensureTextInflated(journal, vNode);
|
|
6641
|
-
}
|
|
6642
|
-
};
|
|
6643
6680
|
const vnode_ensureTextInflated = (journal, vnode) => {
|
|
6644
6681
|
const textVNode = ensureTextVNode(vnode);
|
|
6645
6682
|
const flags = textVNode.flags;
|
|
@@ -6965,7 +7002,9 @@ const vnode_findInsertBefore = (journal, parent, insertBefore) => {
|
|
|
6965
7002
|
else {
|
|
6966
7003
|
adjustedInsertBefore = insertBefore;
|
|
6967
7004
|
}
|
|
6968
|
-
adjustedInsertBefore &&
|
|
7005
|
+
adjustedInsertBefore &&
|
|
7006
|
+
vnode_isTextVNode(adjustedInsertBefore) &&
|
|
7007
|
+
vnode_ensureTextInflated(journal, adjustedInsertBefore);
|
|
6969
7008
|
return adjustedInsertBefore;
|
|
6970
7009
|
};
|
|
6971
7010
|
const vnode_connectSiblings = (parent, vNode, vNext) => {
|
|
@@ -7029,6 +7068,45 @@ const vnode_unlinkFromOldParent = (journal, currentParent, newParent, newChild)
|
|
|
7029
7068
|
vnode_remove(journal, currentParent, newChild, false);
|
|
7030
7069
|
}
|
|
7031
7070
|
};
|
|
7071
|
+
/**
|
|
7072
|
+
* When a projection vnode is about to be repositioned (moved in the vnode tree), its trailing text
|
|
7073
|
+
* node must be inflated before the projection is unlinked from its current sibling chain.
|
|
7074
|
+
* `vnode_ensureTextInflated` relies on `vnode_getDomSibling` to locate adjacent text nodes and
|
|
7075
|
+
* decide which one is "last" (i.e. the one that gets to reuse the shared SSR DOM `Text` node). Once
|
|
7076
|
+
* the projection is unlinked, its `nextSibling` becomes `null`, so `getDomSibling` can no longer
|
|
7077
|
+
* cross the boundary to find a trailing sibling such as an empty-string text node — causing
|
|
7078
|
+
* `isLastNode` to be `true` prematurely and corrupting the shared DOM text node. Inflating the
|
|
7079
|
+
* trailing text node while the siblings are still connected gives it its own fresh DOM node and
|
|
7080
|
+
* avoids the corruption.
|
|
7081
|
+
*
|
|
7082
|
+
* Example:
|
|
7083
|
+
*
|
|
7084
|
+
* ```
|
|
7085
|
+
* <Component>
|
|
7086
|
+
* <button>
|
|
7087
|
+
* <InlineComponent>
|
|
7088
|
+
* <span>
|
|
7089
|
+
* "*"
|
|
7090
|
+
* </span>
|
|
7091
|
+
* </InlineComponent>
|
|
7092
|
+
* <Projection> // <-- this projection when unlinked from the siblings will cause the "test" text node to be considered the last node without inflating it
|
|
7093
|
+
* "test" // <-- this text node is sharing the same DOM node with the ""
|
|
7094
|
+
* </Projection>
|
|
7095
|
+
* "" <-- this text node is sharing the same DOM node with the "test"
|
|
7096
|
+
* </button>
|
|
7097
|
+
* </Component>
|
|
7098
|
+
* ```
|
|
7099
|
+
*/
|
|
7100
|
+
const vnode_inflateProjectionTrailingText = (journal, projection) => {
|
|
7101
|
+
// Follow lastChild through any inner virtual wrappers to reach the actual trailing text node.
|
|
7102
|
+
let last = projection;
|
|
7103
|
+
while (last && vnode_isVirtualVNode(last)) {
|
|
7104
|
+
last = last.lastChild;
|
|
7105
|
+
}
|
|
7106
|
+
if (last && vnode_isTextVNode(last) && (last.flags & 8 /* VNodeFlags.Inflated */) === 0) {
|
|
7107
|
+
vnode_ensureTextInflated(journal, last);
|
|
7108
|
+
}
|
|
7109
|
+
};
|
|
7032
7110
|
const vnode_insertBefore = (journal, parent, newChild, insertBefore) => {
|
|
7033
7111
|
if (vnode_isElementOrTextVNode(newChild)) {
|
|
7034
7112
|
vnode_insertElementBefore(journal, parent, newChild, insertBefore);
|