Skip to content

Commit dfa61e2

Browse files
committed
Integrate changes from facebook/react#26360 (Flight Reply)
1 parent 0c852d3 commit dfa61e2

8 files changed

+124
-52
lines changed

package-lock.json

Lines changed: 19 additions & 19 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,10 @@
3030
"cssnano": "^5.1.15",
3131
"history": "^5.3.0",
3232
"htmlescape": "^1.1.1",
33-
"react": "18.3.0-next-703c67560-20230307",
34-
"react-dom": "18.3.0-next-703c67560-20230307",
33+
"react": "18.3.0-next-f828bad38-20230313",
34+
"react-dom": "18.3.0-next-f828bad38-20230313",
3535
"react-markdown": "^8.0.5",
36-
"react-server-dom-webpack": "18.3.0-next-703c67560-20230307",
36+
"react-server-dom-webpack": "18.3.0-next-f828bad38-20230313",
3737
"server-only": "^0.0.1"
3838
},
3939
"devDependencies": {

src/call-server.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
1-
import type {Thenable} from 'react';
1+
import type {ReactServerValue} from 'react-server-dom-webpack';
22
import ReactServerDOMClient from 'react-server-dom-webpack/client.browser';
33

4-
export function callServer(id: string, args: unknown): Thenable<unknown> {
4+
export async function callServer(
5+
id: string,
6+
args: ReactServerValue,
7+
): Promise<unknown> {
58
return ReactServerDOMClient.createFromFetch(
69
fetch(`/`, {
710
method: `POST`,
811
headers: {'accept': `text/x-component`, 'x-rsc-action': id},
9-
body: JSON.stringify(args),
12+
body: await ReactServerDOMClient.encodeReply(args),
1013
}),
1114
);
1215
}

src/workers/rsc/index.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as React from 'react';
2-
import type {WebpackMap} from 'react-server-dom-webpack';
2+
import type {ClientManifest} from 'react-server-dom-webpack';
33
import ReactServerDOMServer from 'react-server-dom-webpack/server';
44
import {App} from '../../components/server/app.js';
55
import {PathnameServerContextName} from '../../pathname-server-context.js';
@@ -31,7 +31,7 @@ const handleGet: ExportedHandlerFetchHandler<EnvWithStaticContent> = async (
3131
/>
3232
<App />
3333
</>,
34-
reactClientManifest as WebpackMap,
34+
reactClientManifest as ClientManifest,
3535
{
3636
context: [
3737
[`WORKAROUND`, null], // TODO: First value has a bug where the value is not set on the second request: https://github.com/facebook/react/issues/24849
@@ -69,7 +69,8 @@ const handlePost: ExportedHandlerFetchHandler<EnvWithStaticContent> = async (
6969
return new Response(null, {status: 500});
7070
}
7171

72-
const args = (await request.json()) as unknown[];
72+
const body = await request.text();
73+
const args = await ReactServerDOMServer.decodeReply(body);
7374
const actionPromise = action.apply(null, args);
7475

7576
const reactClientManifest = await getJsonFromKv(
@@ -79,11 +80,13 @@ const handlePost: ExportedHandlerFetchHandler<EnvWithStaticContent> = async (
7980

8081
const rscStream = ReactServerDOMServer.renderToReadableStream(
8182
actionPromise,
82-
reactClientManifest as WebpackMap,
83+
reactClientManifest as ClientManifest,
8384
{
8485
onError: (error) => {
8586
console.error(error);
8687

88+
// TODO: Sending the error message as digest kind of defeats the purpose
89+
// of having a digest to mask the error in production.
8790
return error instanceof Error ? error.message : `Unknown Error`;
8891
},
8992
},

src/workers/rsc/is-valid-server-reference.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import type {ReactModel} from 'react-server-dom-webpack/server';
1+
import type {ReactClientValue} from 'react-server-dom-webpack';
22

33
export function isValidServerReference(
44
action: unknown,
5-
): action is (...args: unknown[]) => Promise<ReactModel> {
5+
): action is (...args: unknown[]) => Promise<ReactClientValue> {
66
// TODO: Check against a server reference manifest.
77
return (
88
typeof action === `function` &&

types/react-server-dom-webpack-client.d.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
declare module 'react-server-dom-webpack/client.browser' {
22
import type {Thenable} from 'react';
3-
import type {WebpackMap} from 'react-server-dom-webpack';
3+
import type {
4+
ClientManifest,
5+
ReactServerValue,
6+
ServerReference,
7+
} from 'react-server-dom-webpack';
48

59
export interface ReactServerDomClientOptions {
610
callServer?: CallServerCallback;
711
}
812

913
export type CallServerCallback = (
1014
id: string,
11-
args: unknown,
15+
args: ReactServerValue,
1216
) => Thenable<unknown>;
1317

1418
export function createFromFetch<T>(
@@ -20,14 +24,18 @@ declare module 'react-server-dom-webpack/client.browser' {
2024
stream: ReadableStream,
2125
options?: ReactServerDomClientOptions,
2226
): Thenable<T>;
27+
28+
export function encodeReply(
29+
value: ReactServerValue,
30+
): Promise<string | FormData>;
2331
}
2432

2533
declare module 'react-server-dom-webpack/client.edge' {
2634
import type {Thenable} from 'react';
27-
import type {WebpackMap} from 'react-server-dom-webpack';
35+
import type {SSRManifest} from 'react-server-dom-webpack';
2836

2937
export interface CreateFromReadableStreamOptions {
30-
moduleMap?: WebpackMap;
38+
moduleMap?: SSRManifest;
3139
}
3240

3341
export function createFromReadableStream<T>(
Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,10 @@
11
declare module 'react-server-dom-webpack/server' {
2-
import type {ReactElement} from 'react';
3-
import type {WebpackMap} from 'react-server-dom-webpack';
4-
5-
export type ReactModel =
6-
| ReactElement
7-
| LazyComponent<any, any>
8-
| string
9-
| boolean
10-
| number
11-
| symbol
12-
| null
13-
| Iterable<ReactModel>
14-
| {[key: string]: ReactModel}
15-
| Promise<ReactModel>;
2+
import type {ReactElement, Thenable} from 'react';
3+
import type {
4+
ClientManifest,
5+
ReactClientValue,
6+
ReactServerValue,
7+
} from 'react-server-dom-webpack';
168

179
export type LazyComponent<T, P> = {
1810
$$typeof: symbol | number;
@@ -36,8 +28,10 @@ declare module 'react-server-dom-webpack/server' {
3628
| {[key: string]: ServerContextJSONValue};
3729

3830
export function renderToReadableStream(
39-
model: ReactModel,
40-
webpackMap?: WebpackMap | null,
31+
model: ReactClientValue,
32+
webpackMap?: ClientManifest | null,
4133
options?: RenderToReadableStreamOptions,
4234
): ReadableStream<Uint8Array>;
35+
36+
export function decodeReply(body: string | FormData): Thenable<unknown[]>;
4337
}

types/react-server-dom-webpack.d.ts

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,75 @@
11
declare module 'react-server-dom-webpack' {
2-
export interface WebpackMap {
2+
import type {
3+
Component,
4+
Context,
5+
LazyExoticComponent,
6+
ReactElement,
7+
} from 'react';
8+
9+
export interface ClientManifest {
310
[id: string]: ClientReferenceMetadata;
411
}
512

13+
export interface SSRManifest {
14+
[clientId: string]: {
15+
[clientExportName: string]: ClientReferenceMetadata;
16+
};
17+
}
18+
619
export interface ClientReferenceMetadata {
720
id: string;
821
chunks: string[];
922
name: string;
1023
}
24+
25+
export interface ServerReference {
26+
$$typeof: symbol;
27+
$$id: string;
28+
$$bound: null | ReactClientValue[];
29+
}
30+
31+
// Serializable values for the client
32+
export type ReactClientValue =
33+
// Server Elements and Lazy Components are unwrapped on the Server
34+
| ReactElement
35+
| LazyExoticComponent<ReactClientValue>
36+
// References are passed by their value
37+
| ClientReferenceMetadata
38+
| ServerReference
39+
// The rest are passed as is. Sub-types can be passed in but lose their
40+
// subtype, so the receiver can only accept once of these.
41+
| ReactElement<string>
42+
| ReactElement<ClientReferenceMetadata>
43+
| Context<any> // ServerContext
44+
| string
45+
| boolean
46+
| number
47+
| symbol
48+
| null
49+
| void
50+
| Iterable<ReactClientValue>
51+
| ReactClientValue[]
52+
| ReactClientObject
53+
| Promise<ReactClientValue>; // Thenable<ReactClientValue>
54+
55+
export type ReactClientObject = {[key: string]: ReactClientValue};
56+
57+
// Serializable values for the server
58+
export type ReactServerValue =
59+
// References are passed by their value
60+
| ServerReference
61+
// The rest are passed as is. Sub-types can be passed in but lose their
62+
// subtype, so the receiver can only accept once of these.
63+
| string
64+
| boolean
65+
| number
66+
| symbol
67+
| null
68+
| void
69+
| Iterable<ReactServerValue>
70+
| ReactServerValue[]
71+
| ReactServerObject
72+
| Promise<ReactServerValue>; // Thenable<ReactServerValue>
73+
74+
export type ReactServerObject = {[key: string]: ReactServerValue};
1175
}

0 commit comments

Comments
 (0)