11import { MismatchTypes , isMismatchAllowed , warn } from '@vue/runtime-dom'
22import {
33 type ChildItem ,
4- getHydrationState ,
4+ incrementIndexOffset ,
55 insertionAnchor ,
66 insertionParent ,
77 resetInsertionState ,
@@ -36,9 +36,14 @@ function performHydration<T>(
3636 // optimize anchor cache lookup
3737 ; ( Comment . prototype as any ) . $fe = undefined
3838 ; ( Node . prototype as any ) . $pns = undefined
39- ; ( Node . prototype as any ) . $idx = undefined
4039 ; ( Node . prototype as any ) . $uc = undefined
40+ ; ( Node . prototype as any ) . $idx = undefined
4141 ; ( Node . prototype as any ) . $children = undefined
42+ ; ( Node . prototype as any ) . $idxMap = undefined
43+ ; ( Node . prototype as any ) . $prevDynamicCount = undefined
44+ ; ( Node . prototype as any ) . $anchorCount = undefined
45+ ; ( Node . prototype as any ) . $appendIndex = undefined
46+ ; ( Node . prototype as any ) . $indexOffset = undefined
4247 isOptimized = true
4348 }
4449 enableHydrationNodeHelper ( )
@@ -113,7 +118,9 @@ function adoptTemplateImpl(node: Node, template: string): Node | null {
113118 isComment ( node , ']' ) &&
114119 isComment ( node . previousSibling ! , '[' )
115120 ) {
116- node = parentNode ( node ) ! . insertBefore ( createTextNode ( ) , node )
121+ const parent = parentNode ( node ) !
122+ node = parent . insertBefore ( createTextNode ( ) , node )
123+ incrementIndexOffset ( parent )
117124 break
118125 }
119126 }
@@ -136,13 +143,19 @@ function adoptTemplateImpl(node: Node, template: string): Node | null {
136143
137144function locateHydrationNodeImpl ( ) : void {
138145 let node : Node | null
139- if ( insertionAnchor !== undefined ) {
140- const hydrationState = getHydrationState ( insertionParent ! ) !
141- const { prevDynamicCount, logicalChildren, appendAnchor } = hydrationState
146+ let idxMap : number [ ] | undefined
147+ if ( insertionAnchor !== undefined && ( idxMap = insertionParent ! . $idxMap ) ) {
148+ const {
149+ $prevDynamicCount : prevDynamicCount = 0 ,
150+ $appendIndex : appendIndex ,
151+ $indexOffset : indexOffset = 0 ,
152+ $anchorCount : anchorCount = 0 ,
153+ } = insertionParent !
142154 // prepend
143155 if ( insertionAnchor === 0 ) {
144- // use prevDynamicCount as index to locate the hydration node
145- node = logicalChildren [ prevDynamicCount ]
156+ // use prevDynamicCount as logical index to locate the hydration node
157+ const realIndex = idxMap ! [ prevDynamicCount ] + indexOffset
158+ node = insertionParent ! . childNodes [ realIndex ]
146159 }
147160 // insert
148161 else if ( insertionAnchor instanceof Node ) {
@@ -153,48 +166,52 @@ function locateHydrationNodeImpl(): void {
153166 // consecutive insert operations locate the correct hydration node.
154167 let { $idx, $uc : usedCount } = insertionAnchor as ChildItem
155168 if ( usedCount !== undefined ) {
156- node = logicalChildren [ $idx + usedCount + 1 ]
169+ const realIndex = idxMap ! [ $idx + usedCount + 1 ] + indexOffset
170+ node = insertionParent ! . childNodes [ realIndex ]
157171 usedCount ++
158172 } else {
159173 node = insertionAnchor
160174 // first use of this anchor: it doesn't consume the next child
161175 // so we track unique anchor appearances for later offset correction
162- hydrationState . uniqueAnchorCount ++
176+ insertionParent ! . $anchorCount = anchorCount + 1
163177 usedCount = 0
164178 }
165179 ; ( insertionAnchor as ChildItem ) . $uc = usedCount
166180 }
167181 // append
168182 else {
169- if ( appendAnchor ) {
170- node = logicalChildren [ ( appendAnchor as ChildItem ) . $idx + 1 ]
183+ let realIndex : number
184+ if ( appendIndex !== null && appendIndex !== undefined ) {
185+ realIndex = idxMap ! [ appendIndex + 1 ] + indexOffset
186+ node = insertionParent ! . childNodes [ realIndex ]
171187 } else {
172- node =
188+ if ( insertionAnchor === null ) {
173189 // insertionAnchor is null, indicates no previous static nodes
174190 // use the first child as hydration node
175- insertionAnchor === null
176- ? logicalChildren [ 0 ]
177- : // insertionAnchor is a number > 0
178- // indicates how many static nodes precede the node to append
179- // use it as index to locate the hydration node
180- logicalChildren [ prevDynamicCount + insertionAnchor ]
191+ realIndex = idxMap ! [ 0 ] + indexOffset
192+ node = insertionParent ! . childNodes [ realIndex ]
193+ } else {
194+ // insertionAnchor is a number > 0
195+ // indicates how many static nodes precede the node to append
196+ // use it as index to locate the hydration node
197+ realIndex = idxMap ! [ prevDynamicCount + insertionAnchor ] + indexOffset
198+ node = insertionParent ! . childNodes [ realIndex ]
199+ }
181200 }
182- hydrationState . appendAnchor = node
201+ insertionParent ! . $appendIndex = ( node as ChildItem ) . $idx
183202 }
184203
185- hydrationState . prevDynamicCount ++
204+ insertionParent ! . $ prevDynamicCount = prevDynamicCount + 1
186205 } else {
187206 node = currentHydrationNode
188- if ( insertionParent && ( ! node || parentNode ( node ) !== insertionParent ) ) {
189- node = _child ( insertionParent )
207+ if ( insertionParent && ( ! node || node . parentNode !== insertionParent ) ) {
208+ node = insertionParent . firstChild
190209 }
191210 }
192211
193212 if ( __DEV__ && ! node ) {
194- throw new Error (
195- `No current hydration node was found.\n` +
196- `this is likely a Vue internal bug.` ,
197- )
213+ // TODO more info
214+ warn ( 'Hydration mismatch in ' , insertionParent )
198215 }
199216
200217 resetInsertionState ( )
0 commit comments