@@ -195,6 +195,10 @@ function attemptResolveElement(
195
195
) ;
196
196
}
197
197
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
+ }
198
202
// This is a server-side component.
199
203
return type ( props ) ;
200
204
} else if ( typeof type === 'string' ) {
@@ -295,6 +299,52 @@ function serializeByRefID(id: number): string {
295
299
return '@' + id . toString ( 16 ) ;
296
300
}
297
301
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
+
298
348
function escapeStringValue ( value : string ) : string {
299
349
if ( value [ 0 ] === '$' || value [ 0 ] === '@' ) {
300
350
// We need to escape $ or @ prefixed strings since we use those to encode
@@ -561,45 +611,7 @@ export function resolveModelToJSON(
561
611
562
612
if ( typeof value === 'object' ) {
563
613
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 ) ) ;
603
615
} else if ( ( value : any ) . $$typeof === REACT_PROVIDER_TYPE ) {
604
616
const providerKey = ( ( value : any ) : ReactProviderType < any > ) . _context
605
617
. _globalName ;
@@ -673,6 +685,9 @@ export function resolveModelToJSON(
673
685
}
674
686
675
687
if ( typeof value === 'function' ) {
688
+ if ( isModuleReference ( value ) ) {
689
+ return serializeModuleReference ( request , parent , key , ( value : any ) ) ;
690
+ }
676
691
if ( / ^ o n [ A - Z ] / . test ( key ) ) {
677
692
throw new Error (
678
693
'Event handlers cannot be passed to client component props. ' +
0 commit comments