Skip to content

Commit ac60e73

Browse files
sebmarkbageunstubbable
authored andcommitted
Patch Promise cycles and toString on Server Functions
Co-authored-by: Hendrik Liebau <[email protected]>
1 parent 6bc6b1c commit ac60e73

File tree

8 files changed

+157
-103
lines changed

8 files changed

+157
-103
lines changed

packages/react-client/src/ReactFlightClient.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1372,7 +1372,7 @@ function parseModelString(
13721372
// Symbol
13731373
return Symbol.for(value.slice(2));
13741374
}
1375-
case 'F': {
1375+
case 'h': {
13761376
// Server Reference
13771377
const ref = value.slice(2);
13781378
return getOutlinedModel(

packages/react-client/src/ReactFlightReplyClient.js

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -107,15 +107,14 @@ function serializePromiseID(id: number): string {
107107
}
108108

109109
function serializeServerReferenceID(id: number): string {
110-
return '$F' + id.toString(16);
110+
return '$h' + id.toString(16);
111111
}
112112

113113
function serializeTemporaryReferenceMarker(): string {
114114
return '$T';
115115
}
116116

117117
function serializeFormDataReference(id: number): string {
118-
// Why K? F is "Function". D is "Date". What else?
119118
return '$K' + id.toString(16);
120119
}
121120

@@ -477,8 +476,22 @@ export function processReply(
477476
}
478477
}
479478

479+
const existingReference = writtenObjects.get(value);
480+
480481
// $FlowFixMe[method-unbinding]
481482
if (typeof value.then === 'function') {
483+
if (existingReference !== undefined) {
484+
if (modelRoot === value) {
485+
// This is the ID we're currently emitting so we need to write it
486+
// once but if we discover it again, we refer to it by id.
487+
modelRoot = null;
488+
} else {
489+
// We've already emitted this as an outlined object, so we can
490+
// just refer to that by its existing ID.
491+
return existingReference;
492+
}
493+
}
494+
482495
// We assume that any object with a .then property is a "Thenable" type,
483496
// or a Promise type. Either of which can be represented by a Promise.
484497
if (formData === null) {
@@ -487,11 +500,19 @@ export function processReply(
487500
}
488501
pendingParts++;
489502
const promiseId = nextPartId++;
503+
const promiseReference = serializePromiseID(promiseId);
504+
writtenObjects.set(value, promiseReference);
490505
const thenable: Thenable<any> = (value: any);
491506
thenable.then(
492507
partValue => {
493508
try {
494-
const partJSON = serializeModel(partValue, promiseId);
509+
const previousReference = writtenObjects.get(partValue);
510+
let partJSON;
511+
if (previousReference !== undefined) {
512+
partJSON = JSON.stringify(previousReference);
513+
} else {
514+
partJSON = serializeModel(partValue, promiseId);
515+
}
495516
// $FlowFixMe[incompatible-type] We know it's not null because we assigned it above.
496517
const data: FormData = formData;
497518
data.append(formFieldPrefix + promiseId, partJSON);
@@ -507,10 +528,9 @@ export function processReply(
507528
// that throws on the server instead.
508529
reject,
509530
);
510-
return serializePromiseID(promiseId);
531+
return promiseReference;
511532
}
512533

513-
const existingReference = writtenObjects.get(value);
514534
if (existingReference !== undefined) {
515535
if (modelRoot === value) {
516536
// This is the ID we're currently emitting so we need to write it

packages/react-server-dom-esm/src/ReactFlightESMReferences.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,12 @@ function bind(this: ServerReference<any>): any {
8888
return newFn;
8989
}
9090

91+
const serverReferenceToString = {
92+
value: () => 'function () { [omitted code] }',
93+
configurable: true,
94+
writable: true,
95+
};
96+
9197
export function registerServerReference<T: Function>(
9298
reference: T,
9399
id: string,
@@ -111,12 +117,14 @@ export function registerServerReference<T: Function>(
111117
configurable: true,
112118
},
113119
bind: {value: bind, configurable: true},
120+
toString: serverReferenceToString,
114121
}
115122
: {
116123
$$typeof,
117124
$$id,
118125
$$bound,
119126
bind: {value: bind, configurable: true},
127+
toString: serverReferenceToString,
120128
},
121129
);
122130
}

packages/react-server-dom-turbopack/src/ReactFlightTurbopackReferences.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,12 @@ function bind(this: ServerReference<any>): any {
102102
return newFn;
103103
}
104104

105+
const serverReferenceToString = {
106+
value: () => 'function () { [omitted code] }',
107+
configurable: true,
108+
writable: true,
109+
};
110+
105111
export function registerServerReference<T: Function>(
106112
reference: T,
107113
id: string,
@@ -125,12 +131,14 @@ export function registerServerReference<T: Function>(
125131
configurable: true,
126132
},
127133
bind: {value: bind, configurable: true},
134+
toString: serverReferenceToString,
128135
}
129136
: {
130137
$$typeof,
131138
$$id,
132139
$$bound,
133140
bind: {value: bind, configurable: true},
141+
toString: serverReferenceToString,
134142
},
135143
);
136144
}

packages/react-server-dom-webpack/src/ReactFlightWebpackReferences.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,12 @@ function bind(this: ServerReference<any>): any {
103103
return newFn;
104104
}
105105

106+
const serverReferenceToString = {
107+
value: () => 'function () { [omitted code] }',
108+
configurable: true,
109+
writable: true,
110+
};
111+
106112
export function registerServerReference<T: Function>(
107113
reference: T,
108114
id: string,
@@ -126,12 +132,14 @@ export function registerServerReference<T: Function>(
126132
configurable: true,
127133
},
128134
bind: {value: bind, configurable: true},
135+
toString: serverReferenceToString,
129136
}
130137
: {
131138
$$typeof,
132139
$$id,
133140
$$bound,
134141
bind: {value: bind, configurable: true},
142+
toString: serverReferenceToString,
135143
},
136144
);
137145
}

0 commit comments

Comments
 (0)