@@ -6,12 +6,11 @@ import {
6
6
setInsertionState ,
7
7
} from '../insertionState'
8
8
import {
9
- _child ,
10
9
disableHydrationNodeLookup ,
11
10
enableHydrationNodeLookup ,
12
11
next ,
13
12
} from './node'
14
- import { isDynamicAnchor , isVaporFragmentEndAnchor } from '@vue/shared'
13
+ import { isVaporAnchors , isVaporFragmentAnchor } from '@vue/shared'
15
14
16
15
export let isHydrating = false
17
16
export let currentHydrationNode : Node | null = null
@@ -33,7 +32,6 @@ function performHydration<T>(
33
32
34
33
// optimize anchor cache lookup
35
34
; ( Comment . prototype as any ) . $fs = undefined
36
- ; ( Node . prototype as any ) . $nc = undefined
37
35
isOptimized = true
38
36
}
39
37
enableHydrationNodeLookup ( )
@@ -101,24 +99,29 @@ function adoptTemplateImpl(node: Node, template: string): Node | null {
101
99
return node
102
100
}
103
101
102
+ const hydrationPositionMap = new WeakMap < ParentNode , Node > ( )
103
+
104
104
function locateHydrationNodeImpl ( hasFragmentAnchor ?: boolean ) {
105
105
let node : Node | null
106
106
// prepend / firstChild
107
107
if ( insertionAnchor === 0 ) {
108
- node = _child ( insertionParent ! )
108
+ node = insertionParent ! . firstChild
109
109
} else if ( insertionAnchor ) {
110
- // for dynamic children, use insertionAnchor as the node
110
+ // `insertionAnchor` is a Node, it is the DOM node to hydrate
111
+ // Template: `...<span/><!----><span/>...`// `insertionAnchor` is the placeholder
112
+ // SSR Output: `...<span/>Content<span/>...`// `insertionAnchor` is the actual node
111
113
node = insertionAnchor
112
114
} else {
113
115
node = insertionParent
114
- ? insertionParent . $nc || insertionParent . lastChild
116
+ ? hydrationPositionMap . get ( insertionParent ) || insertionParent . lastChild
115
117
: currentHydrationNode
116
118
117
- // if the last child is a vapor fragment end anchor, find the previous one
118
- if ( hasFragmentAnchor && node && isVaporFragmentEndAnchor ( node ) ) {
119
+ // if node is a vapor fragment anchor, find the previous one
120
+ if ( hasFragmentAnchor && node && isVaporFragmentAnchor ( node ) ) {
119
121
node = node . previousSibling
120
122
if ( __DEV__ && ! node ) {
121
- // TODO warning, should not happen
123
+ // this should not happen
124
+ throw new Error ( `vapor fragment anchor previous node was not found.` )
122
125
}
123
126
}
124
127
@@ -153,7 +156,8 @@ function locateHydrationNodeImpl(hasFragmentAnchor?: boolean) {
153
156
}
154
157
155
158
if ( insertionParent && node ) {
156
- insertionParent . $nc = node ! . previousSibling
159
+ const prev = node . previousSibling
160
+ if ( prev ) hydrationPositionMap . set ( insertionParent , prev )
157
161
}
158
162
}
159
163
@@ -166,10 +170,6 @@ function locateHydrationNodeImpl(hasFragmentAnchor?: boolean) {
166
170
currentHydrationNode = node
167
171
}
168
172
169
- export function isEmptyText ( node : Node ) : node is Text {
170
- return node . nodeType === 3 && ! ( node as Text ) . data . trim ( )
171
- }
172
-
173
173
export function locateEndAnchor (
174
174
node : Node | null ,
175
175
open = '[' ,
@@ -194,26 +194,26 @@ export function locateEndAnchor(
194
194
195
195
export function isNonHydrationNode ( node : Node ) : boolean {
196
196
return (
197
- // empty text nodes
198
- isEmptyText ( node ) ||
199
- // dynamic node anchors (<!--[[-->, <!--]]-->)
200
- isDynamicAnchor ( node ) ||
201
- // fragment end anchor (`<!--]-->`)
197
+ // empty text node
198
+ isEmptyTextNode ( node ) ||
199
+ // vdom fragment end anchor (`<!--]-->`)
202
200
isComment ( node , ']' ) ||
203
- // vapor fragment end anchors
204
- isVaporFragmentEndAnchor ( node )
201
+ // vapor mode specific anchors
202
+ isVaporAnchors ( node )
205
203
)
206
204
}
207
205
208
- export function findVaporFragmentAnchor (
206
+ export function locateVaporFragmentAnchor (
209
207
node : Node ,
210
208
anchorLabel : string ,
211
- ) : Comment | null {
209
+ ) : Comment | undefined {
212
210
let n = node . nextSibling
213
211
while ( n ) {
214
212
if ( isComment ( n , anchorLabel ) ) return n
215
213
n = n . nextSibling
216
214
}
215
+ }
217
216
218
- return null
217
+ export function isEmptyTextNode ( node : Node ) : node is Text {
218
+ return node . nodeType === 3 && ! ( node as Text ) . data . trim ( )
219
219
}
0 commit comments