@@ -47,7 +47,7 @@ export function createHydrationFunctions(
47
47
const {
48
48
mt : mountComponent ,
49
49
p : patch ,
50
- o : { patchProp, nextSibling, parentNode }
50
+ o : { patchProp, nextSibling, parentNode, remove , insert , createComment }
51
51
} = rendererInternals
52
52
53
53
const hydrate : RootHydrateFunction = ( vnode , container ) => {
@@ -76,11 +76,14 @@ export function createHydrationFunctions(
76
76
optimized = false
77
77
) : Node | null => {
78
78
const isFragmentStart = isComment ( node ) && node . data === '['
79
- if ( __DEV__ && isFragmentStart ) {
80
- // in dev mode, replace comment anchors with invisible text nodes
81
- // for easier debugging
82
- node = replaceAnchor ( node , parentNode ( node ) ! )
83
- }
79
+ const onMismatch = ( ) =>
80
+ handleMismtach (
81
+ node ,
82
+ vnode ,
83
+ parentComponent ,
84
+ parentSuspense ,
85
+ isFragmentStart
86
+ )
84
87
85
88
const { type, shapeFlag } = vnode
86
89
const domType = node . nodeType
@@ -89,7 +92,7 @@ export function createHydrationFunctions(
89
92
switch ( type ) {
90
93
case Text :
91
94
if ( domType !== DOMNodeTypes . TEXT ) {
92
- return handleMismtach ( node , vnode , parentComponent , parentSuspense )
95
+ return onMismatch ( )
93
96
}
94
97
if ( ( node as Text ) . data !== vnode . children ) {
95
98
hasMismatch = true
@@ -103,18 +106,18 @@ export function createHydrationFunctions(
103
106
}
104
107
return nextSibling ( node )
105
108
case Comment :
106
- if ( domType !== DOMNodeTypes . COMMENT ) {
107
- return handleMismtach ( node , vnode , parentComponent , parentSuspense )
109
+ if ( domType !== DOMNodeTypes . COMMENT || isFragmentStart ) {
110
+ return onMismatch ( )
108
111
}
109
112
return nextSibling ( node )
110
113
case Static :
111
114
if ( domType !== DOMNodeTypes . ELEMENT ) {
112
- return handleMismtach ( node , vnode , parentComponent , parentSuspense )
115
+ return onMismatch ( )
113
116
}
114
117
return nextSibling ( node )
115
118
case Fragment :
116
- if ( domType !== ( __DEV__ ? DOMNodeTypes . TEXT : DOMNodeTypes . COMMENT ) ) {
117
- return handleMismtach ( node , vnode , parentComponent , parentSuspense )
119
+ if ( ! isFragmentStart ) {
120
+ return onMismatch ( )
118
121
}
119
122
return hydrateFragment (
120
123
node as Comment ,
@@ -129,7 +132,7 @@ export function createHydrationFunctions(
129
132
domType !== DOMNodeTypes . ELEMENT ||
130
133
vnode . type !== ( node as Element ) . tagName . toLowerCase ( )
131
134
) {
132
- return handleMismtach ( node , vnode , parentComponent , parentSuspense )
135
+ return onMismatch ( )
133
136
}
134
137
return hydrateElement (
135
138
node as Element ,
@@ -159,7 +162,7 @@ export function createHydrationFunctions(
159
162
: nextSibling ( node )
160
163
} else if ( shapeFlag & ShapeFlags . PORTAL ) {
161
164
if ( domType !== DOMNodeTypes . COMMENT ) {
162
- return handleMismtach ( node , vnode , parentComponent , parentSuspense )
165
+ return onMismatch ( )
163
166
}
164
167
hydratePortal ( vnode , parentComponent , parentSuspense , optimized )
165
168
return nextSibling ( node )
@@ -247,7 +250,7 @@ export function createHydrationFunctions(
247
250
// The SSRed DOM contains more nodes than it should. Remove them.
248
251
const cur = next
249
252
next = next . nextSibling
250
- el . removeChild ( cur )
253
+ remove ( cur )
251
254
}
252
255
} else if ( shapeFlag & ShapeFlags . TEXT_CHILDREN ) {
253
256
if ( el . textContent !== vnode . children ) {
@@ -321,18 +324,24 @@ export function createHydrationFunctions(
321
324
optimized : boolean
322
325
) => {
323
326
const container = parentNode ( node ) !
324
- let next = hydrateChildren (
327
+ const next = hydrateChildren (
325
328
nextSibling ( node ) ! ,
326
329
vnode ,
327
330
container ,
328
331
parentComponent ,
329
332
parentSuspense ,
330
333
optimized
331
- ) !
332
- if ( __DEV__ ) {
333
- next = replaceAnchor ( next , container )
334
+ )
335
+ if ( next && isComment ( next ) && next . data === ']' ) {
336
+ return nextSibling ( ( vnode . anchor = next ) )
337
+ } else {
338
+ // fragment didn't hydrate successfully, since we didn't get a end anchor
339
+ // back. This should have led to node/children mismatch warnings.
340
+ hasMismatch = true
341
+ // since the anchor is missing, we need to create one and insert it
342
+ insert ( ( vnode . anchor = createComment ( `]` ) ) , container , next )
343
+ return next
334
344
}
335
- return nextSibling ( ( vnode . anchor = next ) )
336
345
}
337
346
338
347
const hydratePortal = (
@@ -366,7 +375,8 @@ export function createHydrationFunctions(
366
375
node : Node ,
367
376
vnode : VNode ,
368
377
parentComponent : ComponentInternalInstance | null ,
369
- parentSuspense : SuspenseBoundary | null
378
+ parentSuspense : SuspenseBoundary | null ,
379
+ isFragment : boolean
370
380
) => {
371
381
hasMismatch = true
372
382
__DEV__ &&
@@ -375,12 +385,31 @@ export function createHydrationFunctions(
375
385
vnode . type ,
376
386
`\n- Server rendered DOM:` ,
377
387
node ,
378
- node . nodeType === DOMNodeTypes . TEXT ? `(text)` : ``
388
+ node . nodeType === DOMNodeTypes . TEXT
389
+ ? `(text)`
390
+ : isComment ( node ) && node . data === '['
391
+ ? `(start of fragment)`
392
+ : ``
379
393
)
380
394
vnode . el = null
395
+
396
+ if ( isFragment ) {
397
+ // remove excessive fragment nodes
398
+ const end = locateClosingAsyncAnchor ( node )
399
+ while ( true ) {
400
+ const next = nextSibling ( node )
401
+ if ( next && next !== end ) {
402
+ remove ( next )
403
+ } else {
404
+ break
405
+ }
406
+ }
407
+ }
408
+
381
409
const next = nextSibling ( node )
382
410
const container = parentNode ( node ) !
383
- container . removeChild ( node )
411
+ remove ( node )
412
+
384
413
patch (
385
414
null ,
386
415
vnode ,
@@ -411,12 +440,5 @@ export function createHydrationFunctions(
411
440
return node
412
441
}
413
442
414
- const replaceAnchor = ( node : Node , parent : Element ) : Node => {
415
- const text = document . createTextNode ( '' )
416
- parent . insertBefore ( text , node )
417
- parent . removeChild ( node )
418
- return text
419
- }
420
-
421
443
return [ hydrate , hydrateNode ] as const
422
444
}
0 commit comments