@parcel/rsc 2.16.5-canary.3498 → 3.0.0-alpha.1
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/package.json +15 -4
- package/src/client.tsx +34 -11
- package/src/node.tsx +41 -15
- package/src/runtime-client.js +12 -0
- package/src/runtime-helpers.js +137 -0
- package/src/runtime-server.js +27 -0
- package/src/server.tsx +57 -30
- package/LICENSE +0 -21
- package/tsconfig.json +0 -31
- package/types.d.ts +0 -81
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parcel/rsc",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0-alpha.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -14,6 +14,10 @@
|
|
|
14
14
|
"url": "https://github.com/parcel-bundler/parcel.git"
|
|
15
15
|
},
|
|
16
16
|
"sideEffects": false,
|
|
17
|
+
"files": [
|
|
18
|
+
"lib",
|
|
19
|
+
"src"
|
|
20
|
+
],
|
|
17
21
|
"exports": {
|
|
18
22
|
".": {
|
|
19
23
|
"types": "./src/ssg.d.ts"
|
|
@@ -29,6 +33,14 @@
|
|
|
29
33
|
"./node": {
|
|
30
34
|
"types": "./lib/node.d.ts",
|
|
31
35
|
"default": "./src/node.tsx"
|
|
36
|
+
},
|
|
37
|
+
"./runtime/server": {
|
|
38
|
+
"source": "./src/runtime-server.js",
|
|
39
|
+
"default": "./src/runtime-server.js"
|
|
40
|
+
},
|
|
41
|
+
"./runtime/client": {
|
|
42
|
+
"source": "./src/runtime-client.js",
|
|
43
|
+
"default": "./src/runtime-client.js"
|
|
32
44
|
}
|
|
33
45
|
},
|
|
34
46
|
"dependencies": {
|
|
@@ -43,6 +55,5 @@
|
|
|
43
55
|
"peerDependencies": {
|
|
44
56
|
"react": "^19.1.0",
|
|
45
57
|
"react-dom": "^19.1.0"
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
}
|
|
58
|
+
}
|
|
59
|
+
}
|
package/src/client.tsx
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
/* @jsxRuntime automatic */
|
|
2
2
|
import {ReactNode, startTransition, useInsertionEffect} from 'react';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
createFromReadableStream,
|
|
5
|
+
createFromFetch,
|
|
6
|
+
encodeReply,
|
|
7
|
+
setServerCallback as setReactServerCallback,
|
|
8
|
+
createTemporaryReferenceSet,
|
|
9
|
+
} from 'react-server-dom-parcel/client';
|
|
4
10
|
import {rscStream} from 'rsc-html-stream/client';
|
|
5
11
|
import {hydrateRoot, HydrationOptions, Root} from 'react-dom/client';
|
|
6
12
|
|
|
@@ -11,7 +17,7 @@ export function setServerCallback(cb: CallServerCallback): void {
|
|
|
11
17
|
|
|
12
18
|
// Stream in initial RSC payload embedded in the HTML.
|
|
13
19
|
let initialRSCPayload: Promise<ReactNode>;
|
|
14
|
-
function RSCRoot({value, cb}: {value?: ReactNode
|
|
20
|
+
function RSCRoot({value, cb}: {value?: ReactNode; cb?: () => void}) {
|
|
15
21
|
initialRSCPayload ??= createFromReadableStream<ReactNode>(rscStream);
|
|
16
22
|
useInsertionEffect(() => {
|
|
17
23
|
cb?.();
|
|
@@ -20,11 +26,13 @@ function RSCRoot({value, cb}: {value?: ReactNode, cb?: () => void}) {
|
|
|
20
26
|
}
|
|
21
27
|
|
|
22
28
|
export interface HydrateOptions extends HydrationOptions {
|
|
23
|
-
callServer?: CallServerCallback
|
|
24
|
-
onHmrReload?: () => void
|
|
29
|
+
callServer?: CallServerCallback;
|
|
30
|
+
onHmrReload?: () => void;
|
|
25
31
|
}
|
|
26
32
|
|
|
27
|
-
export function hydrate(
|
|
33
|
+
export function hydrate(
|
|
34
|
+
options?: HydrateOptions,
|
|
35
|
+
): (value: ReactNode, cb?: () => void) => void {
|
|
28
36
|
if (options?.callServer) {
|
|
29
37
|
setServerCallback(options.callServer);
|
|
30
38
|
}
|
|
@@ -43,16 +51,27 @@ export function hydrate(options?: HydrateOptions): (value: ReactNode, cb?: () =>
|
|
|
43
51
|
|
|
44
52
|
return (value: ReactNode, cb?: () => void) => {
|
|
45
53
|
startTransition(() => {
|
|
46
|
-
root?.render(
|
|
54
|
+
root?.render(
|
|
55
|
+
<RSCRoot
|
|
56
|
+
value={value}
|
|
57
|
+
cb={() => {
|
|
58
|
+
cb?.();
|
|
59
|
+
cb = undefined;
|
|
60
|
+
}}
|
|
61
|
+
/>,
|
|
62
|
+
);
|
|
47
63
|
});
|
|
48
64
|
};
|
|
49
65
|
}
|
|
50
66
|
|
|
51
67
|
export interface RSCRequestInit extends Omit<RequestInit, 'body'> {
|
|
52
|
-
body?: any
|
|
68
|
+
body?: any;
|
|
53
69
|
}
|
|
54
70
|
|
|
55
|
-
export async function fetchRSC<T>(
|
|
71
|
+
export async function fetchRSC<T>(
|
|
72
|
+
url: string | URL | Request,
|
|
73
|
+
options?: RSCRequestInit,
|
|
74
|
+
): Promise<T> {
|
|
56
75
|
const temporaryReferences = createTemporaryReferenceSet();
|
|
57
76
|
const response = fetch(url, {
|
|
58
77
|
...options,
|
|
@@ -60,9 +79,13 @@ export async function fetchRSC<T>(url: string | URL | Request, options?: RSCRequ
|
|
|
60
79
|
Accept: 'text/x-component',
|
|
61
80
|
...options?.headers,
|
|
62
81
|
},
|
|
63
|
-
body:
|
|
64
|
-
|
|
65
|
-
|
|
82
|
+
body:
|
|
83
|
+
options && 'body' in options
|
|
84
|
+
? await encodeReply(options.body, {
|
|
85
|
+
temporaryReferences,
|
|
86
|
+
signal: options?.signal,
|
|
87
|
+
})
|
|
88
|
+
: undefined,
|
|
66
89
|
});
|
|
67
90
|
|
|
68
91
|
return createFromFetch<T>(response, {temporaryReferences});
|
package/src/node.tsx
CHANGED
|
@@ -1,17 +1,31 @@
|
|
|
1
1
|
/* @jsxRuntime automatic */
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
4
|
-
import type {
|
|
2
|
+
import type {IncomingMessage, ServerResponse} from 'http';
|
|
3
|
+
import type {ReadableStream as NodeReadableStream} from 'stream/web';
|
|
4
|
+
import type {ReactNode} from 'react';
|
|
5
5
|
|
|
6
6
|
import {Readable} from 'stream';
|
|
7
|
-
import {
|
|
8
|
-
|
|
7
|
+
import {
|
|
8
|
+
renderToReadableStream,
|
|
9
|
+
createTemporaryReferenceSet,
|
|
10
|
+
} from 'react-server-dom-parcel/server.edge';
|
|
11
|
+
import {
|
|
12
|
+
RSCToHTMLOptions,
|
|
13
|
+
RSCOptions,
|
|
14
|
+
renderHTML as renderHTMLBase,
|
|
15
|
+
callAction as callActionBase,
|
|
16
|
+
renderDevError,
|
|
17
|
+
} from './server';
|
|
9
18
|
|
|
10
19
|
export function renderRSC(root: any, options?: RSCOptions): Readable {
|
|
11
|
-
return Readable.fromWeb(
|
|
20
|
+
return Readable.fromWeb(
|
|
21
|
+
renderToReadableStream(root, options) as NodeReadableStream,
|
|
22
|
+
);
|
|
12
23
|
}
|
|
13
24
|
|
|
14
|
-
export async function renderHTML(
|
|
25
|
+
export async function renderHTML(
|
|
26
|
+
root: any,
|
|
27
|
+
options?: RSCToHTMLOptions,
|
|
28
|
+
): Promise<Readable> {
|
|
15
29
|
let htmlStream = await renderHTMLBase(root, options);
|
|
16
30
|
return Readable.fromWeb(htmlStream as NodeReadableStream);
|
|
17
31
|
}
|
|
@@ -19,15 +33,22 @@ export async function renderHTML(root: any, options?: RSCToHTMLOptions): Promise
|
|
|
19
33
|
const temporaryReferencesSymbol = Symbol.for('temporaryReferences');
|
|
20
34
|
|
|
21
35
|
export interface RenderRequestOptions extends RSCToHTMLOptions {
|
|
22
|
-
renderError?: (err: Error) => ReactNode
|
|
36
|
+
renderError?: (err: Error) => ReactNode;
|
|
23
37
|
}
|
|
24
38
|
|
|
25
|
-
export async function renderRequest(
|
|
39
|
+
export async function renderRequest(
|
|
40
|
+
request: IncomingMessage,
|
|
41
|
+
response: ServerResponse,
|
|
42
|
+
root: any,
|
|
43
|
+
options?: RenderRequestOptions,
|
|
44
|
+
): Promise<void> {
|
|
26
45
|
options = {
|
|
27
46
|
...options,
|
|
28
|
-
temporaryReferences:
|
|
47
|
+
temporaryReferences:
|
|
48
|
+
options?.temporaryReferences ??
|
|
49
|
+
(request as any)[temporaryReferencesSymbol],
|
|
29
50
|
};
|
|
30
|
-
|
|
51
|
+
|
|
31
52
|
if (request.headers.accept?.includes('text/html')) {
|
|
32
53
|
try {
|
|
33
54
|
let html = await renderHTML(root, options);
|
|
@@ -38,7 +59,7 @@ export async function renderRequest(request: IncomingMessage, response: ServerRe
|
|
|
38
59
|
let error = err instanceof Error ? err : new Error(String(err));
|
|
39
60
|
let renderedError;
|
|
40
61
|
try {
|
|
41
|
-
renderedError = options?.renderError
|
|
62
|
+
renderedError = options?.renderError
|
|
42
63
|
? await renderHTMLBase(options.renderError(error), options)
|
|
43
64
|
: await renderDevError(error, options);
|
|
44
65
|
} catch {
|
|
@@ -56,7 +77,10 @@ export async function renderRequest(request: IncomingMessage, response: ServerRe
|
|
|
56
77
|
}
|
|
57
78
|
}
|
|
58
79
|
|
|
59
|
-
export async function callAction(
|
|
80
|
+
export async function callAction(
|
|
81
|
+
request: IncomingMessage,
|
|
82
|
+
id: string | null | undefined,
|
|
83
|
+
): Promise<{result: any}> {
|
|
60
84
|
(request as any)[temporaryReferencesSymbol] ??= createTemporaryReferenceSet();
|
|
61
85
|
|
|
62
86
|
let req = new Request('http://localhost' + request.url, {
|
|
@@ -64,9 +88,11 @@ export async function callAction(request: IncomingMessage, id: string | null | u
|
|
|
64
88
|
headers: request.headers as any,
|
|
65
89
|
body: Readable.toWeb(request) as ReadableStream,
|
|
66
90
|
// @ts-ignore
|
|
67
|
-
duplex: 'half'
|
|
91
|
+
duplex: 'half',
|
|
68
92
|
});
|
|
69
93
|
|
|
70
|
-
(req as any)[temporaryReferencesSymbol] = (request as any)[
|
|
94
|
+
(req as any)[temporaryReferencesSymbol] = (request as any)[
|
|
95
|
+
temporaryReferencesSymbol
|
|
96
|
+
];
|
|
71
97
|
return callActionBase(req, id);
|
|
72
98
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
'use parcel-rsc-runtime';
|
|
2
|
+
|
|
3
|
+
export {createServerReference} from 'react-server-dom-parcel/client';
|
|
4
|
+
export {preinit} from 'react-dom';
|
|
5
|
+
export {
|
|
6
|
+
createResourcesProxy,
|
|
7
|
+
modulePreloadResource,
|
|
8
|
+
scriptPreloadResource,
|
|
9
|
+
stylesheetResource,
|
|
10
|
+
waitForCSS,
|
|
11
|
+
wrapClientReferenceWithResources,
|
|
12
|
+
} from './runtime-helpers';
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
'use parcel-rsc-runtime';
|
|
2
|
+
|
|
3
|
+
import {createElement, Fragment} from 'react';
|
|
4
|
+
|
|
5
|
+
export function stylesheetResource(href) {
|
|
6
|
+
return createElement('link', {
|
|
7
|
+
key: href,
|
|
8
|
+
rel: 'stylesheet',
|
|
9
|
+
href,
|
|
10
|
+
precedence: 'default',
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function modulePreloadResource(href) {
|
|
15
|
+
return createElement('link', {key: href, rel: 'modulepreload', href});
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function scriptPreloadResource(href) {
|
|
19
|
+
return createElement('link', {key: href, rel: 'preload', as: 'script', href});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function wrapClientReferenceWithResources(Reference, resources) {
|
|
23
|
+
return props =>
|
|
24
|
+
createElement(Fragment, null, resources, createElement(Reference, props));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function createResourcesProxy(
|
|
28
|
+
module,
|
|
29
|
+
esModule,
|
|
30
|
+
resources,
|
|
31
|
+
bootstrapScript,
|
|
32
|
+
) {
|
|
33
|
+
if (typeof module === 'function') {
|
|
34
|
+
return createResourcesValueProxy(module, resources, bootstrapScript);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return new Proxy(module, {
|
|
38
|
+
get(target, prop, receiver) {
|
|
39
|
+
if (prop === '__esModule' && esModule) {
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
let value = Reflect.get(target, prop, receiver);
|
|
43
|
+
return createResourcesValueProxy(value, resources, bootstrapScript);
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
let cache = new WeakMap();
|
|
49
|
+
function createResourcesValueProxy(value, resources, bootstrapScript) {
|
|
50
|
+
if (typeof value === 'function') {
|
|
51
|
+
let cached = cache.get(value);
|
|
52
|
+
if (cached) {
|
|
53
|
+
return cached;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Detect reads of `Component.prototype.isReactComponent` or `Component.$$typeof`
|
|
57
|
+
// prior to the function being called as an indication that this is a React component.
|
|
58
|
+
let isReactComponent = false;
|
|
59
|
+
let prototypeProxy;
|
|
60
|
+
if (typeof value.prototype === 'object') {
|
|
61
|
+
prototypeProxy = new Proxy(value.prototype, {
|
|
62
|
+
get(target, prop, receiver) {
|
|
63
|
+
if (prop === 'isReactComponent') {
|
|
64
|
+
isReactComponent = true;
|
|
65
|
+
}
|
|
66
|
+
return Reflect.get(target, prop, receiver);
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
let proxy = new Proxy(value, {
|
|
72
|
+
get(target, prop, receiver) {
|
|
73
|
+
if (
|
|
74
|
+
prototypeProxy &&
|
|
75
|
+
prop === 'prototype' &&
|
|
76
|
+
Object.getOwnPropertyDescriptor(target, 'prototype').configurable
|
|
77
|
+
) {
|
|
78
|
+
return prototypeProxy;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (prop === '$$typeof') {
|
|
82
|
+
isReactComponent = true;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (bootstrapScript && prop === 'bootstrapScript') {
|
|
86
|
+
return bootstrapScript;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return Reflect.get(target, prop, receiver);
|
|
90
|
+
},
|
|
91
|
+
apply(target, thisArg, args) {
|
|
92
|
+
let result = Reflect.apply(target, thisArg, args);
|
|
93
|
+
return isReactComponent
|
|
94
|
+
? createElement(Fragment, null, resources, result)
|
|
95
|
+
: result;
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
cache.set(value, proxy);
|
|
100
|
+
return proxy;
|
|
101
|
+
} else if (value && typeof value === 'object') {
|
|
102
|
+
let cached = cache.get(value);
|
|
103
|
+
if (cached) {
|
|
104
|
+
return cached;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
let proxy = new Proxy(value, {
|
|
108
|
+
get(target, prop, receiver) {
|
|
109
|
+
let value = Reflect.get(target, prop, receiver);
|
|
110
|
+
return createResourcesValueProxy(value, resources, bootstrapScript);
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
cache.set(value, proxy);
|
|
115
|
+
return proxy;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return value;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export function waitForCSS(url) {
|
|
122
|
+
return new Promise((resolve, reject) => {
|
|
123
|
+
if (typeof document === 'undefined') {
|
|
124
|
+
return resolve();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
let link = document.querySelector(
|
|
128
|
+
`link[rel="stylesheet"][href="${CSS.escape(url)}"]`,
|
|
129
|
+
);
|
|
130
|
+
if (!link || link.sheet) {
|
|
131
|
+
return resolve();
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
link.addEventListener('load', resolve);
|
|
135
|
+
link.addEventListener('error', reject);
|
|
136
|
+
});
|
|
137
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
'use parcel-rsc-runtime';
|
|
2
|
+
|
|
3
|
+
export {
|
|
4
|
+
createClientReference,
|
|
5
|
+
registerServerReference,
|
|
6
|
+
registerServerActions,
|
|
7
|
+
} from 'react-server-dom-parcel/server.edge';
|
|
8
|
+
export {preinit} from 'react-dom';
|
|
9
|
+
export {
|
|
10
|
+
createResourcesProxy,
|
|
11
|
+
modulePreloadResource,
|
|
12
|
+
scriptPreloadResource,
|
|
13
|
+
stylesheetResource,
|
|
14
|
+
waitForCSS,
|
|
15
|
+
wrapClientReferenceWithResources,
|
|
16
|
+
} from './runtime-helpers';
|
|
17
|
+
|
|
18
|
+
export function ensureAsyncLocalStorage() {
|
|
19
|
+
if (typeof AsyncLocalStorage === 'undefined') {
|
|
20
|
+
try {
|
|
21
|
+
globalThis.AsyncLocalStorage =
|
|
22
|
+
require('node:async_hooks').AsyncLocalStorage;
|
|
23
|
+
} catch {
|
|
24
|
+
// The edge runtime may not provide node:async_hooks.
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
package/src/server.tsx
CHANGED
|
@@ -1,24 +1,34 @@
|
|
|
1
1
|
/* @jsxRuntime automatic */
|
|
2
|
-
import type {
|
|
2
|
+
import type {ErrorInfo} from 'react-dom/client';
|
|
3
3
|
|
|
4
4
|
// Server dependencies.
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
renderToReadableStream,
|
|
7
|
+
loadServerAction,
|
|
8
|
+
decodeReply,
|
|
9
|
+
decodeAction,
|
|
10
|
+
createTemporaryReferenceSet,
|
|
11
|
+
} from 'react-server-dom-parcel/server.edge';
|
|
6
12
|
import {injectRSCPayload} from 'rsc-html-stream/server';
|
|
7
13
|
|
|
8
14
|
// Client dependencies, used for SSR.
|
|
9
15
|
// These must run in the same environment as client components (e.g. same instance of React).
|
|
10
|
-
import {createFromReadableStream} from 'react-server-dom-parcel/client.edge' with {
|
|
11
|
-
|
|
16
|
+
import {createFromReadableStream} from 'react-server-dom-parcel/client.edge' with {
|
|
17
|
+
env: 'react-client',
|
|
18
|
+
};
|
|
19
|
+
import {renderToReadableStream as renderHTMLToReadableStream} from 'react-dom/server.edge' with {
|
|
20
|
+
env: 'react-client',
|
|
21
|
+
};
|
|
12
22
|
import {ComponentType, ReactNode} from 'react' with {env: 'react-client'};
|
|
13
23
|
|
|
14
24
|
export interface RSCOptions {
|
|
15
25
|
// environmentName?: string | (() => string),
|
|
16
26
|
// filterStackFrame?: (url: string, functionName: string) => boolean,
|
|
17
|
-
identifierPrefix?: string
|
|
18
|
-
signal?: AbortSignal
|
|
19
|
-
temporaryReferences?: any
|
|
20
|
-
onError?: (error: unknown) => void
|
|
21
|
-
onPostpone?: (reason: string) => void
|
|
27
|
+
identifierPrefix?: string;
|
|
28
|
+
signal?: AbortSignal;
|
|
29
|
+
temporaryReferences?: any;
|
|
30
|
+
onError?: (error: unknown) => void;
|
|
31
|
+
onPostpone?: (reason: string) => void;
|
|
22
32
|
}
|
|
23
33
|
|
|
24
34
|
export function renderRSC(root: any, options?: RSCOptions): ReadableStream {
|
|
@@ -26,17 +36,20 @@ export function renderRSC(root: any, options?: RSCOptions): ReadableStream {
|
|
|
26
36
|
}
|
|
27
37
|
|
|
28
38
|
export interface RSCToHTMLOptions {
|
|
29
|
-
component?: ComponentType
|
|
39
|
+
component?: ComponentType;
|
|
30
40
|
identifierPrefix?: string;
|
|
31
41
|
namespaceURI?: string;
|
|
32
42
|
nonce?: string;
|
|
33
43
|
progressiveChunkSize?: number;
|
|
34
44
|
signal?: AbortSignal;
|
|
35
|
-
temporaryReferences?: any
|
|
45
|
+
temporaryReferences?: any;
|
|
36
46
|
onError?: (error: unknown, errorInfo?: ErrorInfo) => string | void;
|
|
37
47
|
}
|
|
38
48
|
|
|
39
|
-
export async function renderHTML(
|
|
49
|
+
export async function renderHTML(
|
|
50
|
+
root: any,
|
|
51
|
+
options?: RSCToHTMLOptions,
|
|
52
|
+
): Promise<ReadableStream> {
|
|
40
53
|
let rscStream = renderToReadableStream(root, options);
|
|
41
54
|
|
|
42
55
|
// Use client react to render the RSC payload to HTML.
|
|
@@ -57,16 +70,22 @@ export async function renderHTML(root: any, options?: RSCToHTMLOptions): Promise
|
|
|
57
70
|
}
|
|
58
71
|
|
|
59
72
|
export interface RenderRequestOptions extends RSCToHTMLOptions {
|
|
60
|
-
headers?: HeadersInit
|
|
61
|
-
renderError?: (err: Error) => ReactNode
|
|
73
|
+
headers?: HeadersInit;
|
|
74
|
+
renderError?: (err: Error) => ReactNode;
|
|
62
75
|
}
|
|
63
76
|
|
|
64
|
-
const temporaryReferencesSymbol = Symbol.for('temporaryReferences')
|
|
77
|
+
const temporaryReferencesSymbol = Symbol.for('temporaryReferences');
|
|
65
78
|
|
|
66
|
-
export async function renderRequest(
|
|
79
|
+
export async function renderRequest(
|
|
80
|
+
request: Request,
|
|
81
|
+
root: any,
|
|
82
|
+
options?: RenderRequestOptions,
|
|
83
|
+
): Promise<Response> {
|
|
67
84
|
options = {
|
|
68
85
|
...options,
|
|
69
|
-
temporaryReferences:
|
|
86
|
+
temporaryReferences:
|
|
87
|
+
options?.temporaryReferences ??
|
|
88
|
+
(request as any)[temporaryReferencesSymbol],
|
|
70
89
|
};
|
|
71
90
|
|
|
72
91
|
if (request.headers.get('Accept')?.includes('text/html')) {
|
|
@@ -75,14 +94,14 @@ export async function renderRequest(request: Request, root: any, options?: Rende
|
|
|
75
94
|
return new Response(html, {
|
|
76
95
|
headers: {
|
|
77
96
|
...options?.headers,
|
|
78
|
-
'Content-Type': 'text/html'
|
|
79
|
-
}
|
|
97
|
+
'Content-Type': 'text/html',
|
|
98
|
+
},
|
|
80
99
|
});
|
|
81
100
|
} catch (err) {
|
|
82
101
|
let error = err instanceof Error ? err : new Error(String(err));
|
|
83
102
|
let res;
|
|
84
103
|
try {
|
|
85
|
-
res = options?.renderError
|
|
104
|
+
res = options?.renderError
|
|
86
105
|
? await renderHTML(options.renderError(error), options)
|
|
87
106
|
: await renderDevError(error, options);
|
|
88
107
|
} catch {
|
|
@@ -92,8 +111,8 @@ export async function renderRequest(request: Request, root: any, options?: Rende
|
|
|
92
111
|
status: 500,
|
|
93
112
|
headers: {
|
|
94
113
|
...options?.headers,
|
|
95
|
-
'Content-Type': 'text/html'
|
|
96
|
-
}
|
|
114
|
+
'Content-Type': 'text/html',
|
|
115
|
+
},
|
|
97
116
|
});
|
|
98
117
|
}
|
|
99
118
|
} else {
|
|
@@ -101,22 +120,27 @@ export async function renderRequest(request: Request, root: any, options?: Rende
|
|
|
101
120
|
return new Response(rscStream, {
|
|
102
121
|
headers: {
|
|
103
122
|
...options?.headers,
|
|
104
|
-
'Content-Type': 'text/x-component'
|
|
105
|
-
}
|
|
123
|
+
'Content-Type': 'text/x-component',
|
|
124
|
+
},
|
|
106
125
|
});
|
|
107
126
|
}
|
|
108
127
|
}
|
|
109
128
|
|
|
110
|
-
export async function callAction(
|
|
129
|
+
export async function callAction(
|
|
130
|
+
request: Request,
|
|
131
|
+
id: string | null | undefined,
|
|
132
|
+
): Promise<{result: any}> {
|
|
111
133
|
(request as any)[temporaryReferencesSymbol] ??= createTemporaryReferenceSet();
|
|
112
134
|
|
|
113
135
|
if (id) {
|
|
114
136
|
let action = await loadServerAction(id);
|
|
115
|
-
let body = request.headers
|
|
137
|
+
let body = request.headers
|
|
138
|
+
.get('content-type')
|
|
139
|
+
?.includes('multipart/form-data')
|
|
116
140
|
? await request.formData()
|
|
117
141
|
: await request.text();
|
|
118
142
|
let args = await decodeReply<any[]>(body, {
|
|
119
|
-
temporaryReferences: (request as any)[temporaryReferencesSymbol]
|
|
143
|
+
temporaryReferences: (request as any)[temporaryReferencesSymbol],
|
|
120
144
|
});
|
|
121
145
|
|
|
122
146
|
let result = action.apply(null, args);
|
|
@@ -137,7 +161,10 @@ export async function callAction(request: Request, id: string | null | undefined
|
|
|
137
161
|
}
|
|
138
162
|
}
|
|
139
163
|
|
|
140
|
-
export async function renderDevError(
|
|
164
|
+
export async function renderDevError(
|
|
165
|
+
error: Error,
|
|
166
|
+
options: RSCToHTMLOptions,
|
|
167
|
+
): Promise<ReadableStream | string> {
|
|
141
168
|
if (process.env.NODE_ENV !== 'production') {
|
|
142
169
|
let content = (
|
|
143
170
|
<html>
|
|
@@ -163,8 +190,8 @@ export async function renderDevError(error: Error, options: RSCToHTMLOptions): P
|
|
|
163
190
|
return await renderHTML(content, {
|
|
164
191
|
...options,
|
|
165
192
|
component: {
|
|
166
|
-
bootstrapScript
|
|
167
|
-
} as any
|
|
193
|
+
bootstrapScript,
|
|
194
|
+
} as any,
|
|
168
195
|
});
|
|
169
196
|
} else {
|
|
170
197
|
return '<h1>Something went wrong!</h1>';
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2017-present Devon Govett
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
package/tsconfig.json
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
/* Visit https://aka.ms/tsconfig to read more about this file */
|
|
4
|
-
"target": "ES2020",
|
|
5
|
-
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
|
6
|
-
"jsx": "react-jsx",
|
|
7
|
-
"useDefineForClassFields": true,
|
|
8
|
-
|
|
9
|
-
/* Modules */
|
|
10
|
-
"module": "ESNext",
|
|
11
|
-
"moduleResolution": "bundler",
|
|
12
|
-
|
|
13
|
-
/* Emit */
|
|
14
|
-
"noEmit": true,
|
|
15
|
-
"declaration": true,
|
|
16
|
-
|
|
17
|
-
/* Interop Constraints */
|
|
18
|
-
"isolatedModules": true,
|
|
19
|
-
"isolatedDeclarations": true,
|
|
20
|
-
"allowSyntheticDefaultImports": true,
|
|
21
|
-
"allowImportingTsExtensions": true,
|
|
22
|
-
"esModuleInterop": true,
|
|
23
|
-
"forceConsistentCasingInFileNames": true,
|
|
24
|
-
|
|
25
|
-
/* Type Checking */
|
|
26
|
-
"strict": true,
|
|
27
|
-
|
|
28
|
-
/* Completeness */
|
|
29
|
-
"skipLibCheck": true
|
|
30
|
-
}
|
|
31
|
-
}
|
package/types.d.ts
DELETED
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
declare module 'react-server-dom-parcel/client' {
|
|
2
|
-
type TemporaryReferenceSet = {__ref: true};
|
|
3
|
-
type ReactCustomFormAction = {
|
|
4
|
-
name?: string;
|
|
5
|
-
action?: string;
|
|
6
|
-
encType?: string;
|
|
7
|
-
method?: string;
|
|
8
|
-
target?: string;
|
|
9
|
-
data?: null | FormData;
|
|
10
|
-
};
|
|
11
|
-
type EncodeFormActionCallback = <A>(
|
|
12
|
-
id: any,
|
|
13
|
-
args: Promise<A>,
|
|
14
|
-
) => ReactCustomFormAction;
|
|
15
|
-
type Options = {
|
|
16
|
-
nonce?: string;
|
|
17
|
-
encodeFormAction?: EncodeFormActionCallback;
|
|
18
|
-
temporaryReferences?: TemporaryReferenceSet;
|
|
19
|
-
replayConsoleLogs?: boolean;
|
|
20
|
-
environmentName?: string;
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
export function createFromFetch<T>(
|
|
24
|
-
res: Promise<Response>,
|
|
25
|
-
options?: Options,
|
|
26
|
-
): Promise<T>;
|
|
27
|
-
export function createFromReadableStream<T>(
|
|
28
|
-
stream: ReadableStream,
|
|
29
|
-
options?: Options,
|
|
30
|
-
): Promise<T>;
|
|
31
|
-
export function encodeReply(
|
|
32
|
-
value: any,
|
|
33
|
-
options?: {
|
|
34
|
-
temporaryReferences?: TemporaryReferenceSet;
|
|
35
|
-
signal?: AbortSignal | null | undefined;
|
|
36
|
-
},
|
|
37
|
-
): Promise<string | URLSearchParams | FormData>;
|
|
38
|
-
export function createTemporaryReferenceSet(): TemporaryReferenceSet;
|
|
39
|
-
|
|
40
|
-
type CallServerCallback = <T>(id: string, args: any[]) => Promise<T>;
|
|
41
|
-
export function setServerCallback(cb: CallServerCallback): void;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
declare module 'react-server-dom-parcel/client.edge' {
|
|
45
|
-
export function createFromReadableStream<T>(
|
|
46
|
-
stream: ReadableStream,
|
|
47
|
-
): Promise<T>;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
declare module 'react-server-dom-parcel/server.edge' {
|
|
51
|
-
type TemporaryReferenceSet = {__ref: true};
|
|
52
|
-
type Options = {
|
|
53
|
-
environmentName?: string | (() => string);
|
|
54
|
-
filterStackFrame?: (url: string, functionName: string) => boolean;
|
|
55
|
-
identifierPrefix?: string;
|
|
56
|
-
signal?: AbortSignal;
|
|
57
|
-
temporaryReferences?: TemporaryReferenceSet;
|
|
58
|
-
onError?: (error: unknown) => void;
|
|
59
|
-
onPostpone?: (reason: string) => void;
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
export function renderToReadableStream(
|
|
63
|
-
value: any,
|
|
64
|
-
options?: Options,
|
|
65
|
-
): ReadableStream;
|
|
66
|
-
export function loadServerAction(
|
|
67
|
-
id: string,
|
|
68
|
-
): Promise<(...args: any[]) => Promise<any>>;
|
|
69
|
-
export function decodeReply<T>(
|
|
70
|
-
body: string | FormData,
|
|
71
|
-
options?: {temporaryReferences?: TemporaryReferenceSet},
|
|
72
|
-
): Promise<T>;
|
|
73
|
-
export function decodeAction(
|
|
74
|
-
body: FormData,
|
|
75
|
-
): Promise<(...args: any[]) => Promise<any>>;
|
|
76
|
-
export function createTemporaryReferenceSet(): TemporaryReferenceSet;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
declare module 'react-dom/server.edge' {
|
|
80
|
-
export * from 'react-dom/server';
|
|
81
|
-
}
|