This content originally appeared on DEV Community and was authored by roggc
TLDR: Visit the Github repository.
Here I will expose a simple running project with react 19 and server components without a framework.
The dependencies
I will show you the package.json
for the dependencies needed to be installed for this project:
{
"babel": {
"presets": [
[
"@babel/preset-react",
{
"runtime": "automatic"
}
]
]
},
"scripts": {
"build": "node scripts/build.js",
"start": "node --conditions react-server server/server.js",
"build-and-start": "npm run build && npm run start"
},
"dependencies": {
"@babel/core": "^7.24.7",
"@babel/plugin-transform-modules-commonjs": "^7.24.7",
"@babel/preset-react": "^7.24.7",
"@babel/register": "^7.24.6",
"babel-loader": "^9.1.3",
"express": "^4.19.2",
"react": "^19.0.0-rc-3da26163a3-20240704",
"react-dom": "^19.0.0-rc-3da26163a3-20240704",
"react-server-dom-webpack": "^19.0.0-rc-3da26163a3-20240704",
"webpack": "^5.92.1"
}
}
The ones for react
, react-dom
, and react-server-dom-webpack
can be installed with the following command:
npm i react@rc react-dom@rc react-server-dom-webpack@rc
The rest of dependencies are installed as usual (npm i dependency-name
).
Folder structure of the project
We will have a public
folder with an index.html
file in it, a server
folder with a server.js
file, a scripts
folder with a build.js
file, and a src
folder with a index.js
file in it.
Content for public/index.html
<!-- public/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="description" content="React with Server Components" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>React Server Components</title>
<script defer src="main.js"></script>
</head>
<body>
<div id="root"></div>
</body>
</html>
The main.js
file referenced in the index.html
file will be generated by the build command.
scripts/build.js
const path = require("path");
const webpack = require("webpack");
const ReactServerWebpackPlugin = require("react-server-dom-webpack/plugin");
webpack(
{
mode: "development",
entry: [path.resolve(__dirname, "../src/index.js")],
output: {
path: path.resolve(__dirname, "../public"),
filename: "main.js",
},
module: {
rules: [
{
test: /\.js$/,
use: "babel-loader",
exclude: /node_modules/,
},
],
},
plugins: [new ReactServerWebpackPlugin({ isServer: false })],
},
(error, stats) => {
if (error) {
console.error(error);
}
}
);
src/index.js
file
import { use } from "react";
import { createFromFetch } from "react-server-dom-webpack/client";
import { createRoot } from "react-dom/client";
const root = createRoot(document.getElementById("root"));
root.render(<Root />);
const cache = new Map();
function Root() {
let content = cache.get("home");
if (!content) {
content = createFromFetch(fetch("/react"));
cache.set("home", content);
}
return <>{use(content)}</>;
}
server/server.js
file
const register = require("react-server-dom-webpack/node-register");
register();
const path = require("path");
const { readFileSync } = require("fs");
const babelRegister = require("@babel/register");
babelRegister({
ignore: [/[\\\/](build|server|node_modules)[\\\/]/],
presets: [["@babel/preset-react", { runtime: "automatic" }]],
plugins: ["@babel/transform-modules-commonjs"],
});
const { renderToPipeableStream } = require("react-server-dom-webpack/server");
const express = require("express");
const React = require("react");
const ReactApp = require("../src/app-s").default;
const app = express();
app.get("/", (req, res) => {
const html = readFileSync(
path.resolve(__dirname, "../public/index.html"),
"utf8"
);
res.send(html);
});
app.get("/react", (req, res) => {
const manifest = readFileSync(
path.resolve(__dirname, "../public/react-client-manifest.json"),
"utf8"
);
const moduleMap = JSON.parse(manifest);
const { pipe } = renderToPipeableStream(
React.createElement(ReactApp),
moduleMap
);
pipe(res);
});
app.use(express.static(path.resolve(__dirname, "../public")));
const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`listening on port ${port}`));
as we can see this last file, the server.js
, references (imports/requires) another one not seen yet:
const ReactApp = require("../src/app-s").default;
We will see it in next section.
Other files in src
folder: the app-s.js
file.
In src
folder we will have the files for React components (server and client components). The first one to be seen is the app-s.js
, a React server component:
import CounterS from "./counter-s";
import Client1S from "./client1-s";
import App from "./app";
import Wrapper from "./wrapper";
export default function () {
return (
<Wrapper>
<App>
<CounterS />
<Client1S />
</App>
</Wrapper>
);
}
The App
component used in this server component is a client component. CounterS
and Client1S
are also server components. Wrapper
is a special server component:
import { Suspense } from "react";
import ErrorBoundary from "./error-boundary";
export default function ({ children }) {
return (
<ErrorBoundary fallback={<div>Something crashed.</div>}>
<Suspense fallback={<div>loading...</div>}>{children}</Suspense>
</ErrorBoundary>
);
}
Client1S.js
import Client1 from "./client1";
import Wrapper from "./wrapper";
export default function Client1S() {
const promise = new Promise((res, rej) => {
setTimeout(() => res("foo"), 5000);
});
return (
<Wrapper>
<Client1 promise={promise} />
</Wrapper>
);
}
As you can see, in this server component we create a promise and pass it to the client component.
Client1.js
"use client";
import { use } from "react";
export default function ({ promise }) {
return <div>{use(promise)}</div>;
}
Note how we begin the component by "use client"
directive. This is important. All client components must have this directive.
What happens in this example
In the example that constitutes this project what happens is that we have a Counter
component that renders quickly and becomes interactive from the first moment and then we have another component that takes its time in fetching data from the server and shows a loading state.
References
This example is a result from looking at here.
This content originally appeared on DEV Community and was authored by roggc
roggc | Sciencx (2024-07-05T04:22:45+00:00) Use React 19 with server components without a framework. Retrieved from https://www.scien.cx/2024/07/05/use-react-19-with-server-components-without-a-framework/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.