@@ -195,6 +195,10 @@ function attemptResolveElement(
195195 ) ;
196196 }
197197 if ( typeof type === 'function' ) {
198+ if ( isModuleReference ( type ) ) {
199+ // This is a reference to a client component.
200+ return [ REACT_ELEMENT_TYPE , type , key , props ] ;
201+ }
198202 // This is a server-side component.
199203 return type ( props ) ;
200204 } else if ( typeof type === 'string' ) {
@@ -295,6 +299,52 @@ function serializeByRefID(id: number): string {
295299 return '@' + id . toString ( 16 ) ;
296300}
297301
302+ function serializeModuleReference (
303+ request : Request ,
304+ parent : { + [ key : string | number ] : ReactModel } | $ReadOnlyArray < ReactModel > ,
305+ key : string ,
306+ moduleReference : ModuleReference < any > ,
307+ ) : string {
308+ const moduleKey : ModuleKey = getModuleKey ( moduleReference ) ;
309+ const writtenModules = request . writtenModules ;
310+ const existingId = writtenModules . get ( moduleKey ) ;
311+ if ( existingId !== undefined ) {
312+ if ( parent [ 0 ] === REACT_ELEMENT_TYPE && key === '1' ) {
313+ // If we're encoding the "type" of an element, we can refer
314+ // to that by a lazy reference instead of directly since React
315+ // knows how to deal with lazy values. This lets us suspend
316+ // on this component rather than its parent until the code has
317+ // loaded.
318+ return serializeByRefID ( existingId ) ;
319+ }
320+ return serializeByValueID ( existingId ) ;
321+ }
322+ try {
323+ const moduleMetaData : ModuleMetaData = resolveModuleMetaData (
324+ request . bundlerConfig ,
325+ moduleReference ,
326+ ) ;
327+ request . pendingChunks ++ ;
328+ const moduleId = request . nextChunkId ++ ;
329+ emitModuleChunk ( request , moduleId , moduleMetaData ) ;
330+ writtenModules . set ( moduleKey , moduleId ) ;
331+ if ( parent [ 0 ] === REACT_ELEMENT_TYPE && key === '1' ) {
332+ // If we're encoding the "type" of an element, we can refer
333+ // to that by a lazy reference instead of directly since React
334+ // knows how to deal with lazy values. This lets us suspend
335+ // on this component rather than its parent until the code has
336+ // loaded.
337+ return serializeByRefID ( moduleId ) ;
338+ }
339+ return serializeByValueID ( moduleId ) ;
340+ } catch ( x ) {
341+ request . pendingChunks ++ ;
342+ const errorId = request . nextChunkId ++ ;
343+ emitErrorChunk ( request , errorId , x ) ;
344+ return serializeByValueID ( errorId ) ;
345+ }
346+ }
347+
298348function escapeStringValue ( value : string ) : string {
299349 if ( value [ 0 ] === '$' || value [ 0 ] === '@' ) {
300350 // We need to escape $ or @ prefixed strings since we use those to encode
@@ -561,45 +611,7 @@ export function resolveModelToJSON(
561611
562612 if ( typeof value === 'object' ) {
563613 if ( isModuleReference ( value ) ) {
564- const moduleReference : ModuleReference < any > = ( value : any ) ;
565- const moduleKey : ModuleKey = getModuleKey ( moduleReference ) ;
566- const writtenModules = request . writtenModules ;
567- const existingId = writtenModules . get ( moduleKey ) ;
568- if ( existingId !== undefined ) {
569- if ( parent [ 0 ] === REACT_ELEMENT_TYPE && key === '1' ) {
570- // If we're encoding the "type" of an element, we can refer
571- // to that by a lazy reference instead of directly since React
572- // knows how to deal with lazy values. This lets us suspend
573- // on this component rather than its parent until the code has
574- // loaded.
575- return serializeByRefID ( existingId ) ;
576- }
577- return serializeByValueID ( existingId ) ;
578- }
579- try {
580- const moduleMetaData : ModuleMetaData = resolveModuleMetaData (
581- request . bundlerConfig ,
582- moduleReference ,
583- ) ;
584- request . pendingChunks ++ ;
585- const moduleId = request . nextChunkId ++ ;
586- emitModuleChunk ( request , moduleId , moduleMetaData ) ;
587- writtenModules . set ( moduleKey , moduleId ) ;
588- if ( parent [ 0 ] === REACT_ELEMENT_TYPE && key === '1' ) {
589- // If we're encoding the "type" of an element, we can refer
590- // to that by a lazy reference instead of directly since React
591- // knows how to deal with lazy values. This lets us suspend
592- // on this component rather than its parent until the code has
593- // loaded.
594- return serializeByRefID ( moduleId ) ;
595- }
596- return serializeByValueID ( moduleId ) ;
597- } catch ( x ) {
598- request . pendingChunks ++ ;
599- const errorId = request . nextChunkId ++ ;
600- emitErrorChunk ( request , errorId , x ) ;
601- return serializeByValueID ( errorId ) ;
602- }
614+ return serializeModuleReference ( request , parent , key , ( value : any ) ) ;
603615 } else if ( ( value : any ) . $$typeof === REACT_PROVIDER_TYPE ) {
604616 const providerKey = ( ( value : any ) : ReactProviderType < any > ) . _context
605617 . _globalName ;
@@ -673,6 +685,9 @@ export function resolveModelToJSON(
673685 }
674686
675687 if ( typeof value === 'function' ) {
688+ if ( isModuleReference ( value ) ) {
689+ return serializeModuleReference ( request , parent , key , ( value : any ) ) ;
690+ }
676691 if ( / ^ o n [ A - Z ] / . test ( key ) ) {
677692 throw new Error (
678693 'Event handlers cannot be passed to client component props. ' +
0 commit comments