Use React 19 with server components without a framework

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…


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


Print Share Comment Cite Upload Translate Updates
APA

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/

MLA
" » Use React 19 with server components without a framework." roggc | Sciencx - Friday July 5, 2024, https://www.scien.cx/2024/07/05/use-react-19-with-server-components-without-a-framework/
HARVARD
roggc | Sciencx Friday July 5, 2024 » Use React 19 with server components without a framework., viewed ,<https://www.scien.cx/2024/07/05/use-react-19-with-server-components-without-a-framework/>
VANCOUVER
roggc | Sciencx - » Use React 19 with server components without a framework. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2024/07/05/use-react-19-with-server-components-without-a-framework/
CHICAGO
" » Use React 19 with server components without a framework." roggc | Sciencx - Accessed . https://www.scien.cx/2024/07/05/use-react-19-with-server-components-without-a-framework/
IEEE
" » Use React 19 with server components without a framework." roggc | Sciencx [Online]. Available: https://www.scien.cx/2024/07/05/use-react-19-with-server-components-without-a-framework/. [Accessed: ]
rf:citation
» Use React 19 with server components without a framework | roggc | Sciencx | 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.

You must be logged in to translate posts. Please log in or register.