Skip to content

Commit bd9dbf1

Browse files
authored
Merge pull request #7236 from QwikDev/v2-warn-server-mismatch-error
feat: log a warning instead of throwing an error for server host mismatch error
2 parents cb22f46 + e0bc963 commit bd9dbf1

File tree

7 files changed

+193
-129
lines changed

7 files changed

+193
-129
lines changed

.changeset/shaggy-poems-appear.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@qwik.dev/core': patch
3+
---
4+
5+
feat: log a warning instead of throwing an error for server host mismatch error

packages/qwik/src/core/client/vnode.ts

-60
Original file line numberDiff line numberDiff line change
@@ -1889,66 +1889,6 @@ export const vnode_getType = (vnode: VNode): 1 | 3 | 11 => {
18891889
const isElement = (node: any): node is Element =>
18901890
node && typeof node == 'object' && fastNodeType(node) === /** Node.ELEMENT_NODE* */ 1;
18911891

1892-
/// These global variables are used to avoid creating new arrays for each call to `vnode_documentPosition`.
1893-
const aPath: VNode[] = [];
1894-
const bPath: VNode[] = [];
1895-
export const vnode_documentPosition = (
1896-
a: VNode,
1897-
b: VNode,
1898-
rootVNode: ElementVNode | null
1899-
): -1 | 0 | 1 => {
1900-
if (a === b) {
1901-
return 0;
1902-
}
1903-
1904-
let aDepth = -1;
1905-
let bDepth = -1;
1906-
while (a) {
1907-
const vNode = (aPath[++aDepth] = a);
1908-
a = (vNode[VNodeProps.parent] ||
1909-
(rootVNode && vnode_getProp(a, QSlotParent, (id) => vnode_locate(rootVNode, id))))!;
1910-
}
1911-
while (b) {
1912-
const vNode = (bPath[++bDepth] = b);
1913-
b = (vNode[VNodeProps.parent] ||
1914-
(rootVNode && vnode_getProp(b, QSlotParent, (id) => vnode_locate(rootVNode, id))))!;
1915-
}
1916-
1917-
while (aDepth >= 0 && bDepth >= 0) {
1918-
a = aPath[aDepth] as VNode;
1919-
b = bPath[bDepth] as VNode;
1920-
if (a === b) {
1921-
// if the nodes are the same, we need to check the next level.
1922-
aDepth--;
1923-
bDepth--;
1924-
} else {
1925-
// We found a difference so we need to scan nodes at this level.
1926-
let cursor: VNode | null = b;
1927-
do {
1928-
cursor = vnode_getNextSibling(cursor);
1929-
if (cursor === a) {
1930-
return 1;
1931-
}
1932-
} while (cursor);
1933-
cursor = b;
1934-
do {
1935-
cursor = vnode_getPreviousSibling(cursor);
1936-
if (cursor === a) {
1937-
return -1;
1938-
}
1939-
} while (cursor);
1940-
if (rootVNode && vnode_getProp(b, QSlotParent, (id) => vnode_locate(rootVNode, id))) {
1941-
// The "b" node is a projection, so we need to set it after "a" node,
1942-
// because the "a" node could be a context provider.
1943-
return -1;
1944-
}
1945-
// The node is not in the list of siblings, that means it must be disconnected.
1946-
return 1;
1947-
}
1948-
}
1949-
return aDepth < bDepth ? -1 : 1;
1950-
};
1951-
19521892
/**
19531893
* Use this method to find the parent component for projection.
19541894
*

packages/qwik/src/core/client/vnode.unit.tsx

-27
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import type {
1313
} from './types';
1414
import {
1515
vnode_applyJournal,
16-
vnode_documentPosition,
1716
vnode_getAttr,
1817
vnode_getFirstChild,
1918
vnode_getNextSibling,
@@ -650,30 +649,4 @@ describe('vnode', () => {
650649
});
651650
});
652651
});
653-
describe('vnode_documentPosition', () => {
654-
it('should compare two elements', () => {
655-
parent.innerHTML = '<b></b><i></i>';
656-
const b = vnode_getFirstChild(vParent) as ElementVNode;
657-
const i = vnode_getNextSibling(b) as ElementVNode;
658-
expect(vnode_documentPosition(b, i, null)).toBe(-1);
659-
expect(vnode_documentPosition(i, b, null)).toBe(1);
660-
});
661-
it('should compare two virtual vNodes', () => {
662-
parent.innerHTML = 'AB';
663-
document.qVNodeData.set(parent, '{B}{B}');
664-
const a = vnode_getFirstChild(vParent) as ElementVNode;
665-
const b = vnode_getNextSibling(a) as ElementVNode;
666-
expect(vnode_documentPosition(a, b, null)).toBe(-1);
667-
expect(vnode_documentPosition(b, a, null)).toBe(1);
668-
});
669-
it('should compare two virtual vNodes', () => {
670-
parent.innerHTML = 'AB';
671-
document.qVNodeData.set(parent, '{{B}}{B}');
672-
const a = vnode_getFirstChild(vParent) as ElementVNode;
673-
const a2 = vnode_getFirstChild(a) as ElementVNode;
674-
const b = vnode_getNextSibling(a) as ElementVNode;
675-
expect(vnode_documentPosition(a2, b, null)).toBe(-1);
676-
expect(vnode_documentPosition(b, a2, null)).toBe(1);
677-
});
678-
});
679652
});

packages/qwik/src/core/shared/error/error.ts

+6-8
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ export const codeToText = (code: number, ...parts: any[]): string => {
5050
"Element must have 'q:container' attribute.", // 42
5151
'Unknown vnode type {{0}}.', // 43
5252
'Materialize error: missing element: {{0}} {{1}} {{2}}', // 44
53-
'SsrError: {{0}}', // 45
5453
'Cannot coerce a Signal, use `.value` instead', // 46
5554
'useComputedSignal$ QRL {{0}} {{1}} returned a Promise', // 47
5655
'ComputedSignal is read-only', // 48
@@ -121,13 +120,12 @@ export const enum QError {
121120
elementWithoutContainer = 42,
122121
invalidVNodeType = 43,
123122
materializeVNodeDataError = 44,
124-
serverHostMismatch = 45,
125-
cannotCoerceSignal = 46,
126-
computedNotSync = 47,
127-
computedReadOnly = 48,
128-
wrappedReadOnly = 49,
129-
promisesNotExpected = 50,
130-
unsafeAttr = 51,
123+
cannotCoerceSignal = 45,
124+
computedNotSync = 46,
125+
computedReadOnly = 47,
126+
wrappedReadOnly = 48,
127+
promisesNotExpected = 49,
128+
unsafeAttr = 50,
131129
}
132130

133131
export const qError = (code: number, errorMessageArgs: any[] = []): Error => {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
2+
import {
3+
vnode_getFirstChild,
4+
vnode_getNextSibling,
5+
vnode_newUnMaterializedElement,
6+
} from '../client/vnode';
7+
import type { ContainerElement, ElementVNode, QDocument } from '../client/types';
8+
import { vnode_documentPosition } from './scheduler-document-position';
9+
import { createDocument } from '@qwik.dev/dom';
10+
11+
describe('vnode_documentPosition', () => {
12+
let parent: ContainerElement;
13+
let document: QDocument;
14+
let vParent: ElementVNode;
15+
beforeEach(() => {
16+
document = createDocument() as QDocument;
17+
document.qVNodeData = new WeakMap();
18+
parent = document.createElement('test') as ContainerElement;
19+
parent.qVNodeRefs = new Map();
20+
vParent = vnode_newUnMaterializedElement(parent);
21+
});
22+
afterEach(() => {
23+
parent = null!;
24+
document = null!;
25+
vParent = null!;
26+
});
27+
28+
it('should compare two elements', () => {
29+
parent.innerHTML = '<b></b><i></i>';
30+
const b = vnode_getFirstChild(vParent) as ElementVNode;
31+
const i = vnode_getNextSibling(b) as ElementVNode;
32+
expect(vnode_documentPosition(b, i, null)).toBe(-1);
33+
expect(vnode_documentPosition(i, b, null)).toBe(1);
34+
});
35+
it('should compare two virtual vNodes', () => {
36+
parent.innerHTML = 'AB';
37+
document.qVNodeData.set(parent, '{B}{B}');
38+
const a = vnode_getFirstChild(vParent) as ElementVNode;
39+
const b = vnode_getNextSibling(a) as ElementVNode;
40+
expect(vnode_documentPosition(a, b, null)).toBe(-1);
41+
expect(vnode_documentPosition(b, a, null)).toBe(1);
42+
});
43+
it('should compare two virtual vNodes', () => {
44+
parent.innerHTML = 'AB';
45+
document.qVNodeData.set(parent, '{{B}}{B}');
46+
const a = vnode_getFirstChild(vParent) as ElementVNode;
47+
const a2 = vnode_getFirstChild(a) as ElementVNode;
48+
const b = vnode_getNextSibling(a) as ElementVNode;
49+
expect(vnode_documentPosition(a2, b, null)).toBe(-1);
50+
expect(vnode_documentPosition(b, a2, null)).toBe(1);
51+
});
52+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
import { VNodeProps, type ElementVNode, type VNode } from '../client/types';
2+
import {
3+
vnode_getNextSibling,
4+
vnode_getPreviousSibling,
5+
vnode_getProp,
6+
vnode_locate,
7+
} from '../client/vnode';
8+
import type { ISsrNode } from '../ssr/ssr-types';
9+
import { QSlotParent } from './utils/markers';
10+
11+
/// These global variables are used to avoid creating new arrays for each call to `vnode_documentPosition`.
12+
const aVNodePath: VNode[] = [];
13+
const bVNodePath: VNode[] = [];
14+
/**
15+
* Compare two VNodes and determine their document position relative to each other.
16+
*
17+
* @param a VNode to compare
18+
* @param b VNode to compare
19+
* @param rootVNode - Root VNode of a container
20+
* @returns -1 if `a` is before `b`, 0 if `a` is the same as `b`, 1 if `a` is after `b`.
21+
*/
22+
export const vnode_documentPosition = (
23+
a: VNode,
24+
b: VNode,
25+
rootVNode: ElementVNode | null
26+
): -1 | 0 | 1 => {
27+
if (a === b) {
28+
return 0;
29+
}
30+
31+
let aDepth = -1;
32+
let bDepth = -1;
33+
while (a) {
34+
const vNode = (aVNodePath[++aDepth] = a);
35+
a = (vNode[VNodeProps.parent] ||
36+
(rootVNode && vnode_getProp(a, QSlotParent, (id) => vnode_locate(rootVNode, id))))!;
37+
}
38+
while (b) {
39+
const vNode = (bVNodePath[++bDepth] = b);
40+
b = (vNode[VNodeProps.parent] ||
41+
(rootVNode && vnode_getProp(b, QSlotParent, (id) => vnode_locate(rootVNode, id))))!;
42+
}
43+
44+
while (aDepth >= 0 && bDepth >= 0) {
45+
a = aVNodePath[aDepth] as VNode;
46+
b = bVNodePath[bDepth] as VNode;
47+
if (a === b) {
48+
// if the nodes are the same, we need to check the next level.
49+
aDepth--;
50+
bDepth--;
51+
} else {
52+
// We found a difference so we need to scan nodes at this level.
53+
let cursor: VNode | null = b;
54+
do {
55+
cursor = vnode_getNextSibling(cursor);
56+
if (cursor === a) {
57+
return 1;
58+
}
59+
} while (cursor);
60+
cursor = b;
61+
do {
62+
cursor = vnode_getPreviousSibling(cursor);
63+
if (cursor === a) {
64+
return -1;
65+
}
66+
} while (cursor);
67+
if (rootVNode && vnode_getProp(b, QSlotParent, (id) => vnode_locate(rootVNode, id))) {
68+
// The "b" node is a projection, so we need to set it after "a" node,
69+
// because the "a" node could be a context provider.
70+
return -1;
71+
}
72+
// The node is not in the list of siblings, that means it must be disconnected.
73+
return 1;
74+
}
75+
}
76+
return aDepth < bDepth ? -1 : 1;
77+
};
78+
79+
/// These global variables are used to avoid creating new arrays for each call to `ssrNodeDocumentPosition`.
80+
const aSsrNodePath: ISsrNode[] = [];
81+
const bSsrNodePath: ISsrNode[] = [];
82+
/**
83+
* Compare two SSR nodes and determine their document position relative to each other. Compares only
84+
* position between parent and child.
85+
*
86+
* @param a SSR node to compare
87+
* @param b SSR node to compare
88+
* @returns -1 if `a` is before `b`, 0 if `a` is the same as `b`, 1 if `a` is after `b`.
89+
*/
90+
export const ssrNodeDocumentPosition = (a: ISsrNode, b: ISsrNode): -1 | 0 | 1 => {
91+
if (a === b) {
92+
return 0;
93+
}
94+
95+
let aDepth = -1;
96+
let bDepth = -1;
97+
while (a) {
98+
const ssrNode = (aSsrNodePath[++aDepth] = a);
99+
a = ssrNode.currentComponentNode!;
100+
}
101+
while (b) {
102+
const ssrNode = (bSsrNodePath[++bDepth] = b);
103+
b = ssrNode.currentComponentNode!;
104+
}
105+
106+
while (aDepth >= 0 && bDepth >= 0) {
107+
a = aSsrNodePath[aDepth] as ISsrNode;
108+
b = bSsrNodePath[bDepth] as ISsrNode;
109+
if (a === b) {
110+
// if the nodes are the same, we need to check the next level.
111+
aDepth--;
112+
bDepth--;
113+
} else {
114+
return 1;
115+
}
116+
}
117+
return aDepth < bDepth ? -1 : 1;
118+
};

0 commit comments

Comments
 (0)