11import { warn } from '@vue/runtime-dom'
22import {
3+ type Anchor ,
34 insertionAnchor ,
45 insertionParent ,
56 resetInsertionState ,
@@ -36,12 +37,6 @@ export function withHydration(container: ParentNode, fn: () => void): void {
3637export let adoptTemplate : ( node : Node , template : string ) => Node | null
3738export let locateHydrationNode : ( ) => void
3839
39- type Anchor = Comment & {
40- // cached matching fragment start to avoid repeated traversal
41- // on nested fragments
42- $fs ?: Anchor
43- }
44-
4540const isComment = ( node : Node , data : string ) : node is Anchor =>
4641 node . nodeType === 8 && ( node as Comment ) . data === data
4742
@@ -77,41 +72,48 @@ function adoptTemplateImpl(node: Node, template: string): Node | null {
7772
7873function locateHydrationNodeImpl ( ) {
7974 let node : Node | null
80-
8175 // prepend / firstChild
8276 if ( insertionAnchor === 0 ) {
8377 node = child ( insertionParent ! )
8478 } 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 ++
111116 }
112- } else if ( isComment ( cur , ']' ) ) {
113- curFragEnd = cur
114- fragDepth ++
115117 }
116118 }
117119 }
@@ -127,3 +129,32 @@ function locateHydrationNodeImpl() {
127129 resetInsertionState ( )
128130 currentHydrationNode = node
129131}
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