@parcel/rsc 2.13.1-canary.3399 → 2.13.1-canary.3401
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/node.d.ts +5 -1
- package/lib/server.d.ts +4 -2
- package/package.json +2 -2
- package/src/node.tsx +30 -7
- package/src/server.tsx +63 -9
package/lib/node.d.ts
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
/* @jsxRuntime automatic */ import type { IncomingMessage, ServerResponse } from 'http';
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
2
3
|
import { Readable } from 'stream';
|
|
3
4
|
import { RSCToHTMLOptions, RSCOptions } from './server';
|
|
4
5
|
export declare function renderRSC(root: any, options?: RSCOptions): Readable;
|
|
5
6
|
export declare function renderHTML(root: any, options?: RSCToHTMLOptions): Promise<Readable>;
|
|
6
|
-
export
|
|
7
|
+
export interface RenderRequestOptions extends RSCToHTMLOptions {
|
|
8
|
+
renderError?: (err: Error) => ReactNode;
|
|
9
|
+
}
|
|
10
|
+
export declare function renderRequest(request: IncomingMessage, response: ServerResponse, root: any, options?: RenderRequestOptions): Promise<void>;
|
|
7
11
|
export declare function callAction(request: IncomingMessage, id: string | null | undefined): Promise<{
|
|
8
12
|
result: any;
|
|
9
13
|
}>;
|
package/lib/server.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* @jsxRuntime automatic */ import type { ErrorInfo } from 'react-dom/client';
|
|
2
|
-
import { ComponentType } from 'react' with {
|
|
2
|
+
import { ComponentType, ReactNode } from 'react' with {
|
|
3
3
|
env: 'react-client'
|
|
4
4
|
};
|
|
5
5
|
export interface RSCOptions {
|
|
@@ -22,11 +22,13 @@ export interface RSCToHTMLOptions {
|
|
|
22
22
|
temporaryReferences?: any;
|
|
23
23
|
onError?: (error: unknown, errorInfo?: ErrorInfo) => string | void;
|
|
24
24
|
}
|
|
25
|
-
export declare function
|
|
25
|
+
export declare function renderHTML(root: any, options?: RSCToHTMLOptions): Promise<ReadableStream>;
|
|
26
26
|
export interface RenderRequestOptions extends RSCToHTMLOptions {
|
|
27
27
|
headers?: HeadersInit;
|
|
28
|
+
renderError?: (err: Error) => ReactNode;
|
|
28
29
|
}
|
|
29
30
|
export declare function renderRequest(request: Request, root: any, options?: RenderRequestOptions): Promise<Response>;
|
|
30
31
|
export declare function callAction(request: Request, id: string | null | undefined): Promise<{
|
|
31
32
|
result: any;
|
|
32
33
|
}>;
|
|
34
|
+
export declare function renderDevError(error: Error, options: RSCToHTMLOptions): Promise<ReadableStream | string>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parcel/rsc",
|
|
3
|
-
"version": "2.13.1-canary.
|
|
3
|
+
"version": "2.13.1-canary.3401+b50bc79cb",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -41,5 +41,5 @@
|
|
|
41
41
|
"react": "^19",
|
|
42
42
|
"react-dom": "^19"
|
|
43
43
|
},
|
|
44
|
-
"gitHead": "
|
|
44
|
+
"gitHead": "b50bc79cbc94fb83381e3dcfba0f8cab936f94b0"
|
|
45
45
|
}
|
package/src/node.tsx
CHANGED
|
@@ -1,32 +1,55 @@
|
|
|
1
1
|
/* @jsxRuntime automatic */
|
|
2
2
|
import type { IncomingMessage, ServerResponse } from 'http';
|
|
3
3
|
import type { ReadableStream as NodeReadableStream } from 'stream/web';
|
|
4
|
+
import type { ReactNode } from 'react';
|
|
4
5
|
|
|
5
6
|
import {Readable} from 'stream';
|
|
6
7
|
import {renderToReadableStream, createTemporaryReferenceSet} from 'react-server-dom-parcel/server.edge';
|
|
7
|
-
import {RSCToHTMLOptions, RSCOptions,
|
|
8
|
+
import {RSCToHTMLOptions, RSCOptions, renderHTML as renderHTMLBase, callAction as callActionBase, renderDevError} from './server';
|
|
8
9
|
|
|
9
10
|
export function renderRSC(root: any, options?: RSCOptions): Readable {
|
|
10
11
|
return Readable.fromWeb(renderToReadableStream(root, options) as NodeReadableStream);
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
export async function renderHTML(root: any, options?: RSCToHTMLOptions): Promise<Readable> {
|
|
14
|
-
let htmlStream = await
|
|
15
|
+
let htmlStream = await renderHTMLBase(root, options);
|
|
15
16
|
return Readable.fromWeb(htmlStream as NodeReadableStream);
|
|
16
17
|
}
|
|
17
18
|
|
|
18
|
-
const temporaryReferencesSymbol = Symbol.for('temporaryReferences')
|
|
19
|
+
const temporaryReferencesSymbol = Symbol.for('temporaryReferences');
|
|
19
20
|
|
|
20
|
-
export
|
|
21
|
+
export interface RenderRequestOptions extends RSCToHTMLOptions {
|
|
22
|
+
renderError?: (err: Error) => ReactNode
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function renderRequest(request: IncomingMessage, response: ServerResponse, root: any, options?: RenderRequestOptions): Promise<void> {
|
|
21
26
|
options = {
|
|
22
27
|
...options,
|
|
23
28
|
temporaryReferences: options?.temporaryReferences ?? (request as any)[temporaryReferencesSymbol]
|
|
24
29
|
};
|
|
25
30
|
|
|
26
31
|
if (request.headers.accept?.includes('text/html')) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
32
|
+
try {
|
|
33
|
+
let html = await renderHTML(root, options);
|
|
34
|
+
response.setHeader('Content-Type', 'text/html');
|
|
35
|
+
html.pipe(response);
|
|
36
|
+
} catch (err) {
|
|
37
|
+
response.statusCode = 500;
|
|
38
|
+
let error = err instanceof Error ? err : new Error(String(err));
|
|
39
|
+
let renderedError;
|
|
40
|
+
try {
|
|
41
|
+
renderedError = options?.renderError
|
|
42
|
+
? await renderHTMLBase(options.renderError(error), options)
|
|
43
|
+
: await renderDevError(error, options);
|
|
44
|
+
} catch {
|
|
45
|
+
renderedError = '<h1>Something went wrong!</h1>';
|
|
46
|
+
}
|
|
47
|
+
if (typeof renderedError === 'string') {
|
|
48
|
+
response.end(renderedError);
|
|
49
|
+
} else {
|
|
50
|
+
Readable.fromWeb(renderedError as NodeReadableStream).pipe(response);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
30
53
|
} else {
|
|
31
54
|
response.setHeader('Content-Type', 'text/x-component');
|
|
32
55
|
renderRSC(root, options).pipe(response);
|
package/src/server.tsx
CHANGED
|
@@ -36,7 +36,7 @@ export interface RSCToHTMLOptions {
|
|
|
36
36
|
onError?: (error: unknown, errorInfo?: ErrorInfo) => string | void;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
export async function
|
|
39
|
+
export async function renderHTML(root: any, options?: RSCToHTMLOptions): Promise<ReadableStream> {
|
|
40
40
|
let rscStream = renderToReadableStream(root, options);
|
|
41
41
|
|
|
42
42
|
// Use client react to render the RSC payload to HTML.
|
|
@@ -50,14 +50,15 @@ export async function renderRSCToHTML(root: any, options?: RSCToHTMLOptions): Pr
|
|
|
50
50
|
|
|
51
51
|
let htmlStream = await renderHTMLToReadableStream(<Content />, {
|
|
52
52
|
...options,
|
|
53
|
-
bootstrapScriptContent: (options?.component as any)?.bootstrapScript
|
|
53
|
+
bootstrapScriptContent: (options?.component as any)?.bootstrapScript,
|
|
54
54
|
});
|
|
55
55
|
|
|
56
56
|
return htmlStream.pipeThrough(injectRSCPayload(s2));
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
export interface RenderRequestOptions extends RSCToHTMLOptions {
|
|
60
|
-
headers?: HeadersInit
|
|
60
|
+
headers?: HeadersInit,
|
|
61
|
+
renderError?: (err: Error) => ReactNode
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
const temporaryReferencesSymbol = Symbol.for('temporaryReferences')
|
|
@@ -69,13 +70,32 @@ export async function renderRequest(request: Request, root: any, options?: Rende
|
|
|
69
70
|
};
|
|
70
71
|
|
|
71
72
|
if (request.headers.get('Accept')?.includes('text/html')) {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
73
|
+
try {
|
|
74
|
+
let html = await renderHTML(root, options);
|
|
75
|
+
return new Response(html, {
|
|
76
|
+
headers: {
|
|
77
|
+
...options?.headers,
|
|
78
|
+
'Content-Type': 'text/html'
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
} catch (err) {
|
|
82
|
+
let error = err instanceof Error ? err : new Error(String(err));
|
|
83
|
+
let res;
|
|
84
|
+
try {
|
|
85
|
+
res = options?.renderError
|
|
86
|
+
? await renderHTML(options.renderError(error), options)
|
|
87
|
+
: await renderDevError(error, options);
|
|
88
|
+
} catch {
|
|
89
|
+
res = '<h1>Something went wrong!</h1>';
|
|
77
90
|
}
|
|
78
|
-
|
|
91
|
+
return new Response(res, {
|
|
92
|
+
status: 500,
|
|
93
|
+
headers: {
|
|
94
|
+
...options?.headers,
|
|
95
|
+
'Content-Type': 'text/html'
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
}
|
|
79
99
|
} else {
|
|
80
100
|
let rscStream = renderToReadableStream(root, options);
|
|
81
101
|
return new Response(rscStream, {
|
|
@@ -116,3 +136,37 @@ export async function callAction(request: Request, id: string | null | undefined
|
|
|
116
136
|
return {result};
|
|
117
137
|
}
|
|
118
138
|
}
|
|
139
|
+
|
|
140
|
+
export async function renderDevError(error: Error, options: RSCToHTMLOptions): Promise<ReadableStream | string> {
|
|
141
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
142
|
+
let content = (
|
|
143
|
+
<html>
|
|
144
|
+
<meta charSet="utf-8" />
|
|
145
|
+
<title>Error</title>
|
|
146
|
+
<body>
|
|
147
|
+
<noscript>
|
|
148
|
+
<h1>Error: {error.message}</h1>
|
|
149
|
+
<pre>{error.stack}</pre>
|
|
150
|
+
</noscript>
|
|
151
|
+
</body>
|
|
152
|
+
</html>
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
// Load bootstrap script containing error overlay, and re-throw server error on the client.
|
|
156
|
+
let bootstrapScript = (options?.component as any)?.bootstrapScript;
|
|
157
|
+
bootstrapScript += '.then(() => {';
|
|
158
|
+
bootstrapScript += `let err = new Error(${JSON.stringify(error.message)});`;
|
|
159
|
+
bootstrapScript += `err.stack = ${JSON.stringify(error.stack)};`;
|
|
160
|
+
bootstrapScript += 'throw err;';
|
|
161
|
+
bootstrapScript += '})';
|
|
162
|
+
|
|
163
|
+
return await renderHTML(content, {
|
|
164
|
+
...options,
|
|
165
|
+
component: {
|
|
166
|
+
bootstrapScript
|
|
167
|
+
} as any
|
|
168
|
+
});
|
|
169
|
+
} else {
|
|
170
|
+
return '<h1>Something went wrong!</h1>';
|
|
171
|
+
}
|
|
172
|
+
}
|