@@ -24,6 +24,7 @@ import {
2424 completeWriting ,
2525 flushBuffered ,
2626 close ,
27+ closeWithError ,
2728 processModelChunk ,
2829 processModuleChunk ,
2930 processSymbolChunk ,
@@ -83,16 +84,20 @@ export type Request = {
8384 completedErrorChunks : Array < Chunk > ,
8485 writtenSymbols : Map < Symbol , number> ,
8586 writtenModules : Map < ModuleKey , number> ,
87+ onError : ( error : mixed ) => void ,
8688 flowing : boolean ,
8789 toJSON : ( key : string , value : ReactModel ) => ReactJSONValue ,
8890} ;
8991
9092const ReactCurrentDispatcher = ReactSharedInternals . ReactCurrentDispatcher ;
9193
94+ function defaultErrorHandler ( ) { }
95+
9296export function createRequest (
9397 model : ReactModel ,
9498 destination : Destination ,
9599 bundlerConfig : BundlerConfig ,
100+ onError : ( error : mixed ) = > void = defaultErrorHandler ,
96101) : Request {
97102 const pingedSegments = [ ] ;
98103 const request = {
@@ -107,6 +112,7 @@ export function createRequest(
107112 completedErrorChunks : [ ] ,
108113 writtenSymbols : new Map ( ) ,
109114 writtenModules : new Map ( ) ,
115+ onError,
110116 flowing : false ,
111117 toJSON : function ( key : string , value : ReactModel ) : ReactJSONValue {
112118 return resolveModelToJSON ( request , this , key , value ) ;
@@ -413,6 +419,7 @@ export function resolveModelToJSON(
413419 x . then ( ping , ping ) ;
414420 return serializeByRefID ( newSegment . id ) ;
415421 } else {
422+ reportError ( request , x ) ;
416423 // Something errored. We'll still send everything we have up until this point.
417424 // We'll replace this element with a lazy reference that throws on the client
418425 // once it gets rendered.
@@ -589,6 +596,15 @@ export function resolveModelToJSON(
589596 );
590597}
591598
599+ function reportError ( request : Request , error : mixed ) : void {
600+ request . onError ( error ) ;
601+ }
602+
603+ function fatalError(request: Request, error: mixed): void {
604+ // This is called outside error handling code such as if an error happens in React internals.
605+ closeWithError ( request . destination , error ) ;
606+ }
607+
592608function emitErrorChunk(request: Request, id: number, error: mixed): void {
593609 // TODO: We should not leak error messages to the client in prod.
594610 // Give this an error code instead and log on the server.
@@ -654,6 +670,7 @@ function retrySegment(request: Request, segment: Segment): void {
654670 x . then ( ping , ping ) ;
655671 return ;
656672 } else {
673+ reportError ( request , x ) ;
657674 // This errored, we need to serialize this error to the
658675 emitErrorChunk ( request , segment . id , x ) ;
659676 }
@@ -666,18 +683,23 @@ function performWork(request: Request): void {
666683 ReactCurrentDispatcher . current = Dispatcher ;
667684 currentCache = request . cache ;
668685
669- const pingedSegments = request . pingedSegments ;
670- request . pingedSegments = [ ] ;
671- for ( let i = 0 ; i < pingedSegments . length ; i ++ ) {
672- const segment = pingedSegments [ i ] ;
673- retrySegment ( request , segment ) ;
674- }
675- if ( request . flowing ) {
676- flushCompletedChunks ( request ) ;
686+ try {
687+ const pingedSegments = request . pingedSegments ;
688+ request . pingedSegments = [ ] ;
689+ for ( let i = 0 ; i < pingedSegments . length ; i ++ ) {
690+ const segment = pingedSegments [ i ] ;
691+ retrySegment ( request , segment ) ;
692+ }
693+ if ( request . flowing ) {
694+ flushCompletedChunks ( request ) ;
695+ }
696+ } catch ( error ) {
697+ reportError ( request , error ) ;
698+ fatalError ( request , error ) ;
699+ } finally {
700+ ReactCurrentDispatcher . current = prevDispatcher ;
701+ currentCache = prevCache ;
677702 }
678-
679- ReactCurrentDispatcher . current = prevDispatcher ;
680- currentCache = prevCache ;
681703}
682704
683705let reentrant = false ;
@@ -749,7 +771,12 @@ export function startWork(request: Request): void {
749771
750772export function startFlowing ( request : Request ) : void {
751773 request . flowing = true ;
752- flushCompletedChunks ( request ) ;
774+ try {
775+ flushCompletedChunks ( request ) ;
776+ } catch ( error ) {
777+ reportError ( request , error ) ;
778+ fatalError ( request , error ) ;
779+ }
753780}
754781
755782function unsupportedHook ( ) : void {
0 commit comments