Skip to content

Commit 647d138

Browse files
committed
Fix issues by correctly skipping comments in diffChildren
1 parent 1281599 commit 647d138

File tree

4 files changed

+26
-22
lines changed

4 files changed

+26
-22
lines changed

compat/test/browser/suspense-hydration.test.js

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ describe('suspense hydration', () => {
132132
});
133133

134134
it('Should hydrate a fragment with no children correctly', () => {
135-
scratch.innerHTML = '<!--$s--><div>Hello</div><div>World!</div><!--/$s-->';
135+
scratch.innerHTML = '<!--$s--><!--/$s-->';
136136
clearLog();
137137

138138
const [Lazy, resolve] = createLazy();
@@ -143,22 +143,13 @@ describe('suspense hydration', () => {
143143
scratch
144144
);
145145
rerender(); // Flush rerender queue to mimic what preact will really do
146-
expect(scratch.innerHTML).to.equal(
147-
'<!--$s--><div>Hello</div><div>World!</div><!--/$s-->'
148-
);
146+
expect(scratch.innerHTML).to.equal('<!--$s--><!--/$s-->');
149147
expect(getLog()).to.deep.equal([]);
150148
clearLog();
151149

152-
return resolve(() => (
153-
<>
154-
<div>Hello</div>
155-
<div>World!</div>
156-
</>
157-
)).then(() => {
150+
return resolve(() => null).then(() => {
158151
rerender();
159-
expect(scratch.innerHTML).to.equal(
160-
'<!--$s--><div>Hello</div><div>World!</div><!--/$s-->'
161-
);
152+
expect(scratch.innerHTML).to.equal('<!--$s--><!--/$s-->');
162153
expect(getLog()).to.deep.equal([]);
163154

164155
clearLog();
@@ -167,7 +158,7 @@ describe('suspense hydration', () => {
167158

168159
// This is in theory correct but still it shows that our oldDom becomes stale very quickly
169160
// and moves DOM into weird places
170-
it.skip('Should hydrate a fragment with no children and an adjacent node correctly', () => {
161+
it('Should hydrate a fragment with no children and an adjacent node correctly', () => {
171162
scratch.innerHTML = '<!--$s--><!--/$s--><div>Baz</div>';
172163
clearLog();
173164

src/component.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,11 @@ export function getDomSibling(vnode, childIndex) {
100100
for (; childIndex < vnode._children.length; childIndex++) {
101101
sibling = vnode._children[childIndex];
102102

103-
if (sibling != null && sibling._dom != null) {
103+
if (
104+
sibling != null &&
105+
sibling._dom != null &&
106+
sibling._dom.nodeType !== 8
107+
) {
104108
// Since updateParentDomPointers keeps _dom pointer correct,
105109
// we can rely on _dom to tell us if this subtree contains a
106110
// rendered DOM node, and what the first rendered DOM node is

src/diff/children.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,9 @@ export function diffChildren(
135135
oldDom = childVNode._nextDom;
136136
} else if (newDom) {
137137
oldDom = newDom.nextSibling;
138+
while (oldDom && oldDom.nodeType == 8) {
139+
oldDom = oldDom.nextSibling;
140+
}
138141
}
139142

140143
// Eagerly cleanup _nextDom. We don't need to persist the value because it

src/diff/index.js

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ export function diff(
5454
isHydrating = !!(oldVNode._flags & MODE_HYDRATE);
5555
if (oldVNode._excess) {
5656
excessDomChildren = oldVNode._excess;
57-
oldDom = newVNode._dom = oldVNode._dom = excessDomChildren[1];
57+
oldDom = newVNode._dom = oldVNode._dom = excessDomChildren[0];
5858
} else {
5959
oldDom = newVNode._dom = oldVNode._dom;
6060
excessDomChildren = [oldDom];
@@ -283,26 +283,32 @@ export function diff(
283283
: MODE_HYDRATE;
284284

285285
let found = excessDomChildren.find(
286-
child => child && child.nodeType == 8 && child.data == '$s'
287-
),
288-
index = excessDomChildren.indexOf(found) + 1;
286+
child => child && child.nodeType == 8 && child.data == '$s'
287+
);
289288

290289
newVNode._dom = oldDom;
291290
if (found) {
292-
let commentMarkersToFind = 1;
293-
newVNode._excess = [found];
291+
let commentMarkersToFind = 1,
292+
index = excessDomChildren.indexOf(found) + 1;
293+
newVNode._excess = [];
294+
// Clear the comment marker so we don't reuse them for sibling
295+
// Suspenders.
294296
excessDomChildren[index - 1] = null;
297+
295298
while (commentMarkersToFind && index <= excessDomChildren.length) {
296299
const node = excessDomChildren[index];
297300
excessDomChildren[index] = null;
298301
index++;
299-
newVNode._excess.push(node);
302+
// node being undefined here would be a problem as it would
303+
// imply that we have a mismatch.
300304
if (node.nodeType == 8) {
301305
if (node.data == '$s') {
302306
commentMarkersToFind++;
303307
} else if (node.data == '/$s') {
304308
commentMarkersToFind--;
305309
}
310+
} else {
311+
newVNode._excess.push(node);
306312
}
307313
}
308314
} else {

0 commit comments

Comments
 (0)