@qwik.dev/core 2.0.0-beta.24 → 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/bindings/qwik.darwin-arm64.node +0 -0
- package/bindings/qwik.linux-x64-gnu.node +0 -0
- package/bindings/qwik.win32-x64-msvc.node +0 -0
- package/bindings/qwik_wasm_bg.wasm +0 -0
- package/dist/backpatch/package.json +1 -1
- package/dist/build/package.json +1 -1
- package/dist/cli.mjs +2 -2
- package/dist/core-internal.d.ts +6 -4
- package/dist/core.min.mjs +1 -1
- package/dist/core.mjs +251 -134
- package/dist/core.mjs.map +1 -1
- package/dist/core.prod.mjs +210 -140
- 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.d.ts +133 -2
- package/dist/testing/index.mjs +206 -164
- 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]);
|
|
@@ -3068,6 +3070,14 @@ const _jsxSplit = (type, varProps, constProps, children, flags, key, dev) => {
|
|
|
3068
3070
|
}
|
|
3069
3071
|
delete constProps[k];
|
|
3070
3072
|
}
|
|
3073
|
+
else if (k === BIND_CHECKED) {
|
|
3074
|
+
// Set flag, will process after walk
|
|
3075
|
+
bindCheckedSignal = constProps[k];
|
|
3076
|
+
}
|
|
3077
|
+
else if (k === BIND_VALUE) {
|
|
3078
|
+
// Set flag, will process after walk
|
|
3079
|
+
bindValueSignal = constProps[k];
|
|
3080
|
+
}
|
|
3071
3081
|
processedKeys.add(k);
|
|
3072
3082
|
}
|
|
3073
3083
|
}
|
|
@@ -3097,44 +3107,65 @@ const _jsxSplit = (type, varProps, constProps, children, flags, key, dev) => {
|
|
|
3097
3107
|
}
|
|
3098
3108
|
processedKeys.add(k);
|
|
3099
3109
|
}
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3110
|
+
}
|
|
3111
|
+
// Handle bind:* - only in varProps, bind:* should be moved to varProps
|
|
3112
|
+
if (bindCheckedSignal || bindValueSignal) {
|
|
3113
|
+
if (!varPropsCopied) {
|
|
3114
|
+
varProps = { ...varProps };
|
|
3115
|
+
varPropsCopied = true;
|
|
3116
|
+
}
|
|
3117
|
+
varProps ||= {};
|
|
3118
|
+
if (bindCheckedSignal) {
|
|
3119
|
+
// Delete from both varProps and constProps if present
|
|
3120
|
+
if (varProps && _hasOwnProperty$1.call(varProps, BIND_CHECKED)) {
|
|
3107
3121
|
delete varProps[BIND_CHECKED];
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3122
|
+
}
|
|
3123
|
+
if (constProps && _hasOwnProperty$1.call(constProps, BIND_CHECKED)) {
|
|
3124
|
+
if (!constPropsCopied) {
|
|
3125
|
+
constProps = { ...constProps };
|
|
3126
|
+
constPropsCopied = true;
|
|
3127
|
+
}
|
|
3128
|
+
delete constProps[BIND_CHECKED];
|
|
3129
|
+
}
|
|
3130
|
+
varProps.checked = bindCheckedSignal;
|
|
3131
|
+
const handler = createQRL(null, '_chk', _chk, null, [bindCheckedSignal]);
|
|
3132
|
+
// Move q-e:input from constProps if it exists
|
|
3133
|
+
if (constProps && _hasOwnProperty$1.call(constProps, 'q-e:input')) {
|
|
3134
|
+
if (!constPropsCopied) {
|
|
3135
|
+
constProps = { ...constProps };
|
|
3136
|
+
constPropsCopied = true;
|
|
3119
3137
|
}
|
|
3120
|
-
|
|
3138
|
+
const existingHandler = constProps['q-e:input'];
|
|
3139
|
+
delete constProps['q-e:input'];
|
|
3140
|
+
toSort = mergeHandlers(varProps, 'q-e:input', existingHandler) || toSort;
|
|
3121
3141
|
}
|
|
3122
|
-
|
|
3142
|
+
toSort = mergeHandlers(varProps, 'q-e:input', handler) || toSort;
|
|
3143
|
+
}
|
|
3144
|
+
else if (bindValueSignal) {
|
|
3145
|
+
// Delete from both varProps and constProps if present
|
|
3146
|
+
if (varProps && _hasOwnProperty$1.call(varProps, BIND_VALUE)) {
|
|
3123
3147
|
delete varProps[BIND_VALUE];
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
constProps = { ...constProps };
|
|
3130
|
-
constPropsCopied = true;
|
|
3131
|
-
}
|
|
3132
|
-
const existingHandler = constProps['q-e:input'];
|
|
3133
|
-
delete constProps['q-e:input'];
|
|
3134
|
-
toSort = mergeHandlers(varProps, 'q-e:input', existingHandler) || toSort;
|
|
3148
|
+
}
|
|
3149
|
+
if (constProps && _hasOwnProperty$1.call(constProps, BIND_VALUE)) {
|
|
3150
|
+
if (!constPropsCopied) {
|
|
3151
|
+
constProps = { ...constProps };
|
|
3152
|
+
constPropsCopied = true;
|
|
3135
3153
|
}
|
|
3136
|
-
|
|
3154
|
+
delete constProps[BIND_VALUE];
|
|
3137
3155
|
}
|
|
3156
|
+
varProps.value = bindValueSignal;
|
|
3157
|
+
const handler = createQRL(null, '_val', _val, null, [bindValueSignal]);
|
|
3158
|
+
// Move q-e:input from constProps if it exists
|
|
3159
|
+
if (constProps && _hasOwnProperty$1.call(constProps, 'q-e:input')) {
|
|
3160
|
+
if (!constPropsCopied) {
|
|
3161
|
+
constProps = { ...constProps };
|
|
3162
|
+
constPropsCopied = true;
|
|
3163
|
+
}
|
|
3164
|
+
const existingHandler = constProps['q-e:input'];
|
|
3165
|
+
delete constProps['q-e:input'];
|
|
3166
|
+
toSort = mergeHandlers(varProps, 'q-e:input', existingHandler) || toSort;
|
|
3167
|
+
}
|
|
3168
|
+
toSort = mergeHandlers(varProps, 'q-e:input', handler) || toSort;
|
|
3138
3169
|
}
|
|
3139
3170
|
}
|
|
3140
3171
|
// Transform className -> class
|
|
@@ -3676,7 +3707,14 @@ const cleanupDestroyable = (destroyable) => {
|
|
|
3676
3707
|
* This safely calls an event handler, handling errors and retrying on thrown Promises, and
|
|
3677
3708
|
* providing extra parameters defined on the elements as arguments (used for loop optimization)
|
|
3678
3709
|
*/
|
|
3679
|
-
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
|
+
}
|
|
3680
3718
|
const container = ctx.$container$;
|
|
3681
3719
|
const hostElement = ctx.$hostElement$;
|
|
3682
3720
|
vnode_ensureElementInflated(container, hostElement);
|
|
@@ -3712,6 +3750,10 @@ function runEventHandlerQRL(handler, event, element, ctx = newInvokeContextFromD
|
|
|
3712
3750
|
* @internal
|
|
3713
3751
|
*/
|
|
3714
3752
|
function _run(event, element) {
|
|
3753
|
+
if (!element.isConnected) {
|
|
3754
|
+
// ignore events on disconnected elements, this can happen when the event is triggered while the element is being removed
|
|
3755
|
+
return;
|
|
3756
|
+
}
|
|
3715
3757
|
const ctx = newInvokeContextFromDOM(event, element);
|
|
3716
3758
|
if (typeof this === 'string') {
|
|
3717
3759
|
setCaptures(deserializeCaptures(ctx.$container$, this));
|
|
@@ -3737,8 +3779,8 @@ function setAttribute(journal, vnode, key, value, scopedStyleIdPrefix, originalV
|
|
|
3737
3779
|
vnode_setProp(vnode, key, originalValue);
|
|
3738
3780
|
addVNodeOperation(journal, createSetAttributeOperation(vnode.node, key, value, scopedStyleIdPrefix, (vnode.flags & 512 /* VNodeFlags.NS_svg */) !== 0));
|
|
3739
3781
|
}
|
|
3740
|
-
|
|
3741
|
-
|
|
3782
|
+
function createDiffContext(container, journal, cursor, scopedStyleIdPrefix) {
|
|
3783
|
+
return {
|
|
3742
3784
|
container,
|
|
3743
3785
|
journal,
|
|
3744
3786
|
cursor,
|
|
@@ -3769,6 +3811,9 @@ const vnode_diff = (container, journal, jsxNode, vStartNode, cursor, scopedStyle
|
|
|
3769
3811
|
}),
|
|
3770
3812
|
},
|
|
3771
3813
|
};
|
|
3814
|
+
}
|
|
3815
|
+
const vnode_diff = (container, journal, jsxNode, vStartNode, cursor, scopedStyleIdPrefix) => {
|
|
3816
|
+
const diffContext = createDiffContext(container, journal, cursor, scopedStyleIdPrefix);
|
|
3772
3817
|
////////////////////////////////
|
|
3773
3818
|
diff(diffContext, jsxNode, vStartNode);
|
|
3774
3819
|
const result = drainAsyncQueue(diffContext);
|
|
@@ -4123,6 +4168,7 @@ function expectSlot(diffContext) {
|
|
|
4123
4168
|
vHost && vnode_setProp(vHost, slotNameKey, diffContext.vNewNode);
|
|
4124
4169
|
isDev &&
|
|
4125
4170
|
vnode_setProp(diffContext.vNewNode, DEBUG_TYPE, "P" /* VirtualType.Projection */);
|
|
4171
|
+
vnode_inflateProjectionTrailingText(diffContext.journal, diffContext.vNewNode);
|
|
4126
4172
|
vnode_insertBefore(diffContext.journal, diffContext.vParent, diffContext.vNewNode, diffContext.vCurrent && getInsertBefore(diffContext));
|
|
4127
4173
|
// If we moved from a q:template and it's now empty, remove it
|
|
4128
4174
|
if (oldParent &&
|
|
@@ -4673,26 +4719,34 @@ function expectComponent(diffContext, component) {
|
|
|
4673
4719
|
const vNodeLookupKey = getKey(host) || vNodeComponentHash;
|
|
4674
4720
|
const lookupKeysAreEqual = lookupKey === vNodeLookupKey;
|
|
4675
4721
|
const hashesAreEqual = componentHash === vNodeComponentHash;
|
|
4676
|
-
if (
|
|
4677
|
-
if (
|
|
4722
|
+
if (lookupKeysAreEqual) {
|
|
4723
|
+
if (hashesAreEqual) {
|
|
4724
|
+
deleteFromSideBuffer(diffContext, null, lookupKey);
|
|
4725
|
+
}
|
|
4726
|
+
else {
|
|
4678
4727
|
insertNewComponent(diffContext, host, componentQRL, jsxProps);
|
|
4728
|
+
host = diffContext.vNewNode;
|
|
4679
4729
|
shouldRender = true;
|
|
4680
4730
|
}
|
|
4681
|
-
host = (diffContext.vNewNode || diffContext.vCurrent);
|
|
4682
|
-
}
|
|
4683
|
-
else if (!hashesAreEqual || !jsxNode.key) {
|
|
4684
|
-
insertNewComponent(diffContext, host, componentQRL, jsxProps);
|
|
4685
|
-
host = diffContext.vNewNode;
|
|
4686
|
-
shouldRender = true;
|
|
4687
4731
|
}
|
|
4688
4732
|
else {
|
|
4689
|
-
|
|
4690
|
-
|
|
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);
|
|
4691
4738
|
}
|
|
4692
4739
|
if (host) {
|
|
4693
4740
|
const vNodeProps = vnode_getProp(host, ELEMENT_PROPS, diffContext.container.$getObjectById$);
|
|
4694
4741
|
if (!shouldRender) {
|
|
4695
|
-
|
|
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;
|
|
4696
4750
|
}
|
|
4697
4751
|
if (shouldRender) {
|
|
4698
4752
|
// Assign the new QRL instance to the host.
|
|
@@ -4714,7 +4768,7 @@ function expectComponent(diffContext, component) {
|
|
|
4714
4768
|
const lookupKeysAreEqual = lookupKey === vNodeLookupKey;
|
|
4715
4769
|
const vNodeComponentHash = getComponentHash(host, diffContext.container.$getObjectById$);
|
|
4716
4770
|
const isInlineComponent = vNodeComponentHash == null;
|
|
4717
|
-
if ((host && !isInlineComponent) ||
|
|
4771
|
+
if ((host && !isInlineComponent) || !host) {
|
|
4718
4772
|
insertNewInlineComponent(diffContext);
|
|
4719
4773
|
host = diffContext.vNewNode;
|
|
4720
4774
|
}
|
|
@@ -5706,7 +5760,7 @@ function walkCursor(cursor, options) {
|
|
|
5706
5760
|
return;
|
|
5707
5761
|
}
|
|
5708
5762
|
// Check time budget (only for DOM, not SSR)
|
|
5709
|
-
if (
|
|
5763
|
+
if (isBrowser) {
|
|
5710
5764
|
const elapsed = performance.now() - startTime;
|
|
5711
5765
|
if (elapsed >= timeBudget) {
|
|
5712
5766
|
// Schedule continuation as macrotask to actually yield to browser
|
|
@@ -5748,10 +5802,27 @@ function tryDescendDirtyChildren(container, cursorData, currentVNode, cursor) {
|
|
|
5748
5802
|
return null;
|
|
5749
5803
|
}
|
|
5750
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;
|
|
5751
5821
|
currentVNode.nextDirtyChildIndex = 0;
|
|
5752
5822
|
const next = getNextVNode(dirtyChildren[0], cursor);
|
|
5753
5823
|
setCursorPosition(container, cursorData, next);
|
|
5754
5824
|
return next;
|
|
5825
|
+
// return null;
|
|
5755
5826
|
}
|
|
5756
5827
|
/**
|
|
5757
5828
|
* Partitions dirtyChildren array so non-projections come first, projections last. Uses in-place
|
|
@@ -5780,14 +5851,14 @@ function getNextVNode(vNode, cursor) {
|
|
|
5780
5851
|
}
|
|
5781
5852
|
return null;
|
|
5782
5853
|
}
|
|
5783
|
-
// Prefer
|
|
5854
|
+
// Prefer slotParent (logical owner) for Projections, fall back to parent
|
|
5784
5855
|
let parent = null;
|
|
5785
|
-
if (vNode.
|
|
5786
|
-
parent = vNode.parent;
|
|
5787
|
-
}
|
|
5788
|
-
else if (vNode.slotParent && vNode.slotParent.dirty & 32 /* ChoreBits.CHILDREN */) {
|
|
5856
|
+
if (vNode.slotParent && vNode.slotParent.dirty & 32 /* ChoreBits.CHILDREN */) {
|
|
5789
5857
|
parent = vNode.slotParent;
|
|
5790
5858
|
}
|
|
5859
|
+
else if (vNode.parent && vNode.parent.dirty & 32 /* ChoreBits.CHILDREN */) {
|
|
5860
|
+
parent = vNode.parent;
|
|
5861
|
+
}
|
|
5791
5862
|
if (!parent) {
|
|
5792
5863
|
if (cursor.dirty & 127 /* ChoreBits.DIRTY_MASK */) {
|
|
5793
5864
|
return cursor;
|
|
@@ -5959,7 +6030,9 @@ function propagatePath(target) {
|
|
|
5959
6030
|
const parent = reusablePath[i + 1] || target;
|
|
5960
6031
|
parent.dirty |= 32 /* ChoreBits.CHILDREN */;
|
|
5961
6032
|
parent.dirtyChildren ||= [];
|
|
5962
|
-
parent.dirtyChildren.
|
|
6033
|
+
if (!parent.dirtyChildren.includes(child)) {
|
|
6034
|
+
parent.dirtyChildren.push(child);
|
|
6035
|
+
}
|
|
5963
6036
|
}
|
|
5964
6037
|
}
|
|
5965
6038
|
/**
|
|
@@ -5968,7 +6041,7 @@ function propagatePath(target) {
|
|
|
5968
6041
|
*/
|
|
5969
6042
|
function propagateToCursorRoot(vNode, cursorRoot) {
|
|
5970
6043
|
reusablePath.push(vNode);
|
|
5971
|
-
let current = vNode.
|
|
6044
|
+
let current = vNode.slotParent || vNode.parent;
|
|
5972
6045
|
while (current) {
|
|
5973
6046
|
const isDirty = current.dirty & 127 /* ChoreBits.DIRTY_MASK */;
|
|
5974
6047
|
const currentIsCursor = isCursor(current);
|
|
@@ -5993,7 +6066,7 @@ function propagateToCursorRoot(vNode, cursorRoot) {
|
|
|
5993
6066
|
}
|
|
5994
6067
|
}
|
|
5995
6068
|
reusablePath.push(current);
|
|
5996
|
-
current = current.
|
|
6069
|
+
current = current.slotParent || current.parent;
|
|
5997
6070
|
}
|
|
5998
6071
|
reusablePath.length = 0;
|
|
5999
6072
|
throwErrorAndStop('Cursor root not found in current path!');
|
|
@@ -6004,7 +6077,7 @@ function propagateToCursorRoot(vNode, cursorRoot) {
|
|
|
6004
6077
|
*/
|
|
6005
6078
|
function findAndPropagateToBlockingCursor(vNode) {
|
|
6006
6079
|
reusablePath.push(vNode);
|
|
6007
|
-
let current = vNode.
|
|
6080
|
+
let current = vNode.slotParent || vNode.parent;
|
|
6008
6081
|
while (current) {
|
|
6009
6082
|
const currentIsCursor = isCursor(current);
|
|
6010
6083
|
if (currentIsCursor) {
|
|
@@ -6013,7 +6086,7 @@ function findAndPropagateToBlockingCursor(vNode) {
|
|
|
6013
6086
|
return true;
|
|
6014
6087
|
}
|
|
6015
6088
|
reusablePath.push(current);
|
|
6016
|
-
current = current.
|
|
6089
|
+
current = current.slotParent || current.parent;
|
|
6017
6090
|
}
|
|
6018
6091
|
reusablePath.length = 0;
|
|
6019
6092
|
return false;
|
|
@@ -6047,7 +6120,7 @@ function markVNodeDirty(container, vNode, bits, cursorRoot = null) {
|
|
|
6047
6120
|
if ((isRealDirty ? prevDirty & 127 /* ChoreBits.DIRTY_MASK */ : prevDirty) || vNode === cursorRoot) {
|
|
6048
6121
|
return;
|
|
6049
6122
|
}
|
|
6050
|
-
const parent = vNode.
|
|
6123
|
+
const parent = vNode.slotParent || vNode.parent;
|
|
6051
6124
|
// If cursorRoot is provided, propagate up to it
|
|
6052
6125
|
if (cursorRoot && isRealDirty && parent && !parent.dirty) {
|
|
6053
6126
|
propagateToCursorRoot(vNode, cursorRoot);
|
|
@@ -6059,7 +6132,9 @@ function markVNodeDirty(container, vNode, bits, cursorRoot = null) {
|
|
|
6059
6132
|
parent.dirty |= 32 /* ChoreBits.CHILDREN */;
|
|
6060
6133
|
}
|
|
6061
6134
|
parent.dirtyChildren ||= [];
|
|
6062
|
-
parent.dirtyChildren.
|
|
6135
|
+
if (!parent.dirtyChildren.includes(vNode)) {
|
|
6136
|
+
parent.dirtyChildren.push(vNode);
|
|
6137
|
+
}
|
|
6063
6138
|
if (isRealDirty && vNode.dirtyChildren) {
|
|
6064
6139
|
// this node is maybe an ancestor of the current cursor position
|
|
6065
6140
|
// if so we must restart from here
|
|
@@ -6070,7 +6145,7 @@ function markVNodeDirty(container, vNode, bits, cursorRoot = null) {
|
|
|
6070
6145
|
if (cursorPosition) {
|
|
6071
6146
|
// find the ancestor of the cursor position that is current vNode
|
|
6072
6147
|
while (cursorPosition !== cursor) {
|
|
6073
|
-
cursorPosition = cursorPosition.
|
|
6148
|
+
cursorPosition = cursorPosition.slotParent || cursorPosition.parent;
|
|
6074
6149
|
if (cursorPosition === vNode) {
|
|
6075
6150
|
// set cursor position to this node
|
|
6076
6151
|
cursorData.position = vNode;
|
|
@@ -6454,7 +6529,7 @@ function vnode_walkVNode(vNode, callback) {
|
|
|
6454
6529
|
let vCursor = vNode;
|
|
6455
6530
|
// Depth first traversal
|
|
6456
6531
|
if (vnode_isTextVNode(vNode)) {
|
|
6457
|
-
|
|
6532
|
+
callback?.(vNode, null);
|
|
6458
6533
|
return;
|
|
6459
6534
|
}
|
|
6460
6535
|
let vParent = null;
|
|
@@ -6602,11 +6677,6 @@ const vnode_getDomSibling = (vNode, nextDirection, descend) => {
|
|
|
6602
6677
|
}
|
|
6603
6678
|
return null;
|
|
6604
6679
|
};
|
|
6605
|
-
const vnode_ensureInflatedIfText = (journal, vNode) => {
|
|
6606
|
-
if (vnode_isTextVNode(vNode)) {
|
|
6607
|
-
vnode_ensureTextInflated(journal, vNode);
|
|
6608
|
-
}
|
|
6609
|
-
};
|
|
6610
6680
|
const vnode_ensureTextInflated = (journal, vnode) => {
|
|
6611
6681
|
const textVNode = ensureTextVNode(vnode);
|
|
6612
6682
|
const flags = textVNode.flags;
|
|
@@ -6932,7 +7002,9 @@ const vnode_findInsertBefore = (journal, parent, insertBefore) => {
|
|
|
6932
7002
|
else {
|
|
6933
7003
|
adjustedInsertBefore = insertBefore;
|
|
6934
7004
|
}
|
|
6935
|
-
adjustedInsertBefore &&
|
|
7005
|
+
adjustedInsertBefore &&
|
|
7006
|
+
vnode_isTextVNode(adjustedInsertBefore) &&
|
|
7007
|
+
vnode_ensureTextInflated(journal, adjustedInsertBefore);
|
|
6936
7008
|
return adjustedInsertBefore;
|
|
6937
7009
|
};
|
|
6938
7010
|
const vnode_connectSiblings = (parent, vNode, vNext) => {
|
|
@@ -6996,6 +7068,45 @@ const vnode_unlinkFromOldParent = (journal, currentParent, newParent, newChild)
|
|
|
6996
7068
|
vnode_remove(journal, currentParent, newChild, false);
|
|
6997
7069
|
}
|
|
6998
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
|
+
};
|
|
6999
7110
|
const vnode_insertBefore = (journal, parent, newChild, insertBefore) => {
|
|
7000
7111
|
if (vnode_isElementOrTextVNode(newChild)) {
|
|
7001
7112
|
vnode_insertElementBefore(journal, parent, newChild, insertBefore);
|
|
@@ -7619,6 +7730,15 @@ function materializeFromVNodeData(vParent, vData, element, child) {
|
|
|
7619
7730
|
vnode_ensureElementKeyInflated(elementVNode);
|
|
7620
7731
|
addVNode(elementVNode);
|
|
7621
7732
|
child = fastNextSibling(child);
|
|
7733
|
+
while (
|
|
7734
|
+
// skip only elements, not text nodes
|
|
7735
|
+
isElement(child) &&
|
|
7736
|
+
shouldSkipElement(child)) {
|
|
7737
|
+
child = fastNextSibling(child);
|
|
7738
|
+
if (!child && value > 0) {
|
|
7739
|
+
throw qError(27 /* QError.materializeVNodeDataError */, [vData, peek(), nextToConsumeIdx]);
|
|
7740
|
+
}
|
|
7741
|
+
}
|
|
7622
7742
|
}
|
|
7623
7743
|
// collect the elements;
|
|
7624
7744
|
}
|
|
@@ -9010,12 +9130,7 @@ class Serializer {
|
|
|
9010
9130
|
]);
|
|
9011
9131
|
}
|
|
9012
9132
|
else if (value instanceof EffectSubscription) {
|
|
9013
|
-
this.output(32 /* TypeIds.EffectSubscription */, [
|
|
9014
|
-
value.consumer,
|
|
9015
|
-
value.property,
|
|
9016
|
-
value.backRef,
|
|
9017
|
-
value.data,
|
|
9018
|
-
]);
|
|
9133
|
+
this.output(32 /* TypeIds.EffectSubscription */, [value.consumer, value.property, value.data]);
|
|
9019
9134
|
}
|
|
9020
9135
|
else if (isStore(value)) {
|
|
9021
9136
|
const storeHandler = getStoreHandler(value);
|
|
@@ -9083,19 +9198,13 @@ class Serializer {
|
|
|
9083
9198
|
this.output(2 /* TypeIds.ForwardRef */, forwardRefId);
|
|
9084
9199
|
}
|
|
9085
9200
|
else {
|
|
9086
|
-
this.output(26 /* TypeIds.SerializerSignal */, [
|
|
9087
|
-
value.$computeQrl$,
|
|
9088
|
-
filterEffectBackRefs(value[_EFFECT_BACK_REF]),
|
|
9089
|
-
value.$effects$,
|
|
9090
|
-
maybeValue,
|
|
9091
|
-
]);
|
|
9201
|
+
this.output(26 /* TypeIds.SerializerSignal */, [value.$computeQrl$, value.$effects$, maybeValue]);
|
|
9092
9202
|
}
|
|
9093
9203
|
return;
|
|
9094
9204
|
}
|
|
9095
9205
|
if (value instanceof WrappedSignalImpl) {
|
|
9096
9206
|
this.output(23 /* TypeIds.WrappedSignal */, [
|
|
9097
9207
|
...serializeWrappingFn(this.$serializationContext$, value),
|
|
9098
|
-
filterEffectBackRefs(value[_EFFECT_BACK_REF]),
|
|
9099
9208
|
value.$flags$,
|
|
9100
9209
|
value.$hostElement$,
|
|
9101
9210
|
...(value.$effects$ || []),
|
|
@@ -9123,11 +9232,7 @@ class Serializer {
|
|
|
9123
9232
|
else if (shouldNeverSerialize) {
|
|
9124
9233
|
v = NEEDS_COMPUTATION;
|
|
9125
9234
|
}
|
|
9126
|
-
const out = [
|
|
9127
|
-
value.$computeQrl$,
|
|
9128
|
-
filterEffectBackRefs(value[_EFFECT_BACK_REF]),
|
|
9129
|
-
value.$effects$,
|
|
9130
|
-
];
|
|
9235
|
+
const out = [value.$computeQrl$, value.$effects$];
|
|
9131
9236
|
if (isAsync) {
|
|
9132
9237
|
// After SSR, the signal is never loading, so no need to send it
|
|
9133
9238
|
out.push(value.$loadingEffects$, value.$errorEffects$, value.$untrackedError$);
|
|
@@ -9254,14 +9359,7 @@ class Serializer {
|
|
|
9254
9359
|
this.output(29 /* TypeIds.JSXNode */, out);
|
|
9255
9360
|
}
|
|
9256
9361
|
else if (value instanceof Task) {
|
|
9257
|
-
const out = [
|
|
9258
|
-
value.$qrl$,
|
|
9259
|
-
value.$flags$,
|
|
9260
|
-
value.$index$,
|
|
9261
|
-
value.$el$,
|
|
9262
|
-
value[_EFFECT_BACK_REF],
|
|
9263
|
-
value.$state$,
|
|
9264
|
-
];
|
|
9362
|
+
const out = [value.$qrl$, value.$flags$, value.$index$, value.$el$, value.$state$];
|
|
9265
9363
|
while (out[out.length - 1] === undefined) {
|
|
9266
9364
|
out.pop();
|
|
9267
9365
|
}
|
|
@@ -9460,18 +9558,6 @@ function serializeWrappingFn(serializationContext, value) {
|
|
|
9460
9558
|
const syncFnId = serializationContext.$addSyncFn$(value.$funcStr$, value.$args$.length, value.$func$);
|
|
9461
9559
|
return [syncFnId, value.$args$];
|
|
9462
9560
|
}
|
|
9463
|
-
function filterEffectBackRefs(effectBackRef) {
|
|
9464
|
-
let effectBackRefToSerialize = undefined;
|
|
9465
|
-
if (effectBackRef) {
|
|
9466
|
-
for (const [effectProp, effect] of effectBackRef) {
|
|
9467
|
-
if (effect.backRef) {
|
|
9468
|
-
effectBackRefToSerialize ||= new Map();
|
|
9469
|
-
effectBackRefToSerialize.set(effectProp, effect);
|
|
9470
|
-
}
|
|
9471
|
-
}
|
|
9472
|
-
}
|
|
9473
|
-
return effectBackRefToSerialize;
|
|
9474
|
-
}
|
|
9475
9561
|
function tryGetBackRefs(props) {
|
|
9476
9562
|
return Object.prototype.hasOwnProperty.call(props, QBackRefs)
|
|
9477
9563
|
? props[QBackRefs]
|
|
@@ -10195,8 +10281,7 @@ const inflate = (container, target, typeId, data) => {
|
|
|
10195
10281
|
task.$flags$ = v[1];
|
|
10196
10282
|
task.$index$ = v[2];
|
|
10197
10283
|
task.$el$ = v[3];
|
|
10198
|
-
task
|
|
10199
|
-
task.$state$ = v[5];
|
|
10284
|
+
task.$state$ = v[4];
|
|
10200
10285
|
break;
|
|
10201
10286
|
case 21 /* TypeIds.Component */:
|
|
10202
10287
|
target[SERIALIZABLE_STATE][0] = data[0];
|
|
@@ -10217,6 +10302,7 @@ const inflate = (container, target, typeId, data) => {
|
|
|
10217
10302
|
const storeHandler = getStoreHandler(target);
|
|
10218
10303
|
storeHandler.$flags$ = flags;
|
|
10219
10304
|
storeHandler.$effects$ = effects;
|
|
10305
|
+
restoreEffectBackRefForEffectsMap(storeHandler.$effects$, store);
|
|
10220
10306
|
break;
|
|
10221
10307
|
}
|
|
10222
10308
|
case 22 /* TypeIds.Signal */: {
|
|
@@ -10224,6 +10310,7 @@ const inflate = (container, target, typeId, data) => {
|
|
|
10224
10310
|
const d = data;
|
|
10225
10311
|
signal.$untrackedValue$ = d[0];
|
|
10226
10312
|
signal.$effects$ = new Set(d.slice(1));
|
|
10313
|
+
restoreEffectBackRefForEffects(signal.$effects$, signal);
|
|
10227
10314
|
break;
|
|
10228
10315
|
}
|
|
10229
10316
|
case 23 /* TypeIds.WrappedSignal */: {
|
|
@@ -10231,41 +10318,43 @@ const inflate = (container, target, typeId, data) => {
|
|
|
10231
10318
|
const d = data;
|
|
10232
10319
|
signal.$func$ = container.getSyncFn(d[0]);
|
|
10233
10320
|
signal.$args$ = d[1];
|
|
10234
|
-
signal[_EFFECT_BACK_REF] = d[2];
|
|
10235
10321
|
signal.$untrackedValue$ = NEEDS_COMPUTATION;
|
|
10236
|
-
signal.$flags$ = d[
|
|
10322
|
+
signal.$flags$ = d[2];
|
|
10237
10323
|
signal.$flags$ |= 1 /* SignalFlags.INVALID */;
|
|
10238
|
-
signal.$hostElement$ = d[
|
|
10239
|
-
signal.$effects$ = new Set(d.slice(
|
|
10324
|
+
signal.$hostElement$ = d[3];
|
|
10325
|
+
signal.$effects$ = new Set(d.slice(4));
|
|
10240
10326
|
inflateWrappedSignalValue(signal);
|
|
10327
|
+
restoreEffectBackRefForEffects(signal.$effects$, signal);
|
|
10241
10328
|
break;
|
|
10242
10329
|
}
|
|
10243
10330
|
case 25 /* TypeIds.AsyncSignal */: {
|
|
10244
10331
|
const asyncSignal = target;
|
|
10245
10332
|
const d = data;
|
|
10246
10333
|
asyncSignal.$computeQrl$ = d[0];
|
|
10247
|
-
asyncSignal
|
|
10248
|
-
asyncSignal.$
|
|
10249
|
-
asyncSignal.$
|
|
10250
|
-
asyncSignal.$
|
|
10251
|
-
asyncSignal.$
|
|
10252
|
-
asyncSignal.$flags$ = d[6] ?? 0;
|
|
10334
|
+
asyncSignal.$effects$ = new Set(d[1]);
|
|
10335
|
+
asyncSignal.$loadingEffects$ = new Set(d[2]);
|
|
10336
|
+
asyncSignal.$errorEffects$ = new Set(d[3]);
|
|
10337
|
+
asyncSignal.$untrackedError$ = d[4];
|
|
10338
|
+
asyncSignal.$flags$ = d[5] ?? 0;
|
|
10253
10339
|
if (asyncSignal.$flags$ & 64 /* AsyncSignalFlags.CLIENT_ONLY */) {
|
|
10254
10340
|
// If it's client only, it was serialized because it pretended to be loading
|
|
10255
10341
|
asyncSignal.$untrackedLoading$ = true;
|
|
10256
10342
|
}
|
|
10257
|
-
const hasValue = d.length >
|
|
10343
|
+
const hasValue = d.length > 6;
|
|
10258
10344
|
if (hasValue) {
|
|
10259
|
-
asyncSignal.$untrackedValue$ = d[
|
|
10345
|
+
asyncSignal.$untrackedValue$ = d[6];
|
|
10260
10346
|
}
|
|
10261
10347
|
// can happen when never serialize etc
|
|
10262
10348
|
if (asyncSignal.$untrackedValue$ === NEEDS_COMPUTATION) {
|
|
10263
10349
|
asyncSignal.$flags$ |= 1 /* SignalFlags.INVALID */;
|
|
10264
10350
|
}
|
|
10265
10351
|
// Note, we use the setter so that it schedules polling if needed
|
|
10266
|
-
asyncSignal.interval = (d[
|
|
10267
|
-
asyncSignal.$concurrency$ = (d[
|
|
10268
|
-
asyncSignal.$timeoutMs$ = (d[
|
|
10352
|
+
asyncSignal.interval = (d[7] ?? 0);
|
|
10353
|
+
asyncSignal.$concurrency$ = (d[8] ?? 1);
|
|
10354
|
+
asyncSignal.$timeoutMs$ = (d[9] ?? 0);
|
|
10355
|
+
restoreEffectBackRefForEffects(asyncSignal.$effects$, asyncSignal);
|
|
10356
|
+
restoreEffectBackRefForEffects(asyncSignal.$loadingEffects$, asyncSignal);
|
|
10357
|
+
restoreEffectBackRefForEffects(asyncSignal.$errorEffects$, asyncSignal);
|
|
10269
10358
|
break;
|
|
10270
10359
|
}
|
|
10271
10360
|
// Inflating a SerializerSignal is the same as inflating a ComputedSignal
|
|
@@ -10283,19 +10372,19 @@ const inflate = (container, target, typeId, data) => {
|
|
|
10283
10372
|
// ignore preload errors
|
|
10284
10373
|
});
|
|
10285
10374
|
loading = loading.finally(() => p);
|
|
10286
|
-
|
|
10287
|
-
|
|
10288
|
-
computed.$effects$ = new Set(d[2]);
|
|
10375
|
+
if (d[1]) {
|
|
10376
|
+
computed.$effects$ = new Set(d[1]);
|
|
10289
10377
|
}
|
|
10290
|
-
const hasValue = d.length >
|
|
10378
|
+
const hasValue = d.length > 2;
|
|
10291
10379
|
if (hasValue) {
|
|
10292
|
-
computed.$untrackedValue$ = d[
|
|
10380
|
+
computed.$untrackedValue$ = d[2];
|
|
10293
10381
|
}
|
|
10294
10382
|
if (typeId !== 26 /* TypeIds.SerializerSignal */ && computed.$untrackedValue$ !== NEEDS_COMPUTATION) {
|
|
10295
10383
|
// If we have a value after SSR, it will always be mean the signal was not invalid
|
|
10296
10384
|
// The serialized signal is always left invalid so it can recreate the custom object
|
|
10297
10385
|
computed.$flags$ &= -2 /* SignalFlags.INVALID */;
|
|
10298
10386
|
}
|
|
10387
|
+
restoreEffectBackRefForEffects(computed.$effects$, computed);
|
|
10299
10388
|
break;
|
|
10300
10389
|
}
|
|
10301
10390
|
case 15 /* TypeIds.Error */: {
|
|
@@ -10370,7 +10459,9 @@ const inflate = (container, target, typeId, data) => {
|
|
|
10370
10459
|
owner._proxy = propsProxy;
|
|
10371
10460
|
}
|
|
10372
10461
|
propsProxy[_OWNER] = owner;
|
|
10373
|
-
|
|
10462
|
+
const propsHandler = propsProxy[_PROPS_HANDLER];
|
|
10463
|
+
propsHandler.$effects$ = d[3];
|
|
10464
|
+
restoreEffectBackRefForEffectsMap(propsHandler.$effects$, propsProxy);
|
|
10374
10465
|
break;
|
|
10375
10466
|
case 31 /* TypeIds.SubscriptionData */: {
|
|
10376
10467
|
const effectData = target;
|
|
@@ -10383,14 +10474,15 @@ const inflate = (container, target, typeId, data) => {
|
|
|
10383
10474
|
const d = data;
|
|
10384
10475
|
effectSub.consumer = d[0];
|
|
10385
10476
|
effectSub.property = d[1];
|
|
10386
|
-
effectSub.
|
|
10387
|
-
effectSub
|
|
10477
|
+
effectSub.data = d[2];
|
|
10478
|
+
restoreEffectBackRefForConsumer(effectSub);
|
|
10388
10479
|
break;
|
|
10389
10480
|
}
|
|
10390
10481
|
default:
|
|
10391
10482
|
throw qError(16 /* QError.serializeErrorNotImplemented */, [typeId]);
|
|
10392
10483
|
}
|
|
10393
|
-
};
|
|
10484
|
+
};
|
|
10485
|
+
/**
|
|
10394
10486
|
* Restores an array eagerly. If you need it lazily, use `deserializeData(container, TypeIds.Array,
|
|
10395
10487
|
* array)` instead
|
|
10396
10488
|
*/
|
|
@@ -10441,6 +10533,31 @@ function inflateWrappedSignalValue(signal) {
|
|
|
10441
10533
|
}
|
|
10442
10534
|
}
|
|
10443
10535
|
}
|
|
10536
|
+
function restoreEffectBackRefForConsumer(effect) {
|
|
10537
|
+
const isServerSide = import.meta.env.TEST ? isServerPlatform() : isServer;
|
|
10538
|
+
const consumerBackRef = effect.consumer;
|
|
10539
|
+
if (isServerSide && !consumerBackRef) {
|
|
10540
|
+
// on browser, we don't serialize for example VNodes, so then on server side we don't have consumer
|
|
10541
|
+
return;
|
|
10542
|
+
}
|
|
10543
|
+
consumerBackRef[_EFFECT_BACK_REF] ||= new Map();
|
|
10544
|
+
consumerBackRef[_EFFECT_BACK_REF].set(effect.property, effect);
|
|
10545
|
+
}
|
|
10546
|
+
function restoreEffectBackRefForEffects(effects, consumer) {
|
|
10547
|
+
if (effects) {
|
|
10548
|
+
for (const effect of effects) {
|
|
10549
|
+
effect.backRef ||= new Set();
|
|
10550
|
+
effect.backRef.add(consumer);
|
|
10551
|
+
}
|
|
10552
|
+
}
|
|
10553
|
+
}
|
|
10554
|
+
function restoreEffectBackRefForEffectsMap(effectsMap, consumer) {
|
|
10555
|
+
if (effectsMap) {
|
|
10556
|
+
for (const [, effects] of effectsMap) {
|
|
10557
|
+
restoreEffectBackRefForEffects(effects, consumer);
|
|
10558
|
+
}
|
|
10559
|
+
}
|
|
10560
|
+
}
|
|
10444
10561
|
|
|
10445
10562
|
/** Arrays/Objects are special-cased so their identifiers is a single digit. */
|
|
10446
10563
|
const needsInflation = (typeId) => typeId >= 15 /* TypeIds.Error */ || typeId === 4 /* TypeIds.Array */ || typeId === 5 /* TypeIds.Object */;
|