@@ -38,7 +38,7 @@ import type { DeserializeContainer, HostElement, ObjToProxyMap } from './types';
3838import { _CONST_PROPS , _VAR_PROPS } from './utils/constants' ;
3939import { isElement , isNode } from './utils/element' ;
4040import { EMPTY_ARRAY , EMPTY_OBJ } from './utils/flyweight' ;
41- import { ELEMENT_ID } from './utils/markers' ;
41+ import { ELEMENT_ID , ELEMENT_PROPS , QBackRefs } from './utils/markers' ;
4242import { isPromise } from './utils/promises' ;
4343import { SerializerSymbol , fastSkipSerialize } from './utils/serialize-utils' ;
4444import {
@@ -601,9 +601,8 @@ export function inflateQRL(container: DeserializeContainer, qrl: QRLInternal<any
601601
602602/** A selection of attributes of the real thing */
603603type SsrNode = {
604- nodeType : number ;
605604 id : string ;
606- childrenVNodeData : VNodeData [ ] | null ;
605+ children : ISsrNode [ ] | null ;
607606 vnodeData : VNodeData ;
608607 [ _EFFECT_BACK_REF ] : Map < EffectProperty | string , EffectSubscription > | null ;
609608} ;
@@ -679,7 +678,6 @@ export interface SerializationContext {
679678
680679 $getProp$ : ( obj : any , prop : string ) => any ;
681680 $setProp$ : ( obj : any , prop : string , value : any ) => void ;
682- $prepVNodeData$ ?: ( vNodeData : VNodeData ) => void ;
683681}
684682
685683export const createSerializationContext = (
@@ -690,19 +688,17 @@ export const createSerializationContext = (
690688 * server will not know what to do with them.
691689 */
692690 NodeConstructor : {
693- new ( ...rest : any [ ] ) : { nodeType : number ; id : string } ;
691+ new ( ...rest : any [ ] ) : { __brand__ : 'SsrNode' } ;
694692 } | null ,
695693 /** DomRef constructor, for instanceof checks. */
696694 DomRefConstructor : {
697- new ( ...rest : any [ ] ) : { $ssrNode$ : ISsrNode } ;
695+ new ( ...rest : any [ ] ) : { __brand__ : 'DomRef' } ;
698696 } | null ,
699697 symbolToChunkResolver : SymbolToChunkResolver ,
700698 getProp : ( obj : any , prop : string ) => any ,
701699 setProp : ( obj : any , prop : string , value : any ) => void ,
702700 storeProxyMap : ObjToProxyMap ,
703- writer ?: StreamWriter ,
704- // temporary until we serdes the vnode data here
705- prepVNodeData ?: ( vNodeData : VNodeData ) => void
701+ writer ?: StreamWriter
706702) : SerializationContext => {
707703 if ( ! writer ) {
708704 const buffer : string [ ] = [ ] ;
@@ -763,9 +759,10 @@ export const createSerializationContext = (
763759 return seen . $rootIndex$ ;
764760 } ;
765761
766- const isSsrNode = ( NodeConstructor ? ( obj ) => obj instanceof NodeConstructor : ( ) => false ) as (
767- obj : unknown
768- ) => obj is SsrNode ;
762+ const isSsrNode = (
763+ NodeConstructor ? ( obj ) => obj instanceof NodeConstructor : ( ( ( ) => false ) as any )
764+ ) as ( obj : unknown ) => obj is SsrNode ;
765+
769766 isDomRef = (
770767 DomRefConstructor ? ( obj ) => obj instanceof DomRefConstructor : ( ( ( ) => false ) as any )
771768 ) as ( obj : unknown ) => obj is DomRef ;
@@ -816,7 +813,6 @@ export const createSerializationContext = (
816813 $storeProxyMap$ : storeProxyMap ,
817814 $getProp$ : getProp ,
818815 $setProp$ : setProp ,
819- $prepVNodeData$ : prepVNodeData ,
820816 $pathMap$ : rootsPathMap ,
821817 } ;
822818} ;
@@ -847,8 +843,14 @@ const discoverValuesForVNodeData = (vnodeData: VNodeData, callback: (value: unkn
847843 for ( const value of vnodeData ) {
848844 if ( isSsrAttrs ( value ) ) {
849845 for ( let i = 1 ; i < value . length ; i += 2 ) {
846+ const keyValue = value [ i - 1 ] ;
850847 const attrValue = value [ i ] ;
851- if ( typeof attrValue === 'string' ) {
848+ if (
849+ typeof attrValue === 'string' ||
850+ // skip empty props
851+ ( keyValue === ELEMENT_PROPS &&
852+ Object . keys ( attrValue as Record < string , unknown > ) . length === 0 )
853+ ) {
852854 continue ;
853855 }
854856 callback ( attrValue ) ;
@@ -1192,14 +1194,25 @@ async function serialize(serializationContext: SerializationContext): Promise<vo
11921194 output ( TypeIds . VNode , value . id ) ;
11931195 const vNodeData = value . vnodeData ;
11941196 if ( vNodeData ) {
1195- serializationContext . $prepVNodeData$ ?.( vNodeData ) ;
11961197 discoverValuesForVNodeData ( vNodeData , ( vNodeDataValue ) => $addRoot$ ( vNodeDataValue ) ) ;
11971198 vNodeData [ 0 ] |= VNodeDataFlag . SERIALIZE ;
11981199 }
1199- if ( value . childrenVNodeData ) {
1200- for ( const vNodeData of value . childrenVNodeData ) {
1201- discoverValuesForVNodeData ( vNodeData , ( vNodeDataValue ) => $addRoot$ ( vNodeDataValue ) ) ;
1202- vNodeData [ 0 ] |= VNodeDataFlag . SERIALIZE ;
1200+ if ( value . children ) {
1201+ // can be static, but we need to save vnode data structure + discover the back refs
1202+ for ( const child of value . children ) {
1203+ const childVNodeData = child . vnodeData ;
1204+ if ( childVNodeData ) {
1205+ // add all back refs to the roots
1206+ for ( const value of childVNodeData ) {
1207+ if ( isSsrAttrs ( value ) ) {
1208+ const backRefKeyIndex = value . findIndex ( ( v ) => v === QBackRefs ) ;
1209+ if ( backRefKeyIndex !== - 1 ) {
1210+ $addRoot$ ( value [ backRefKeyIndex + 1 ] ) ;
1211+ }
1212+ }
1213+ }
1214+ childVNodeData [ 0 ] |= VNodeDataFlag . SERIALIZE ;
1215+ }
12031216 }
12041217 }
12051218 } else if ( typeof FormData !== 'undefined' && value instanceof FormData ) {
0 commit comments