Skip to content

Commit fddecc9

Browse files
committed
chore: better materialization error
1 parent b65dcdf commit fddecc9

File tree

5 files changed

+60
-12
lines changed

5 files changed

+60
-12
lines changed

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,11 @@ import { escapeHTML } from '../shared/utils/character-escaping';
9999
import { clearAllEffects } from '../reactive-primitives/cleanup';
100100
import { serializeAttribute } from '../shared/utils/styles';
101101
import { QError, qError } from '../shared/error/error';
102-
import { getFileLocationFromJsx } from '../shared/utils/jsx-filename';
102+
import { appendQwikInspectorAttribute, getFileLocationFromJsx } from '../shared/utils/jsx-filename';
103103
import { EffectProperty } from '../reactive-primitives/types';
104104
import { SubscriptionData } from '../reactive-primitives/subscription-data';
105105
import { WrappedSignalImpl } from '../reactive-primitives/impl/wrapped-signal-impl';
106+
import { qInspector } from '../shared/utils/qdev';
106107

107108
export const vnode_diff = (
108109
container: ClientContainer,
@@ -712,6 +713,9 @@ export const vnode_diff = (
712713
const jsxKey: string | null = jsx.key;
713714
let needsQDispatchEventPatch = false;
714715
const currentFile = getFileLocationFromJsx(jsx.dev);
716+
if (isDev && currentFile && qInspector) {
717+
appendQwikInspectorAttribute(jsx, currentFile);
718+
}
715719
if (!isSameElementName || jsxKey !== getKey(vCurrent)) {
716720
// So we have a key and it does not match the current node.
717721
// We need to do a forward search to find it.

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

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ import {
150150
QSlotParent,
151151
QStyle,
152152
QStylesAllSelector,
153+
qwikInspectorAttr,
153154
} from '../shared/utils/markers';
154155
import { isHtmlElement } from '../shared/utils/types';
155156
import { VNodeDataChar } from '../shared/vnode-data-types';
@@ -1829,9 +1830,49 @@ function materializeFromVNodeData(
18291830
if (isNumber(peek())) {
18301831
// Element counts get encoded as numbers.
18311832
while (!isElement(child)) {
1833+
const previousChild = child;
18321834
child = fastNextSibling(child);
18331835
if (!child) {
1834-
throw qError(QError.materializeVNodeDataError, [vData, peek(), nextToConsumeIdx]);
1836+
let childDescription: string | null = null;
1837+
let childDescriptionFile: string | null = null;
1838+
if (isDev) {
1839+
const getChildDescription = () => {
1840+
if (previousChild && isElement(previousChild)) {
1841+
return previousChild.outerHTML;
1842+
} else if (previousChild && isText(previousChild)) {
1843+
return previousChild.nodeValue;
1844+
} else {
1845+
return previousChild?.nodeName || null;
1846+
}
1847+
};
1848+
1849+
const getChildDescriptionFile = () => {
1850+
let previousChildWithFileLocation = previousChild;
1851+
while (!childDescriptionFile && previousChildWithFileLocation) {
1852+
if (
1853+
isElement(previousChildWithFileLocation) &&
1854+
previousChildWithFileLocation.hasAttribute(qwikInspectorAttr)
1855+
) {
1856+
return previousChildWithFileLocation.getAttribute(qwikInspectorAttr);
1857+
}
1858+
previousChildWithFileLocation =
1859+
previousChildWithFileLocation.parentNode as Node | null;
1860+
}
1861+
return null;
1862+
};
1863+
1864+
childDescription = getChildDescription();
1865+
childDescriptionFile = getChildDescriptionFile();
1866+
} else {
1867+
childDescription = previousChild?.nodeName || null;
1868+
}
1869+
throw qError(QError.materializeVNodeDataError, [
1870+
childDescription,
1871+
childDescriptionFile,
1872+
vData,
1873+
peek(),
1874+
nextToConsumeIdx,
1875+
]);
18351876
}
18361877
}
18371878
// We pretend that style element's don't exist as they can get moved out.

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export const codeToText = (code: number, ...parts: any[]): string => {
4949
'Unable to find q:container', // 41
5050
"Element must have 'q:container' attribute.", // 42
5151
'Unknown vnode type {{0}}.', // 43
52-
'Materialize error: missing element: {{0}} {{1}} {{2}}', // 44
52+
'Materialization error: Expected a text or element after\n{{0}}\nat location {{1}}\n metadata: {{2}},\n value: {{3}},\n next id: {{4}}', // 44
5353
'Cannot coerce a Signal, use `.value` instead', // 45
5454
'useComputedSignal$ QRL {{0}} {{1}} returned a Promise', // 46
5555
'ComputedSignal is read-only', // 47

packages/qwik/src/core/shared/utils/jsx-filename.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
1-
import type { DevJSX } from '../jsx/types/jsx-node';
1+
import type { DevJSX, JSXNodeInternal } from '../jsx/types/jsx-node';
2+
import { qwikInspectorAttr } from './markers';
3+
4+
export function appendQwikInspectorAttribute(
5+
jsx: JSXNodeInternal,
6+
qwikInspectorAttrValue: string | null
7+
) {
8+
if (qwikInspectorAttrValue && (!jsx.constProps || !(qwikInspectorAttr in jsx.constProps))) {
9+
(jsx.constProps ||= {})[qwikInspectorAttr] = qwikInspectorAttrValue;
10+
}
11+
}
212

313
export function getFileLocationFromJsx(jsxDev?: DevJSX): string | null {
414
if (!jsxDev) {

packages/qwik/src/core/ssr/ssr-render-jsx.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,14 @@ import {
1818
jsxEventToHtmlAttribute,
1919
} from '../shared/utils/event-names';
2020
import { EMPTY_ARRAY } from '../shared/utils/flyweight';
21-
import { getFileLocationFromJsx } from '../shared/utils/jsx-filename';
21+
import { appendQwikInspectorAttribute, getFileLocationFromJsx } from '../shared/utils/jsx-filename';
2222
import {
2323
ELEMENT_KEY,
2424
FLUSH_COMMENT,
2525
QDefaultSlot,
2626
QScopedStyle,
2727
QSlot,
2828
QSlotParent,
29-
qwikInspectorAttr,
3029
} from '../shared/utils/markers';
3130
import { isPromise } from '../shared/utils/promises';
3231
import { qInspector } from '../shared/utils/qdev';
@@ -510,12 +509,6 @@ function getSlotName(host: ISsrNode, jsx: JSXNodeInternal, ssr: SSRContainer): s
510509
return directGetPropsProxyProp(jsx, 'name') || QDefaultSlot;
511510
}
512511

513-
function appendQwikInspectorAttribute(jsx: JSXNodeInternal, qwikInspectorAttrValue: string | null) {
514-
if (qwikInspectorAttrValue && (!jsx.constProps || !(qwikInspectorAttr in jsx.constProps))) {
515-
(jsx.constProps ||= {})[qwikInspectorAttr] = qwikInspectorAttrValue;
516-
}
517-
}
518-
519512
// append class attribute if styleScopedId exists and there is no class attribute
520513
function appendClassIfScopedStyleExists(jsx: JSXNodeInternal, styleScoped: string | null) {
521514
const classAttributeExists = directGetPropsProxyProp(jsx, 'class') != null;

0 commit comments

Comments
 (0)