diff --git a/debug/src/debug.js b/debug/src/debug.js index 8eb2fea33d..d0190594d4 100644 --- a/debug/src/debug.js +++ b/debug/src/debug.js @@ -66,7 +66,6 @@ export function initDebug() { let oldCatchError = options._catchError; let oldRoot = options._root; let oldHook = options._hook; - let oldCommit = options._commit; const warnedComponents = !isWeakMapSupported ? null : { @@ -75,8 +74,6 @@ export function initDebug() { lazyPropTypes: new WeakMap() }; const deprecations = []; - /** @type {import("./internal.d.ts").VNode[]} */ - let checkVNodeDom = []; options._catchError = (error, vnode, oldVNode, errorInfo) => { let component = vnode && vnode._component; @@ -150,9 +147,6 @@ export function initDebug() { options._diff = vnode => { let { type } = vnode; - if ((typeof type === 'string' && isTableElement(type)) || type === 'p') { - checkVNodeDom.push(vnode); - } hooksAllowed = true; @@ -319,6 +313,7 @@ export function initDebug() { }; options.diffed = vnode => { + const { type, _parent: parent } = vnode; // Check if the user passed plain objects as children. Note that we cannot // move this check into `options.vnode` because components can receive // children in any shape they want (e.g. @@ -338,6 +333,70 @@ export function initDebug() { }); } + if (typeof type === 'string' && (isTableElement(type) || type === 'p')) { + // Avoid false positives when Preact only partially rendered the + // HTML tree. Whilst we attempt to include the outer DOM in our + // validation, this wouldn't work on the server for + // `preact-render-to-string`. There we'd otherwise flood the terminal + // with false positives, which we'd like to avoid. + let domParentName = getClosestDomNodeParentName(parent); + if (domParentName !== '') { + if (type === 'table' && isTableElement(domParentName)) { + console.error( + 'Improper nesting of table. Your should not have a table-node parent.' + + serializeVNode(vnode) + + `\n\n${getOwnerStack(vnode)}` + ); + } else if ( + (type === 'thead' || type === 'tfoot' || type === 'tbody') && + domParentName !== 'table' + ) { + console.error( + 'Improper nesting of table. Your should have a
parent.' + + serializeVNode(vnode) + + `\n\n${getOwnerStack(vnode)}` + ); + } else if ( + type === 'tr' && + domParentName !== 'thead' && + domParentName !== 'tfoot' && + domParentName !== 'tbody' && + domParentName !== 'table' + ) { + console.error( + 'Improper nesting of table. Your should have a parent.' + + serializeVNode(vnode) + + `\n\n${getOwnerStack(vnode)}` + ); + } else if (type === 'td' && domParentName !== 'tr') { + console.error( + 'Improper nesting of table. Your parent.' + + serializeVNode(vnode) + + `\n\n${getOwnerStack(vnode)}` + ); + } else if (type === 'th' && domParentName !== 'tr') { + console.error( + 'Improper nesting of table. Your .' + + serializeVNode(vnode) + + `\n\n${getOwnerStack(vnode)}` + ); + } + } else if (type === 'p') { + let illegalDomChildrenTypes = getDomChildren(vnode).filter(childType => + ILLEGAL_PARAGRAPH_CHILD_ELEMENTS.test(childType) + ); + if (illegalDomChildrenTypes.length) { + console.error( + 'Improper nesting of paragraph. Your

should not have ' + + illegalDomChildrenTypes.join(', ') + + 'as child-elements.' + + serializeVNode(vnode) + + `\n\n${getOwnerStack(vnode)}` + ); + } + } + } + hooksAllowed = false; if (oldDiffed) oldDiffed(vnode); @@ -388,75 +447,6 @@ export function initDebug() { } } }; - - options._commit = (root, queue) => { - for (let i = 0; i < checkVNodeDom.length; i++) { - const vnode = checkVNodeDom[i]; - - // Check if HTML nesting is valid. We need to do it in `options.diffed` - // so that we can optionally traverse outside the vdom root in case - // it's an island embedded in an existing (and valid) HTML tree. - const { type, _parent: parent } = vnode; - - let domParentName = getClosestDomNodeParentName(parent); - if (type === 'table' && isTableElement(domParentName)) { - console.error( - 'Improper nesting of table. Your

should have a
should have a
should not have a table-node parent.' + - serializeVNode(vnode) + - `\n\n${getOwnerStack(vnode)}` - ); - } else if ( - (type === 'thead' || type === 'tfoot' || type === 'tbody') && - domParentName !== 'table' - ) { - console.error( - 'Improper nesting of table. Your should have a
parent.' + - serializeVNode(vnode) + - `\n\n${getOwnerStack(vnode)}` - ); - } else if ( - type === 'tr' && - domParentName !== 'thead' && - domParentName !== 'tfoot' && - domParentName !== 'tbody' && - domParentName !== 'table' - ) { - console.error( - 'Improper nesting of table. Your should have a parent.' + - serializeVNode(vnode) + - `\n\n${getOwnerStack(vnode)}` - ); - } else if (type === 'td' && domParentName !== 'tr') { - console.error( - 'Improper nesting of table. Your parent.' + - serializeVNode(vnode) + - `\n\n${getOwnerStack(vnode)}` - ); - } else if (type === 'th' && domParentName !== 'tr') { - console.error( - 'Improper nesting of table. Your .' + - serializeVNode(vnode) + - `\n\n${getOwnerStack(vnode)}` - ); - } else if (type === 'p') { - let illegalDomChildrenTypes = getDomChildren(vnode).filter(childType => - ILLEGAL_PARAGRAPH_CHILD_ELEMENTS.test(childType) - ); - if (illegalDomChildrenTypes.length) { - console.error( - 'Improper nesting of paragraph. Your

should not have ' + - illegalDomChildrenTypes.join(', ') + - 'as child-elements.' + - serializeVNode(vnode) + - `\n\n${getOwnerStack(vnode)}` - ); - } - } - } - checkVNodeDom = []; - - if (oldCommit) oldCommit(root, queue); - }; } const setState = Component.prototype.setState; diff --git a/debug/test/browser/component-stack.test.js b/debug/test/browser/component-stack.test.js index 87cd085ce4..ac533b228f 100644 --- a/debug/test/browser/component-stack.test.js +++ b/debug/test/browser/component-stack.test.js @@ -79,7 +79,7 @@ describe('component stack', () => { render(, scratch); let lines = getStack(errors).split('\n'); - expect(lines[0].indexOf('td') > -1).to.equal(true); + expect(lines[0].indexOf('tr') > -1).to.equal(true); expect(lines[1].indexOf('Thrower') > -1).to.equal(true); expect(lines[2].indexOf('Bar') > -1).to.equal(true); }); diff --git a/debug/test/browser/debug.test.js b/debug/test/browser/debug.test.js index 3fb7812d33..b7eb6d29a4 100644 --- a/debug/test/browser/debug.test.js +++ b/debug/test/browser/debug.test.js @@ -355,9 +355,11 @@ describe('debug', () => { describe('table markup', () => { it('missing

///
should have a
should have a
', () => { const Table = () => ( - - - +
+
+ + + ); render(
hi
hi
, scratch); expect(console.error).to.be.calledOnce; @@ -365,11 +367,13 @@ describe('debug', () => { it('missing
with ', () => { const Table = () => ( - - - - - +
+
+ + + + + ); render(
hi
hi
, scratch); expect(console.error).to.be.calledOnce; @@ -377,11 +381,13 @@ describe('debug', () => { it('missing
with ', () => { const Table = () => ( - - - - - +
+
+ + + + + ); render(
hi
hi
, scratch); expect(console.error).to.be.calledOnce; @@ -389,11 +395,13 @@ describe('debug', () => { it('missing
with ', () => { const Table = () => ( - - - - - +
+
+ + + + + ); render(
hi
hi
, scratch); expect(console.error).to.be.calledOnce;