diff --git a/compat/test/browser/suspense-hydration.test.js b/compat/test/browser/suspense-hydration.test.js
index 9143903238..43b43b552c 100644
--- a/compat/test/browser/suspense-hydration.test.js
+++ b/compat/test/browser/suspense-hydration.test.js
@@ -139,6 +139,75 @@ describe('suspense hydration', () => {
});
});
+ it('Should hydrate a fragment with multiple children correctly', () => {
+ scratch.innerHTML = '
Hello
World!
';
+ clearLog();
+
+ const [Lazy, resolve] = createLazy();
+ hydrate(
+
+
+ ,
+ scratch
+ );
+ rerender(); // Flush rerender queue to mimic what preact will really do
+ expect(scratch.innerHTML).to.equal('Hello
World!
');
+ expect(getLog()).to.deep.equal([]);
+ clearLog();
+
+ return resolve(() => (
+ <>
+ Hello
+ World!
+ >
+ )).then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.equal('Hello
World!
');
+ expect(getLog()).to.deep.equal([]);
+
+ clearLog();
+ });
+ });
+
+ // This is an expected fail case, we should encourage folks to not have adjacent
+ // nodes of the same type, or return a single wrapping dom node from a lazy boundary.
+ it.skip('Should hydrate a fragment with multiple children and an adjacent node correctly', () => {
+ scratch.innerHTML = 'Hello
World!
Baz
';
+ clearLog();
+
+ const [Lazy, resolve] = createLazy();
+ hydrate(
+ <>
+
+
+
+ Baz
+ >,
+ scratch
+ );
+ rerender(); // Flush rerender queue to mimic what preact will really do
+ expect(scratch.innerHTML).to.equal(
+ 'Hello
World!
Baz
'
+ );
+ expect(getLog()).to.deep.equal([]);
+ clearLog();
+
+ return resolve(() => (
+ <>
+ Hello
+ World!
+ >
+ )).then(() => {
+ rerender();
+ expect(scratch.innerHTML).to.equal(
+ 'Hello
World!
Baz
'
+ );
+ expect(getLog()).to.deep.equal([]);
+
+ clearLog();
+ });
+ });
+
it('should allow siblings to update around suspense boundary', () => {
scratch.innerHTML = 'Count: 0
Hello
';
clearLog();
diff --git a/jsx-runtime/src/index.js b/jsx-runtime/src/index.js
index 454df6308a..98551fc28a 100644
--- a/jsx-runtime/src/index.js
+++ b/jsx-runtime/src/index.js
@@ -59,6 +59,7 @@ function createVNode(type, props, key, isStaticChildren, __source, __self) {
_nextDom: undefined,
_component: null,
constructor: undefined,
+ _excess: null,
_original: --vnodeId,
_index: -1,
_flags: 0,
diff --git a/mangle.json b/mangle.json
index fcd2dce74f..4bb11b1fae 100644
--- a/mangle.json
+++ b/mangle.json
@@ -27,6 +27,7 @@
"props": {
"$_listeners": "l",
"$_cleanup": "__c",
+ "$_excess": "__x",
"$__hooks": "__H",
"$_list": "__",
"$_pendingEffects": "__h",
diff --git a/src/create-element.js b/src/create-element.js
index 66898b2224..6308287d7a 100644
--- a/src/create-element.js
+++ b/src/create-element.js
@@ -62,6 +62,7 @@ export function createVNode(type, props, key, ref, original) {
props,
key,
ref,
+ _excess: null,
_children: null,
_parent: null,
_depth: 0,
diff --git a/src/diff/index.js b/src/diff/index.js
index 3e4b17bd62..35a9b7c6d2 100644
--- a/src/diff/index.js
+++ b/src/diff/index.js
@@ -53,7 +53,7 @@ export function diff(
if (oldVNode._flags & MODE_SUSPENDED) {
isHydrating = !!(oldVNode._flags & MODE_HYDRATE);
oldDom = newVNode._dom = oldVNode._dom;
- excessDomChildren = [oldDom];
+ excessDomChildren = oldVNode._excess;
}
if ((tmp = options._diff)) tmp(newVNode);
@@ -277,6 +277,7 @@ export function diff(
newVNode._flags |= isHydrating
? MODE_HYDRATE | MODE_SUSPENDED
: MODE_HYDRATE;
+ newVNode._excess = [...excessDomChildren];
excessDomChildren[excessDomChildren.indexOf(oldDom)] = null;
// ^ could possibly be simplified to:
// excessDomChildren.length = 0;
diff --git a/src/internal.d.ts b/src/internal.d.ts
index cbf23b3888..e771e8e679 100644
--- a/src/internal.d.ts
+++ b/src/internal.d.ts
@@ -141,6 +141,7 @@ declare global {
_children: Array> | null;
_parent: VNode | null;
_depth: number | null;
+ _excess: Array | null;
/**
* The [first (for Fragments)] DOM child of a VNode
*/