@samitouri / QOS-React-2 / commits / fd0511c728

[Flight] Add support BigInt support (#26479)

## Summary Adds support for sending `BigInt` to Flight and Flight Reply ## How did you test this change? - added tests

Sebastian Silbermann committed Mar 29, 2023 at 18:23 UTC fd0511c728e186905b7f0e71f072b4b247d6f29f
11 files changed +51 -7
.eslintrc.js
+3
@@ -449,6 +449,9 @@ module.exports = {
449 $ReadOnlyArray: 'readonly',
450 $Shape: 'readonly',
451 AnimationFrameID: 'readonly',
452 + // For Flow type annotation. Only `BigInt` is valid at runtime.
453 + bigint: 'readonly',
454 + BigInt: 'readonly',
455 Class: 'readonly',
456 ClientRect: 'readonly',
457 CopyInspectedElementPath: 'readonly',
packages/react-client/src/ReactFlightClient.js
+4
@@ -564,6 +564,10 @@ export function parseModelString(
564 // Special encoding for `undefined` which can't be serialized as JSON otherwise.
565 return undefined;
566 }
567 + case 'n': {
568 + // BigInt
569 + return BigInt(value.substring(2));
570 + }
571 default: {
572 // We assume that anything else is a reference ID.
573 const id = parseInt(value.substring(1), 16);
packages/react-client/src/ReactFlightReplyClient.js
+5 -3
@@ -75,6 +75,10 @@ function serializeUndefined(): string {
75 return '$undefined';
76 }
77
78 +function serializeBigInt(n: bigint): string {
79 + return '$n' + n.toString(10);
80 +}
81 +
82 function escapeStringValue(value: string): string {
83 if (value[0] === '$') {
84 // We need to escape $ prefixed strings since we use those to encode
@@ -264,9 +268,7 @@ export function processReply(
268 }
269
270 if (typeof value === 'bigint') {
267 - throw new Error(
268 - `BigInt (${value}) is not yet supported as an argument to a Server Function.`,
269 - );
271 + return serializeBigInt(value);
272 }
273
274 throw new Error(
packages/react-client/src/__tests__/ReactFlight-test.js
+19
@@ -229,6 +229,25 @@ describe('ReactFlight', () => {
229 expect(ReactNoop).toMatchRenderedOutput(null);
230 });
231
232 + it('can transport BigInt', async () => {
233 + function ComponentClient({prop}) {
234 + return `prop: ${prop} (${typeof prop})`;
235 + }
236 + const Component = clientReference(ComponentClient);
237 +
238 + const model = <Component prop={90071992547409910000n} />;
239 +
240 + const transport = ReactNoopFlightServer.render(model);
241 +
242 + await act(async () => {
243 + ReactNoop.render(await ReactNoopFlightClient.read(transport));
244 + });
245 +
246 + expect(ReactNoop).toMatchRenderedOutput(
247 + 'prop: 90071992547409910000 (bigint)',
248 + );
249 + });
250 +
251 it('can render a lazy component as a shared component on the server', async () => {
252 function SharedComponent({text}) {
253 return (
packages/react-server-dom-webpack/src/__tests__/ReactFlightDOMReply-test.js
+7
@@ -75,4 +75,11 @@ describe('ReactFlightDOMReply', () => {
75 }
76 expect(items).toEqual(['A', 'B', 'C']);
77 });
78 +
79 + it('can pass a BigInt as a reply', async () => {
80 + const body = await ReactServerDOMClient.encodeReply(90071992547409910000n);
81 + const n = await ReactServerDOMServer.decodeReply(body, webpackServerMap);
82 +
83 + expect(n).toEqual(90071992547409910000n);
84 + });
85 });
packages/react-server/src/ReactFlightReplyServer.js
+4
@@ -402,6 +402,10 @@ function parseModelString(
402 // Special encoding for `undefined` which can't be serialized as JSON otherwise.
403 return undefined;
404 }
405 + case 'n': {
406 + // BigInt
407 + return BigInt(value.substring(2));
408 + }
409 default: {
410 // We assume that anything else is a reference ID.
411 const id = parseInt(value.substring(1), 16);
packages/react-server/src/ReactFlightServer.js
+5 -4
@@ -553,6 +553,10 @@ function serializeUndefined(): string {
553 return '$undefined';
554 }
555
556 +function serializeBigInt(n: bigint): string {
557 + return '$n' + n.toString(10);
558 +}
559 +
560 function serializeClientReference(
561 request: Request,
562 parent:
@@ -931,10 +935,7 @@ export function resolveModelToJSON(
935 }
936
937 if (typeof value === 'bigint') {
934 - throw new Error(
935 - `BigInt (${value}) is not yet supported in Client Component props.` +
936 - describeObjectForErrorMessage(parent, key),
937 - );
938 + return serializeBigInt(value);
939 }
940
941 throw new Error(
scripts/rollup/validate/eslintrc.esm.js
+1
@@ -7,6 +7,7 @@ module.exports = {
7 },
8 globals: {
9 // ES 6
10 + BigInt: 'readonly',
11 Map: 'readonly',
12 Set: 'readonly',
13 Proxy: 'readonly',
scripts/rollup/validate/eslintrc.fb.js
+1
@@ -7,6 +7,7 @@ module.exports = {
7 },
8 globals: {
9 // ES6
10 + BigInt: 'readonly',
11 Map: 'readonly',
12 Set: 'readonly',
13 Symbol: 'readonly',
scripts/rollup/validate/eslintrc.rn.js
+1
@@ -7,6 +7,7 @@ module.exports = {
7 },
8 globals: {
9 // ES6
10 + BigInt: 'readonly',
11 Map: 'readonly',
12 Set: 'readonly',
13 Symbol: 'readonly',
scripts/rollup/validate/eslintrc.umd.js
+1
@@ -6,6 +6,7 @@ module.exports = {
6 },
7 globals: {
8 // ES6
9 + BigInt: 'readonly',
10 Map: 'readonly',
11 Set: 'readonly',
12 Symbol: 'readonly',