react-server-frame 0.0.1 → 0.0.2
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/dist/browser.d.mts +21 -0
- package/dist/browser.mjs +88 -0
- package/dist/client.d.mts +4 -1
- package/dist/client.mjs +13 -1
- package/dist/generic-payload-Bio3B-X_.d.mts +16 -0
- package/dist/index.d.mts +32 -3
- package/dist/index.mjs +62 -1
- package/dist/vite/entry.client.tsx +8 -111
- package/dist/vite/entry.ssr.tsx +5 -2
- package/dist/vite/fetch-frame.mjs +2 -10
- package/dist/vite/frames.d.mts +5 -2
- package/dist/vite/frames.mjs +19 -34
- package/dist/vite/plugin.d.mts +2 -2
- package/dist/vite/plugin.mjs +2 -2
- package/package.json +2 -1
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { t as Payload } from "./generic-payload-Bio3B-X_.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/browser.d.ts
|
|
4
|
+
declare function createServerCallback({
|
|
5
|
+
createFromFetch,
|
|
6
|
+
createTemporaryReferenceSet,
|
|
7
|
+
encodeReply
|
|
8
|
+
}: {
|
|
9
|
+
createFromFetch: (response: Promise<Response>, options?: object) => Promise<Payload>;
|
|
10
|
+
createTemporaryReferenceSet: () => unknown;
|
|
11
|
+
encodeReply: (v: unknown[], options?: object) => Promise<string | FormData>;
|
|
12
|
+
}): (id: string, args: unknown[]) => Promise<unknown>;
|
|
13
|
+
declare function hydrate({
|
|
14
|
+
createFromFetch,
|
|
15
|
+
createFromReadableStream
|
|
16
|
+
}: {
|
|
17
|
+
createFromFetch: (response: Promise<Response>, options?: object) => Promise<Payload>;
|
|
18
|
+
createFromReadableStream: (stream: ReadableStream<Uint8Array>, options?: object) => Promise<Payload>;
|
|
19
|
+
}): void;
|
|
20
|
+
//#endregion
|
|
21
|
+
export { createServerCallback, hydrate };
|
package/dist/browser.mjs
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { StrictMode, startTransition, use, useState } from "react";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { hydrateRoot } from "react-dom/client";
|
|
4
|
+
import { rscStream } from "rsc-html-stream/client";
|
|
5
|
+
//#region src/browser.tsx
|
|
6
|
+
let setPayload;
|
|
7
|
+
function createServerCallback({ createFromFetch, createTemporaryReferenceSet, encodeReply }) {
|
|
8
|
+
return async (id, args) => {
|
|
9
|
+
const url = new URL(window.location.href);
|
|
10
|
+
url.pathname += ".rsc";
|
|
11
|
+
const temporaryReferences = createTemporaryReferenceSet();
|
|
12
|
+
const payload = await createFromFetch(fetch(url, {
|
|
13
|
+
method: "POST",
|
|
14
|
+
body: await encodeReply(args, { temporaryReferences }),
|
|
15
|
+
headers: { "x-rsc-action": id }
|
|
16
|
+
}), { temporaryReferences });
|
|
17
|
+
requestAnimationFrame(() => {
|
|
18
|
+
if (payload.type === "render") startTransition(() => {
|
|
19
|
+
setPayload(Promise.resolve(payload));
|
|
20
|
+
});
|
|
21
|
+
if (payload.type === "redirect") if (window.navigation) requestAnimationFrame(() => {
|
|
22
|
+
window.navigation.navigate(payload.redirect, { history: "replace" });
|
|
23
|
+
});
|
|
24
|
+
else window.location.href = payload.redirect;
|
|
25
|
+
});
|
|
26
|
+
return payload.returnValue;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
let seenPayloads = /* @__PURE__ */ new WeakMap();
|
|
30
|
+
function Content({ initialPayload }) {
|
|
31
|
+
const [promise, _setPayload] = useState(initialPayload);
|
|
32
|
+
setPayload = _setPayload;
|
|
33
|
+
const payload = use(promise);
|
|
34
|
+
if (payload.type === "redirect") if (window.navigation) {
|
|
35
|
+
if (!seenPayloads.has(payload)) {
|
|
36
|
+
const promise = Promise.resolve(window.navigation.navigate(payload.redirect, { history: "replace" }).finished).then(() => {});
|
|
37
|
+
seenPayloads.set(payload, Promise.resolve(promise));
|
|
38
|
+
}
|
|
39
|
+
use(seenPayloads.get(payload));
|
|
40
|
+
return null;
|
|
41
|
+
} else {
|
|
42
|
+
window.location.href = payload.redirect;
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
return payload.root;
|
|
46
|
+
}
|
|
47
|
+
function hydrate({ createFromFetch, createFromReadableStream }) {
|
|
48
|
+
createFromReadableStream(rscStream).then((payload) => startTransition(() => {
|
|
49
|
+
hydrateRoot(document, /* @__PURE__ */ jsx(StrictMode, { children: /* @__PURE__ */ jsx(Content, { initialPayload: Promise.resolve(payload) }) }), { formState: payload.formState });
|
|
50
|
+
}), (reason) => console.error("Failed to hydrate root", reason));
|
|
51
|
+
let navigationController = new AbortController();
|
|
52
|
+
async function navigate(to) {
|
|
53
|
+
const url = new URL(to, window.location.href);
|
|
54
|
+
url.pathname += ".rsc";
|
|
55
|
+
const thisController = new AbortController();
|
|
56
|
+
const responses = fetch(url, { signal: thisController.signal }).then((response) => [response, response.clone()]);
|
|
57
|
+
startTransition(() => setPayload(createFromFetch(responses.then(([r]) => r))));
|
|
58
|
+
navigationController.abort();
|
|
59
|
+
navigationController = thisController;
|
|
60
|
+
const [, response] = await responses;
|
|
61
|
+
if (!response.body) return;
|
|
62
|
+
const reader = response.body.getReader();
|
|
63
|
+
try {
|
|
64
|
+
let chunk = await reader.read();
|
|
65
|
+
while (!chunk.done) chunk = await reader.read();
|
|
66
|
+
} finally {
|
|
67
|
+
reader.releaseLock();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
window.navigation?.addEventListener("navigate", (event) => {
|
|
71
|
+
if (!event.canIntercept) return;
|
|
72
|
+
if (event.hashChange || event.downloadRequest !== null) return;
|
|
73
|
+
const url = new URL(event.destination.url);
|
|
74
|
+
if (window.location.origin !== url.origin) {
|
|
75
|
+
window.location.href = url.href;
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
event.intercept({ async handler() {
|
|
79
|
+
await navigate(event.destination.url);
|
|
80
|
+
} });
|
|
81
|
+
});
|
|
82
|
+
if (import.meta.hot) import.meta.hot.on("rsc:update", (e) => {
|
|
83
|
+
console.log("[vite-rsc:update]", e.file);
|
|
84
|
+
navigate(location.href);
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
//#endregion
|
|
88
|
+
export { createServerCallback, hydrate };
|
package/dist/client.d.mts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { t as Payload } from "./generic-payload-Bio3B-X_.mjs";
|
|
2
|
+
import * as _$react from "react";
|
|
1
3
|
import * as _$react_jsx_runtime0 from "react/jsx-runtime";
|
|
2
4
|
|
|
3
5
|
//#region src/frames.client.d.ts
|
|
@@ -20,5 +22,6 @@ declare function ClientFrame({
|
|
|
20
22
|
children?: React.ReactNode;
|
|
21
23
|
src: string;
|
|
22
24
|
}): _$react_jsx_runtime0.JSX.Element;
|
|
25
|
+
declare function fetchFrame(url: URL, signal: AbortSignal, createFromFetch: (response: Promise<Response>, options?: object) => Promise<Payload>): Promise<string | number | bigint | boolean | Iterable<_$react.ReactNode> | _$react.ReactElement<unknown, string | _$react.JSXElementConstructor<any>> | _$react.ReactPortal | null | undefined>;
|
|
23
26
|
//#endregion
|
|
24
|
-
export { ClientFrame, FetchFrameProvider, useFrame };
|
|
27
|
+
export { ClientFrame, FetchFrameProvider, fetchFrame, useFrame };
|
package/dist/client.mjs
CHANGED
|
@@ -48,5 +48,17 @@ function ClientFrame({ children, src }) {
|
|
|
48
48
|
children: content
|
|
49
49
|
});
|
|
50
50
|
}
|
|
51
|
+
async function fetchFrame(url, signal, createFromFetch) {
|
|
52
|
+
url.pathname += ".rsc";
|
|
53
|
+
const payload = await createFromFetch(fetch(url, { signal }));
|
|
54
|
+
if (payload.type === "redirect") if (window.navigation) return Promise.resolve(window.navigation.navigate(payload.redirect, { history: "replace" }).finished).then(() => {
|
|
55
|
+
return null;
|
|
56
|
+
});
|
|
57
|
+
else {
|
|
58
|
+
window.location.href = payload.redirect;
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
return payload.root;
|
|
62
|
+
}
|
|
51
63
|
//#endregion
|
|
52
|
-
export { ClientFrame, FetchFrameProvider, useFrame };
|
|
64
|
+
export { ClientFrame, FetchFrameProvider, fetchFrame, useFrame };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ReactFormState } from "react-dom/client";
|
|
2
|
+
|
|
3
|
+
//#region src/generic-payload.d.ts
|
|
4
|
+
type Payload = {
|
|
5
|
+
type: "render";
|
|
6
|
+
root: React.ReactNode;
|
|
7
|
+
returnValue?: Promise<unknown>;
|
|
8
|
+
formState?: ReactFormState;
|
|
9
|
+
} | {
|
|
10
|
+
type: "redirect";
|
|
11
|
+
redirect: string;
|
|
12
|
+
returnValue?: Promise<unknown>;
|
|
13
|
+
formState?: undefined;
|
|
14
|
+
};
|
|
15
|
+
//#endregion
|
|
16
|
+
export { Payload as t };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,8 +1,24 @@
|
|
|
1
1
|
import * as _$react_jsx_runtime0 from "react/jsx-runtime";
|
|
2
2
|
import { ReactFormState } from "react-dom/client";
|
|
3
|
+
import { Middleware, Router } from "remix/fetch-router";
|
|
3
4
|
import { Route } from "remix/fetch-router/routes";
|
|
4
5
|
|
|
5
6
|
//#region src/frames.d.ts
|
|
7
|
+
declare function mapFrames<Frames extends Routes>(router: Router<any>, frames: Frames, {
|
|
8
|
+
components,
|
|
9
|
+
middleware
|
|
10
|
+
}: {
|
|
11
|
+
middleware?: Middleware[];
|
|
12
|
+
components: Components<Frames>;
|
|
13
|
+
}, config: {
|
|
14
|
+
createTemporaryReferenceSet: () => unknown;
|
|
15
|
+
fetchFrame: (url: URL, signal: AbortSignal) => Promise<React.ReactNode>;
|
|
16
|
+
prerender: (body: ReadableStream<Uint8Array>) => Promise<Response>;
|
|
17
|
+
renderToReadableStream: (payload: any, options?: {
|
|
18
|
+
temporaryReferences: unknown;
|
|
19
|
+
onError: (error: unknown) => string | undefined;
|
|
20
|
+
}) => ReadableStream<Uint8Array>;
|
|
21
|
+
}): void;
|
|
6
22
|
declare class UseServerState {
|
|
7
23
|
formState?: ReactFormState;
|
|
8
24
|
returnValue?: Promise<unknown>;
|
|
@@ -14,6 +30,19 @@ declare class RedirectState {
|
|
|
14
30
|
location: string;
|
|
15
31
|
constructor(location: string);
|
|
16
32
|
}
|
|
33
|
+
declare function useServerMiddleware({
|
|
34
|
+
createTemporaryReferenceSet,
|
|
35
|
+
decodeAction,
|
|
36
|
+
decodeFormState,
|
|
37
|
+
decodeReply,
|
|
38
|
+
loadServerAction
|
|
39
|
+
}: {
|
|
40
|
+
createTemporaryReferenceSet: () => unknown;
|
|
41
|
+
decodeAction: (formData: FormData) => Promise<() => Promise<void>>;
|
|
42
|
+
decodeFormState: (actionResult: unknown, body: FormData) => Promise<ReactFormState | undefined>;
|
|
43
|
+
decodeReply: (body: string | FormData, options?: object) => Promise<unknown[]>;
|
|
44
|
+
loadServerAction: (id: string) => Promise<Function>;
|
|
45
|
+
}): Middleware;
|
|
17
46
|
declare function redirect(location: string): void;
|
|
18
47
|
declare function render({
|
|
19
48
|
createTemporaryReferenceSet,
|
|
@@ -24,7 +53,7 @@ declare function render({
|
|
|
24
53
|
}: {
|
|
25
54
|
createTemporaryReferenceSet: () => unknown;
|
|
26
55
|
prerender: (body: ReadableStream<Uint8Array>) => Promise<Response>;
|
|
27
|
-
renderToReadableStream: (payload: any, options
|
|
56
|
+
renderToReadableStream: (payload: any, options?: {
|
|
28
57
|
temporaryReferences: unknown;
|
|
29
58
|
onError: (error: unknown) => string | undefined;
|
|
30
59
|
}) => ReadableStream<Uint8Array>;
|
|
@@ -35,7 +64,7 @@ declare class NotFoundError extends Error {
|
|
|
35
64
|
constructor(message: string);
|
|
36
65
|
}
|
|
37
66
|
interface Routes extends Record<string, Route | Routes> {}
|
|
38
|
-
type Components<R extends
|
|
67
|
+
type Components<R extends Routes> = { [K in keyof R]: R[K] extends Routes ? Components<R[K]> : React.ComponentType };
|
|
39
68
|
type ProvideFramesProps<Frames extends Routes> = {
|
|
40
69
|
children?: React.ReactNode;
|
|
41
70
|
components: Components<Frames>;
|
|
@@ -54,4 +83,4 @@ declare function Frame({
|
|
|
54
83
|
src: string;
|
|
55
84
|
}): _$react_jsx_runtime0.JSX.Element;
|
|
56
85
|
//#endregion
|
|
57
|
-
export { Frame, NotFoundError, ProvideFrames, ProvideFramesProps, RedirectState, UseServerState, redirect, render };
|
|
86
|
+
export { Frame, NotFoundError, ProvideFrames, ProvideFramesProps, RedirectState, UseServerState, mapFrames, redirect, render, useServerMiddleware };
|
package/dist/index.mjs
CHANGED
|
@@ -2,7 +2,39 @@ import { ClientFrame, FetchFrameProvider } from "./client.mjs";
|
|
|
2
2
|
import { cache } from "react";
|
|
3
3
|
import { getContext } from "remix/async-context-middleware";
|
|
4
4
|
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
import "remix/route-pattern";
|
|
5
6
|
//#region src/frames.tsx
|
|
7
|
+
function mapFrames(router, frames, { components, middleware }, config) {
|
|
8
|
+
for (let [key, frame] of Object.entries(frames)) if (typeof frame.pattern?.test === "function") {
|
|
9
|
+
const handler = ({ request }) => {
|
|
10
|
+
const { createTemporaryReferenceSet, fetchFrame, prerender, renderToReadableStream } = config;
|
|
11
|
+
return render({
|
|
12
|
+
createTemporaryReferenceSet,
|
|
13
|
+
prerender,
|
|
14
|
+
renderToReadableStream,
|
|
15
|
+
request,
|
|
16
|
+
root: /* @__PURE__ */ jsx(ProvideFrames, {
|
|
17
|
+
fetchFrame,
|
|
18
|
+
frames,
|
|
19
|
+
components,
|
|
20
|
+
children: /* @__PURE__ */ jsx(Frame, { src: request.url })
|
|
21
|
+
})
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
const action = {
|
|
25
|
+
handler,
|
|
26
|
+
middleware
|
|
27
|
+
};
|
|
28
|
+
let route = frame.pattern;
|
|
29
|
+
router.route("GET", route.source, action);
|
|
30
|
+
router.route("GET", route.source + ".rsc", action);
|
|
31
|
+
router.route("POST", route.source, action);
|
|
32
|
+
router.route("POST", route.source + ".rsc", action);
|
|
33
|
+
} else mapFrames(router, frame, {
|
|
34
|
+
components: components[key],
|
|
35
|
+
middleware
|
|
36
|
+
}, config);
|
|
37
|
+
}
|
|
6
38
|
var UseServerState = class {
|
|
7
39
|
formState;
|
|
8
40
|
returnValue;
|
|
@@ -21,6 +53,35 @@ var RedirectState = class {
|
|
|
21
53
|
this.location = location;
|
|
22
54
|
}
|
|
23
55
|
};
|
|
56
|
+
function useServerMiddleware({ createTemporaryReferenceSet, decodeAction, decodeFormState, decodeReply, loadServerAction }) {
|
|
57
|
+
return async ({ request, set }, next) => {
|
|
58
|
+
let formState;
|
|
59
|
+
let returnValue;
|
|
60
|
+
let temporaryReferences;
|
|
61
|
+
let actionStatus;
|
|
62
|
+
if (request.method === "POST") {
|
|
63
|
+
const actionId = request.headers.get("x-rsc-action");
|
|
64
|
+
if (actionId) try {
|
|
65
|
+
const body = request.headers.get("content-type")?.startsWith("multipart/form-data") ? await request.formData() : await request.text();
|
|
66
|
+
temporaryReferences = createTemporaryReferenceSet();
|
|
67
|
+
const args = await decodeReply(body, { temporaryReferences });
|
|
68
|
+
returnValue = (await loadServerAction(actionId)).apply(null, args);
|
|
69
|
+
await returnValue;
|
|
70
|
+
} catch (e) {
|
|
71
|
+
actionStatus = 500;
|
|
72
|
+
returnValue = Promise.reject(e);
|
|
73
|
+
}
|
|
74
|
+
else try {
|
|
75
|
+
const formData = await request.formData();
|
|
76
|
+
formState = await decodeFormState(await (await decodeAction(formData))(), formData);
|
|
77
|
+
} catch (e) {
|
|
78
|
+
console.error(e);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
set(UseServerState, new UseServerState(formState, returnValue, temporaryReferences, actionStatus));
|
|
82
|
+
return next();
|
|
83
|
+
};
|
|
84
|
+
}
|
|
24
85
|
function redirect(location) {
|
|
25
86
|
getContext().set(RedirectState, new RedirectState(location));
|
|
26
87
|
}
|
|
@@ -103,4 +164,4 @@ function match(frames, components, href) {
|
|
|
103
164
|
}
|
|
104
165
|
}
|
|
105
166
|
//#endregion
|
|
106
|
-
export { Frame, NotFoundError, ProvideFrames, RedirectState, UseServerState, redirect, render };
|
|
167
|
+
export { Frame, NotFoundError, ProvideFrames, RedirectState, UseServerState, mapFrames, redirect, render, useServerMiddleware };
|
|
@@ -5,119 +5,16 @@ import {
|
|
|
5
5
|
encodeReply,
|
|
6
6
|
setServerCallback,
|
|
7
7
|
} from "@vitejs/plugin-rsc/browser";
|
|
8
|
-
import { startTransition, StrictMode, use, useState } from "react";
|
|
9
|
-
import { hydrateRoot } from "react-dom/client";
|
|
10
|
-
import { rscStream } from "rsc-html-stream/client";
|
|
11
8
|
|
|
9
|
+
import { createServerCallback, hydrate } from "react-server-frame/browser";
|
|
12
10
|
import type { Payload } from "../generic-payload.ts";
|
|
13
11
|
|
|
14
|
-
setServerCallback(
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
method: "POST",
|
|
21
|
-
body: await encodeReply(args, { temporaryReferences }),
|
|
22
|
-
headers: {
|
|
23
|
-
"x-rsc-action": id,
|
|
24
|
-
},
|
|
25
|
-
}),
|
|
26
|
-
{ temporaryReferences },
|
|
27
|
-
);
|
|
28
|
-
if (payload.type === "render") {
|
|
29
|
-
startTransition(() => {
|
|
30
|
-
setPayload(Promise.resolve(payload));
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
if (payload.type === "redirect") {
|
|
34
|
-
if (window.navigation) {
|
|
35
|
-
navigate(payload.redirect);
|
|
36
|
-
} else {
|
|
37
|
-
window.location.href = payload.redirect;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
return payload.returnValue;
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
createFromReadableStream<Payload>(rscStream).then(
|
|
44
|
-
(payload) =>
|
|
45
|
-
startTransition(() => {
|
|
46
|
-
hydrateRoot(
|
|
47
|
-
document,
|
|
48
|
-
<StrictMode>
|
|
49
|
-
<Content initialPayload={Promise.resolve(payload)} />
|
|
50
|
-
</StrictMode>,
|
|
51
|
-
{
|
|
52
|
-
formState: payload.formState,
|
|
53
|
-
},
|
|
54
|
-
);
|
|
55
|
-
}),
|
|
56
|
-
(reason) => console.error("Failed to hydrate root", reason),
|
|
12
|
+
setServerCallback(
|
|
13
|
+
createServerCallback({
|
|
14
|
+
createFromFetch: (response, options) => createFromFetch<Payload>(response, options),
|
|
15
|
+
createTemporaryReferenceSet,
|
|
16
|
+
encodeReply,
|
|
17
|
+
}),
|
|
57
18
|
);
|
|
58
19
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
let seenPayloads = new WeakSet<Payload>();
|
|
62
|
-
|
|
63
|
-
function Content({ initialPayload }: { initialPayload: Promise<Payload> }) {
|
|
64
|
-
const [promise, _setPayload] = useState(initialPayload);
|
|
65
|
-
setPayload = _setPayload;
|
|
66
|
-
|
|
67
|
-
const payload = use(promise);
|
|
68
|
-
|
|
69
|
-
if (payload.type === "redirect") {
|
|
70
|
-
if (window.navigation) {
|
|
71
|
-
if (!seenPayloads) {
|
|
72
|
-
navigate(payload.redirect);
|
|
73
|
-
}
|
|
74
|
-
return null;
|
|
75
|
-
} else {
|
|
76
|
-
window.location.href = payload.redirect;
|
|
77
|
-
return null;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
return payload.root;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
let navigationController = new AbortController();
|
|
85
|
-
function navigate(to: string) {
|
|
86
|
-
const url = new URL(to, window.location.href);
|
|
87
|
-
url.pathname += ".rsc";
|
|
88
|
-
|
|
89
|
-
if (window.location.host !== url.host) {
|
|
90
|
-
window.location.href = url.href;
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
let thisController = new AbortController();
|
|
95
|
-
startTransition(() =>
|
|
96
|
-
setPayload(createFromFetch<Payload>(fetch(url, { signal: thisController.signal }))),
|
|
97
|
-
);
|
|
98
|
-
navigationController.abort();
|
|
99
|
-
navigationController = thisController;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
window.navigation?.addEventListener("navigate", (event) => {
|
|
103
|
-
if (!event.canIntercept) {
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
if (event.hashChange || event.downloadRequest !== null) {
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
event.intercept({
|
|
112
|
-
async handler() {
|
|
113
|
-
navigate(event.destination.url);
|
|
114
|
-
},
|
|
115
|
-
});
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
if (import.meta.hot) {
|
|
119
|
-
import.meta.hot.on("rsc:update", (e) => {
|
|
120
|
-
console.log("[vite-rsc:update]", e.file);
|
|
121
|
-
navigate(location.href);
|
|
122
|
-
});
|
|
123
|
-
}
|
|
20
|
+
hydrate({ createFromFetch, createFromReadableStream });
|
package/dist/vite/entry.ssr.tsx
CHANGED
|
@@ -6,7 +6,8 @@ import { injectRSCPayload } from "rsc-html-stream/server";
|
|
|
6
6
|
import type { Payload } from "../generic-payload.ts";
|
|
7
7
|
|
|
8
8
|
export async function prerender(body: ReadableStream<Uint8Array>) {
|
|
9
|
-
const [decodeBody,
|
|
9
|
+
const [decodeBody, _formStateBody] = body.tee();
|
|
10
|
+
const [formStateBody, inlineBody] = _formStateBody.tee();
|
|
10
11
|
|
|
11
12
|
let decode: Promise<Payload> | undefined;
|
|
12
13
|
function Content() {
|
|
@@ -31,8 +32,11 @@ export async function prerender(body: ReadableStream<Uint8Array>) {
|
|
|
31
32
|
try {
|
|
32
33
|
const bootstrapScriptContent = await import.meta.viteRsc.loadBootstrapScriptContent("index");
|
|
33
34
|
|
|
35
|
+
const payload = await createFromReadableStream<Payload>(formStateBody);
|
|
36
|
+
|
|
34
37
|
const html = await renderToReadableStream(<Content />, {
|
|
35
38
|
bootstrapScriptContent,
|
|
39
|
+
formState: payload.formState,
|
|
36
40
|
onError(reason: unknown) {
|
|
37
41
|
if (
|
|
38
42
|
typeof reason === "object" &&
|
|
@@ -46,7 +50,6 @@ export async function prerender(body: ReadableStream<Uint8Array>) {
|
|
|
46
50
|
},
|
|
47
51
|
});
|
|
48
52
|
|
|
49
|
-
const payload = await decode;
|
|
50
53
|
return new Response(html.pipeThrough(injectRSCPayload(inlineBody)), {
|
|
51
54
|
status: payload!.type === "redirect" ? 302 : notFoundError ? 404 : 200,
|
|
52
55
|
headers: {
|
|
@@ -1,18 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
import { fetchFrame as fetchFrame$1 } from "../client.mjs";
|
|
2
3
|
//#region src/vite/fetch-frame.ts
|
|
3
4
|
if (typeof document !== "undefined") import("@vitejs/plugin-rsc/browser");
|
|
4
5
|
async function fetchFrame(url, signal) {
|
|
5
6
|
const { createFromFetch } = await import("@vitejs/plugin-rsc/browser");
|
|
6
|
-
url
|
|
7
|
-
const payload = await createFromFetch(fetch(url, { signal }));
|
|
8
|
-
if (payload.type === "redirect") if (window.navigation) return Promise.resolve(window.navigation.navigate(payload.redirect, { history: "replace" }).finished).then(() => {
|
|
9
|
-
return null;
|
|
10
|
-
});
|
|
11
|
-
else {
|
|
12
|
-
window.location.href = payload.redirect;
|
|
13
|
-
return;
|
|
14
|
-
}
|
|
15
|
-
return payload.root;
|
|
7
|
+
return fetchFrame$1(url, signal, createFromFetch);
|
|
16
8
|
}
|
|
17
9
|
//#endregion
|
|
18
10
|
export { fetchFrame };
|
package/dist/vite/frames.d.mts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import { ProvideFrames as ProvideFrames$1 } from "../index.mjs";
|
|
1
|
+
import { ProvideFrames as ProvideFrames$1, mapFrames as mapFrames$1 } from "../index.mjs";
|
|
2
2
|
import * as _$react_jsx_runtime0 from "react/jsx-runtime";
|
|
3
3
|
import { Middleware } from "remix/fetch-router";
|
|
4
|
+
import { Route } from "remix/fetch-router/routes";
|
|
4
5
|
|
|
5
6
|
//#region src/vite/frames.d.ts
|
|
7
|
+
interface Routes extends Record<string, Route | Routes> {}
|
|
8
|
+
declare function mapFrames<Frames extends Routes>(router: Parameters<typeof mapFrames$1<Frames>>[0], frames: Parameters<typeof mapFrames$1<Frames>>[1], actions: Parameters<typeof mapFrames$1<Frames>>[2]): void;
|
|
6
9
|
declare function useServerMiddleware(): Middleware;
|
|
7
10
|
declare function render(request: Request, root: React.ReactNode): Promise<Response>;
|
|
8
11
|
declare function ProvideFrames(props: Omit<React.ComponentProps<typeof ProvideFrames$1>, "fetchFrame">): _$react_jsx_runtime0.JSX.Element;
|
|
9
12
|
//#endregion
|
|
10
|
-
export { ProvideFrames, render, useServerMiddleware };
|
|
13
|
+
export { ProvideFrames, mapFrames, render, useServerMiddleware };
|
package/dist/vite/frames.mjs
CHANGED
|
@@ -1,41 +1,26 @@
|
|
|
1
|
-
import { ProvideFrames as ProvideFrames$1,
|
|
1
|
+
import { ProvideFrames as ProvideFrames$1, mapFrames as mapFrames$1, render as render$1, useServerMiddleware as useServerMiddleware$1 } from "../index.mjs";
|
|
2
2
|
import { fetchFrame } from "./fetch-frame.mjs";
|
|
3
3
|
import { jsx } from "react/jsx-runtime";
|
|
4
4
|
import { createTemporaryReferenceSet, decodeAction, decodeFormState, decodeReply, loadServerAction, renderToReadableStream } from "@vitejs/plugin-rsc/rsc";
|
|
5
5
|
//#region src/vite/frames.tsx
|
|
6
|
+
function mapFrames(router, frames, actions) {
|
|
7
|
+
return mapFrames$1(router, frames, actions, {
|
|
8
|
+
createTemporaryReferenceSet,
|
|
9
|
+
fetchFrame,
|
|
10
|
+
prerender: async (...args) => {
|
|
11
|
+
return (await import.meta.viteRsc.import("./entry.ssr.tsx", { environment: "ssr" })).prerender(...args);
|
|
12
|
+
},
|
|
13
|
+
renderToReadableStream
|
|
14
|
+
});
|
|
15
|
+
}
|
|
6
16
|
function useServerMiddleware() {
|
|
7
|
-
return
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
if (actionId) {
|
|
15
|
-
const body = request.headers.get("content-type")?.startsWith("multipart/form-data") ? await request.formData() : await request.text();
|
|
16
|
-
temporaryReferences = createTemporaryReferenceSet();
|
|
17
|
-
const args = await decodeReply(body, { temporaryReferences });
|
|
18
|
-
const action = await loadServerAction(actionId);
|
|
19
|
-
try {
|
|
20
|
-
returnValue = action.apply(null, args);
|
|
21
|
-
await returnValue;
|
|
22
|
-
} catch (e) {
|
|
23
|
-
actionStatus = 500;
|
|
24
|
-
returnValue = Promise.reject(e);
|
|
25
|
-
}
|
|
26
|
-
} else {
|
|
27
|
-
const formData = await request.formData();
|
|
28
|
-
const decodedAction = await decodeAction(formData);
|
|
29
|
-
try {
|
|
30
|
-
formState = await decodeFormState(await decodedAction(), formData);
|
|
31
|
-
} catch (e) {
|
|
32
|
-
console.error(e);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
set(UseServerState, new UseServerState(formState, returnValue, temporaryReferences, actionStatus));
|
|
37
|
-
return next();
|
|
38
|
-
};
|
|
17
|
+
return useServerMiddleware$1({
|
|
18
|
+
createTemporaryReferenceSet,
|
|
19
|
+
decodeAction,
|
|
20
|
+
decodeFormState,
|
|
21
|
+
decodeReply,
|
|
22
|
+
loadServerAction
|
|
23
|
+
});
|
|
39
24
|
}
|
|
40
25
|
async function render(request, root) {
|
|
41
26
|
return render$1({
|
|
@@ -53,4 +38,4 @@ function ProvideFrames(props) {
|
|
|
53
38
|
});
|
|
54
39
|
}
|
|
55
40
|
//#endregion
|
|
56
|
-
export { ProvideFrames, render, useServerMiddleware };
|
|
41
|
+
export { ProvideFrames, mapFrames, render, useServerMiddleware };
|
package/dist/vite/plugin.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as Vite from "vite";
|
|
2
2
|
|
|
3
3
|
//#region src/vite/plugin.d.ts
|
|
4
|
-
declare function
|
|
4
|
+
declare function reactServerFrame({
|
|
5
5
|
entry
|
|
6
6
|
}?: {
|
|
7
7
|
entry?: string;
|
|
@@ -10,4 +10,4 @@ declare function framework({
|
|
|
10
10
|
config(this: Vite.ConfigPluginContext, userConfig: Vite.UserConfig): Record<string, any>;
|
|
11
11
|
};
|
|
12
12
|
//#endregion
|
|
13
|
-
export {
|
|
13
|
+
export { reactServerFrame };
|
package/dist/vite/plugin.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import * as Vite from "vite";
|
|
|
5
5
|
function getEntry(file) {
|
|
6
6
|
return Vite.normalizePath(path.join(path.dirname(fileURLToPath(import.meta.url)), file));
|
|
7
7
|
}
|
|
8
|
-
function
|
|
8
|
+
function reactServerFrame({ entry = "/src/entry.server" } = {}) {
|
|
9
9
|
return {
|
|
10
10
|
name: "framework",
|
|
11
11
|
config(userConfig) {
|
|
@@ -18,4 +18,4 @@ function framework({ entry = "/src/entry.server" } = {}) {
|
|
|
18
18
|
};
|
|
19
19
|
}
|
|
20
20
|
//#endregion
|
|
21
|
-
export {
|
|
21
|
+
export { reactServerFrame };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-server-frame",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"description": "A new type of RSC routing.",
|
|
5
5
|
"homepage": "https://github.com/jacob-ebey/react-server-frame#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"type": "module",
|
|
20
20
|
"exports": {
|
|
21
21
|
".": "./dist/index.mjs",
|
|
22
|
+
"./browser": "./dist/browser.mjs",
|
|
22
23
|
"./client": "./dist/client.mjs",
|
|
23
24
|
"./vite/fetch-frame": "./dist/vite/fetch-frame.mjs",
|
|
24
25
|
"./vite/frames": "./dist/vite/frames.mjs",
|