diff --git a/debug/src/debug.js b/debug/src/debug.js index a5b660a9ac..6aeeaef17b 100644 --- a/debug/src/debug.js +++ b/debug/src/debug.js @@ -582,3 +582,11 @@ export function serializeVNode(vnode) { children && children.length ? '>..' + name + '>' : ' />' }`; } + +options._hydrationMismatch = (newVNode, excessDomChildren) => { + const { type } = newVNode; + const availableTypes = excessDomChildren.map(child => child.localName); + console.error( + `Expected a DOM node of type ${type} but found ${availableTypes.join(', ')}as available DOM-node(s), this is caused by the SSR'd HTML containing different DOM-nodes compared to the hydrated one.\n\n${getOwnerStack(newVNode)}` + ); +}; diff --git a/debug/test/browser/debug.test.js b/debug/test/browser/debug.test.js index 2dcb5a05ae..eda8e77534 100644 --- a/debug/test/browser/debug.test.js +++ b/debug/test/browser/debug.test.js @@ -1,4 +1,11 @@ -import { createElement, render, createRef, Component, Fragment } from 'preact'; +import { + createElement, + render, + createRef, + Component, + Fragment, + hydrate +} from 'preact'; import { useState } from 'preact/hooks'; import { setupScratch, @@ -870,4 +877,43 @@ describe('debug', () => { expect(console.error).to.not.be.called; }); }); + + describe('Hydration mismatches', () => { + it('Should warn us for a node mismatch', () => { + scratch.innerHTML = '
foo
+