Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Battle test RSC with Suspense + client components #190

Merged
merged 9 commits into from
Dec 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion arch/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"version": "0.0.1",
"scripts": {
"react-dom-server": "node react-dom-server.js",
"render-to-stream": "bun render-to-stream.js",
"render-html-to-stream": "bun render-html-to-stream.js",
"render-rsc-to-stream": "bun --conditions react-server render-rsc-to-stream.js",
"react-server-dom-webpack": "node --conditions react-server react-server-dom-webpack.js"
},
"license": "MIT",
Expand Down
106 changes: 0 additions & 106 deletions arch/server/react-server-dom-webpack.js

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -26,27 +26,28 @@ const debug = (readableStream) => {
reader.read().then(debugReader);
};

/* const app = () => (
<div>
<React.Suspense fallback="Fallback 1">
<DefferedComponent sleep={1}>"lol"</DefferedComponent>
</React.Suspense>
</div>
); */

const sleep = (seconds) =>
new Promise((res) => setTimeout(res, seconds * 1000));

const App = () => (
/* const App = () => (
<React.Suspense fallback="Fallback 1">
<DefferedComponent sleep={1}>
<React.Suspense fallback="Fallback 2">
<DefferedComponent sleep={1}>"lol"</DefferedComponent>
</React.Suspense>
</DefferedComponent>
</React.Suspense>
); */

const App = () => (
<div>
<React.Suspense fallback="Fallback 1">
<DefferedComponent sleep={1}>"lol"</DefferedComponent>
</React.Suspense>
</div>
);


ReactDOM.renderToReadableStream(<App />).then((stream) => {
debug(stream);
});
40 changes: 40 additions & 0 deletions arch/server/render-rsc-to-stream.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React from "react";
import { renderToPipeableStream } from "react-server-dom-webpack/server";

const DefferedComponent = async ({ sleep, children }) => {
await new Promise((res) => setTimeout(() => res(), sleep * 1000));
return <span>Sleep {sleep}s, {children}</span>;
};

const decoder = new TextDecoder();

const debug = (readableStream) => {
const reader = readableStream.getReader();
const debugReader = ({ done, value }) => {
if (done) {
console.log("Stream complete");
return;
}
console.log(decoder.decode(value));
console.log(" ");
return reader.read().then(debugReader);
};
reader.read().then(debugReader);
};

const sleep = (seconds) =>
new Promise((res) => setTimeout(res, seconds * 1000));

const App = () => (
<React.Suspense fallback="Fallback 1">
<DefferedComponent sleep={1}>
<React.Suspense fallback="Fallback 2">
<DefferedComponent sleep={1}>"lol"</DefferedComponent>
</React.Suspense>
</DefferedComponent>
</React.Suspense>
);

const { pipe } = renderToPipeableStream(<App />);

pipe(process.stdout);
2 changes: 1 addition & 1 deletion demo/client/dune
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
(enabled_if
(= %{profile} "dev"))
(modules index)
(libraries melange demo_shared_js reason-react)
(libraries melange demo_shared_js reason-react melange.dom melange-webapi)
(preprocess
(pps reason-react-ppx browser_ppx -js melange.ppx))
(module_systems es6))
Expand Down
4 changes: 3 additions & 1 deletion demo/client/index.re
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
let _ = MelRaw.mockInitWebsocket();

switch (ReactDOM.querySelector("#root")) {
let element = Webapi.Dom.Document.querySelector("#root", Webapi.Dom.document);

switch (element) {
| Some(el) =>
let _ = ReactDOM.Client.hydrateRoot(el, <App />);
();
Expand Down
35 changes: 20 additions & 15 deletions demo/client/runtime-with-client.jsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
window.__webpack_require__ = (id) => {
const component = window.__client_manifest_map[id];
console.log("REQUIRE ---");
const component = window.__client_manifest_map[id];
console.log(id);
console.log(component);
console.log("---");
/* return { __esModule: true, default: component }; */
return component;
return { __esModule: true, default: component };
};

const React = require("react");
Expand All @@ -21,17 +20,20 @@ const register = (name, render) => {
};

register(
"Note_editor",
React.lazy(() => import("./app/demo/universal/js/Note_editor.js")),
"Counter",
React.lazy(() => import("./app/demo/universal/js/Counter.js"))
);

register(
"Counter",
React.lazy(() => import("./app/demo/universal/js/Counter.js")),
"Note_editor",
React.lazy(() => import("./app/demo/universal/js/Note_editor.js")),
);
register(

/* register(
"Promise_renderer",
React.lazy(() => import("./app/demo/universal/js/Promise_renderer.js")),
);
); */

/* end bootstrap.js */

class ErrorBoundary extends React.Component {
Expand Down Expand Up @@ -68,14 +70,17 @@ try {
const stream = window.srr_stream.readable_stream;
const promise = ReactServerDOM.createFromReadableStream(stream);
const element = document.getElementById("root");
const app = (
<ErrorBoundary>
<Use promise={promise} />
</ErrorBoundary>
);

React.startTransition(() => {
const app = (
<ErrorBoundary>
<Use promise={promise} />
</ErrorBoundary>
);
ReactDOM.hydrateRoot(element, app);
});
} catch (e) {
console.error(e);
console.error("Error type:", e.constructor.name);
console.error("Full error:", e);
console.error("Stack:", e.stack);
}
33 changes: 27 additions & 6 deletions demo/server/server.re
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,34 @@ let stream_rsc = fn => {
);
};

let serverComponentsHandler = request => {
let sleep = (~ms, value) => {
let%lwt () = Lwt_unix.sleep(ms /. 1000.);
Lwt.return(value);
module Page = {
[@react.async.component]
let make = () => {
let%lwt () = Lwt_unix.sleep(1.0);
Lwt.return(
<Layout background=Theme.Color.black>
<Stack gap=8 justify=`start>
<p
className={Cx.make([
"text-3xl",
"font-bold",
Theme.text(Theme.Color.white),
])}>
{React.string("This is a small form")}
</p>
/* TODO: payload is wrong in client components */
<Note_editor title="Hello" body="World" />
<Hr />
<Counter initial=123 />
<Hr />
</Stack>
</Layout>,
);
};
let app = <Noter valueIn3seconds={sleep(~ms=300., "PROMISE VALUE HERE")} />;
};

let serverComponentsHandler = request => {
let app = <Page />;
switch (Dream.header(request, "Accept")) {
| Some(accept) when is_react_component_header(accept) =>
stream_rsc(stream => {
Expand Down Expand Up @@ -202,7 +224,6 @@ let router = [

let () = {
Dream.run(
~adjust_terminal=true,
~port=8080,
~interface={
switch (Sys.getenv_opt("SERVER_INTERFACE")) {
Expand Down
2 changes: 1 addition & 1 deletion demo/universal/native/lib/App.re
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ let make = () => {
<Stack gap=8 justify=`start>
<Title />
<Hr />
<Counter initial=23 />
<Counter initial=22 />
</Stack>
</Layout>;
};
19 changes: 2 additions & 17 deletions demo/universal/native/lib/Counter.re
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ let make = (~initial) => {
};

<div className={Theme.text(Theme.Color.white)}>
<Spacer bottom=3>
<Spacer bottom=0>
<div
className={Cx.make([
"flex",
Expand All @@ -26,17 +26,11 @@ let make = (~initial) => {
</button>
</div>
</Spacer>
<p className="text-lg">
{React.string(
"The HTML comes from the server"
++ " then is updated by the client after React runs. Via render or hydration (when using ReactDOM.hydrateRoot).",
)}
</p>
</div>;
};

[@react.component]
let make = (~initial) =>
let make = (~initial: int) =>
switch%platform (Runtime.platform) {
| Server =>
React.Client_component({
Expand All @@ -49,12 +43,3 @@ let make = (~initial) =>
};

let default = make;

/* switch%platform (Runtime.platform) {
| Server => ()
| Client =>
Components.register("Counter", (props: Js.t({..})) => {
React.jsx(make, makeProps(~initial=props##initial, ()))
})
};
*/
11 changes: 11 additions & 0 deletions demo/universal/native/lib/Hr.re
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[@react.component]
let make = () => {
<hr
className={Cx.make([
"block",
"w-full",
"h-px",
Theme.border("gray-700"),
])}
/>;
};
Loading
Loading