@@ -21,8 +21,9 @@ export function genTemplates(
2121export function genChildren (
2222 dynamic : IRDynamicInfo ,
2323 context : CodegenContext ,
24- from : number ,
25- paths : number [ ] = [ ] ,
24+ from : string ,
25+ path : number [ ] = [ ] ,
26+ knownPaths : [ id : string , path : number [ ] ] [ ] = [ ] ,
2627) : CodeFragment [ ] {
2728 const { helper } = context
2829 const [ frag , push ] = buildCodeFragment ( )
@@ -34,7 +35,7 @@ export function genChildren(
3435 push ( ...genDirectivesForElement ( id , context ) )
3536 }
3637
37- let prev : [ id : number , elementIndex : number ] | undefined
38+ let prev : [ variable : string , elementIndex : number ] | undefined
3839 for ( const [ index , child ] of children . entries ( ) ) {
3940 if ( child . flags & DynamicFlag . NON_TEMPLATE ) {
4041 offset --
@@ -47,34 +48,81 @@ export function genChildren(
4748 : child . id
4849 : undefined
4950
50- const elementIndex = Number ( index ) + offset
51- const newPaths = [ ...paths , elementIndex ]
52-
53- if ( id === undefined ) {
54- push ( ...genChildren ( child , context , from , newPaths ) )
51+ if ( id === undefined && ! child . hasDynamicChild ) {
52+ const { id, template } = child
53+ if ( id !== undefined && template !== undefined ) {
54+ push ( NEWLINE , `const n${ id } = t${ template } ()` )
55+ push ( ...genDirectivesForElement ( id , context ) )
56+ }
5557 continue
5658 }
5759
58- push ( NEWLINE , `const n${ id } = ` )
60+ const elementIndex = Number ( index ) + offset
61+ const newPath = [ ...path , elementIndex ]
62+
63+ const variable = id === undefined ? `_n${ context . block . tempId ++ } ` : `n${ id } `
64+ push ( NEWLINE , `const ${ variable } = ` )
65+
5966 if ( prev ) {
6067 const offset = elementIndex - prev [ 1 ]
6168 if ( offset === 1 ) {
62- push ( `n ${ prev [ 0 ] } .nextSibling` )
69+ push ( ... genCall ( helper ( 'next' ) , prev [ 0 ] ) )
6370 } else {
64- push ( ...genCall ( helper ( 'next ' ) , `n ${ prev [ 0 ] } ` , String ( offset ) ) )
71+ push ( ...genCall ( helper ( 'nextn ' ) , prev [ 0 ] , String ( offset ) ) )
6572 }
6673 } else {
67- if ( newPaths . length === 1 && newPaths [ 0 ] === 0 ) {
68- push ( `n ${ from } .firstChild` )
74+ if ( newPath . length === 1 && newPath [ 0 ] === 0 ) {
75+ push ( ... genCall ( helper ( 'child' ) , from ) )
6976 } else {
70- push (
71- ...genCall ( helper ( 'children' ) , `n${ from } ` , ...newPaths . map ( String ) ) ,
72- )
77+ // check if there's a node that we can reuse from
78+ let resolvedFrom = from
79+ let resolvedPath = newPath
80+ let skipFirstChild = false
81+ outer: for ( const [ from , path ] of knownPaths ) {
82+ const l = path . length
83+ const tail = newPath . slice ( l )
84+ for ( let i = 0 ; i < l ; i ++ ) {
85+ const parentSeg = path [ i ]
86+ const thisSeg = newPath [ i ]
87+ if ( parentSeg !== thisSeg ) {
88+ if ( i === l - 1 ) {
89+ // last bit is reusable
90+ resolvedFrom = from
91+ resolvedPath = [ thisSeg - parentSeg , ...tail ]
92+ skipFirstChild = true
93+ break outer
94+ }
95+ break
96+ } else if ( i === l - 1 ) {
97+ // full overlap
98+ resolvedFrom = from
99+ resolvedPath = tail
100+ break outer
101+ }
102+ }
103+ }
104+ let init
105+ for ( const i of resolvedPath ) {
106+ init = init
107+ ? genCall ( helper ( 'child' ) , init )
108+ : skipFirstChild
109+ ? resolvedFrom
110+ : genCall ( helper ( 'child' ) , resolvedFrom )
111+ if ( i === 1 ) {
112+ init = genCall ( helper ( 'next' ) , init )
113+ } else if ( i > 1 ) {
114+ init = genCall ( helper ( 'nextn' ) , init , String ( i ) )
115+ }
116+ }
117+ push ( ...init ! )
73118 }
74119 }
75- push ( ...genDirectivesForElement ( id , context ) )
76- prev = [ id , elementIndex ]
77- push ( ...genChildren ( child , context , id , [ ] ) )
120+ if ( id !== undefined ) {
121+ push ( ...genDirectivesForElement ( id , context ) )
122+ }
123+ knownPaths . unshift ( [ variable , newPath ] )
124+ prev = [ variable , elementIndex ]
125+ push ( ...genChildren ( child , context , variable ) )
78126 }
79127
80128 return frag
0 commit comments