1
1
import { warn } from '@vue/runtime-dom'
2
2
import {
3
+ type Anchor ,
3
4
insertionAnchor ,
4
5
insertionParent ,
5
6
resetInsertionState ,
@@ -36,12 +37,6 @@ export function withHydration(container: ParentNode, fn: () => void): void {
36
37
export let adoptTemplate : ( node : Node , template : string ) => Node | null
37
38
export let locateHydrationNode : ( ) => void
38
39
39
- type Anchor = Comment & {
40
- // cached matching fragment start to avoid repeated traversal
41
- // on nested fragments
42
- $fs ?: Anchor
43
- }
44
-
45
40
const isComment = ( node : Node , data : string ) : node is Anchor =>
46
41
node . nodeType === 8 && ( node as Comment ) . data === data
47
42
@@ -77,41 +72,48 @@ function adoptTemplateImpl(node: Node, template: string): Node | null {
77
72
78
73
function locateHydrationNodeImpl ( ) {
79
74
let node : Node | null
80
-
81
75
// prepend / firstChild
82
76
if ( insertionAnchor === 0 ) {
83
77
node = child ( insertionParent ! )
84
78
} else {
85
- node = insertionAnchor
86
- ? insertionAnchor . previousSibling
87
- : insertionParent
88
- ? insertionParent . lastChild
89
- : currentHydrationNode
90
-
91
- if ( node && isComment ( node , ']' ) ) {
92
- // fragment backward search
93
- if ( node . $fs ) {
94
- // already cached matching fragment start
95
- node = node . $fs
96
- } else {
97
- let cur : Node | null = node
98
- let curFragEnd = node
99
- let fragDepth = 0
100
- node = null
101
- while ( cur ) {
102
- cur = cur . previousSibling
103
- if ( cur ) {
104
- if ( isComment ( cur , '[' ) ) {
105
- curFragEnd . $fs = cur
106
- if ( ! fragDepth ) {
107
- node = cur
108
- break
109
- } else {
110
- fragDepth --
79
+ // dynamic child anchor `<!--[[-->`
80
+ if ( insertionAnchor && isDynamicStart ( insertionAnchor ) ) {
81
+ const anchor = ( insertionParent ! . lds = insertionParent ! . lds
82
+ ? // continuous dynamic children, the next dynamic start must exist
83
+ locateNextDynamicStart ( insertionParent ! . lds ) !
84
+ : insertionAnchor )
85
+ node = anchor . nextSibling
86
+ } else {
87
+ node = insertionAnchor
88
+ ? insertionAnchor . previousSibling
89
+ : insertionParent
90
+ ? insertionParent . lastChild
91
+ : currentHydrationNode
92
+ if ( node && isComment ( node , ']' ) ) {
93
+ // fragment backward search
94
+ if ( node . $fs ) {
95
+ // already cached matching fragment start
96
+ node = node . $fs
97
+ } else {
98
+ let cur : Node | null = node
99
+ let curFragEnd = node
100
+ let fragDepth = 0
101
+ node = null
102
+ while ( cur ) {
103
+ cur = cur . previousSibling
104
+ if ( cur ) {
105
+ if ( isComment ( cur , '[' ) ) {
106
+ curFragEnd . $fs = cur
107
+ if ( ! fragDepth ) {
108
+ node = cur
109
+ break
110
+ } else {
111
+ fragDepth --
112
+ }
113
+ } else if ( isComment ( cur , ']' ) ) {
114
+ curFragEnd = cur
115
+ fragDepth ++
111
116
}
112
- } else if ( isComment ( cur , ']' ) ) {
113
- curFragEnd = cur
114
- fragDepth ++
115
117
}
116
118
}
117
119
}
@@ -127,3 +129,32 @@ function locateHydrationNodeImpl() {
127
129
resetInsertionState ( )
128
130
currentHydrationNode = node
129
131
}
132
+
133
+ function isDynamicStart ( node : Node ) : node is Anchor {
134
+ return isComment ( node , '[[' )
135
+ }
136
+
137
+ function locateNextDynamicStart ( anchor : Anchor ) : Anchor | undefined {
138
+ let cur : Node | null = anchor
139
+ let end = null
140
+ let depth = 0
141
+ while ( cur ) {
142
+ cur = cur . nextSibling
143
+ if ( cur ) {
144
+ if ( isComment ( cur , '[[' ) ) {
145
+ depth ++
146
+ } else if ( isComment ( cur , ']]' ) ) {
147
+ if ( ! depth ) {
148
+ end = cur
149
+ break
150
+ } else {
151
+ depth --
152
+ }
153
+ }
154
+ }
155
+ }
156
+
157
+ if ( end ) {
158
+ return end ! . nextSibling as Anchor
159
+ }
160
+ }
0 commit comments