React Server Components بدون هیچ چارچوبی

با شروع با Next.js 13، توسعه دهندگان می توانند به قدرت React Server Components دسترسی داشته باشند (از این به بعد فقط از RSC استفاده کنیم). اما اگر نمی خواهید از Next.js استفاده کنید و می خواهید از RSC خارج از جعبه استفاده کنید، پس چگونه باید شروع کنید؟
شما باید از نسخه های آزمایشی استفاده کنید react
، react-dom
و react-server-dom-webpack
.
بیایید یک پروژه جدید راه اندازی کنیم و اینها را نصب کنیم. ما استفاده خواهیم کرد pnpm
، زیرا اکنون بهترین و محبوب ترین انتخاب است. همچنین برای راهاندازی سریع، از Vite برای سمت کلاینت و از HatTip برای کنترلر پشتیبان خود برای مدیریت راحتتر جریان خوانا استفاده میکنیم.
mkdir hello-rsc
cd hello-rsc
pnpm init
pnpm add react@experimental react-dom@experimental react-server-dom-webpack@experimental vite @vitejs/plugin-react @hattip/core @hattip/adapter-node
برای شروع کار با رندر SSR با Vite، باید چند فایل برای شروع کار ایجاد کنیم.
SSR
ما به یک نیاز خواهیم داشت index.html
فایل، که الگوی HTML SSR ما خواهد بود، که اسکریپت ورودی مشتری را بارگیری می کند. این بسیار بسیار کم است.
<script type="module" src="index.jsx"></script>
<div id="root"></div>
برای راه اندازی سرور توسعه Vite دارای SSR، اجازه دهید یک سرور ایجاد کنیم index.mjs
فایل، که در آن سرور توسعه Vite را در حالت میانافزار و با آن نمونهسازی میکنیم “ssr” به عنوان نوع برنامه
import { createMiddleware } from "@hattip/adapter-node";
import { createServer as createViteDevServer } from "vite";
import react from "@vitejs/plugin-react";
import { readFile } from "node:fs/promises";
const viteDevServer = await createViteDevServer({
server: {
middlewareMode: true,
},
appType: "ssr",
plugins: [react()],
});
ما باید خود را از قبل بارگذاری کنیم index.html
برای استفاده بعدی پس بیایید فایل را همانطور که هست بخوانیم.
const html = await readFile("./index.html", "utf-8");
کنترل کننده HatTip زیر روتر ما برای رسیدگی به درخواست هایی خواهد بود که پاسخ RSC را می پذیرد. اگر Accept
هدر شامل text/x-component
نوع MIME، سپس می دانیم که مشتری به پاسخ در قالب RSC نیاز دارد.
فرمت RSC یک فرمت JSON مانند است که شامل تمام عناصر React است که مشتری ارائه خواهد کرد.
0:"$L1"
1:[["$","h1",null,{"children":"Hello World!"}],["$","h2",null,{"children":["Darwin"," ","x64"," ","22.5.0"]}],"2023-07-07T12:40:30.880Z"]
پیاده سازی ما بارگذاری می شود rsc.jsx
ماژول SSR با استفاده از Vite و با استفاده از render
تابعی که RSC را به یک جریان قابل خواندن تبدیل می کند. ما همچنین برخی از مدیریت خطاهای اساسی را انجام می دهیم.
const ssr = createMiddleware(async ({ request }) => {
if (request.headers.get("accept").includes("text/x-component")) {
try {
const { render } = await viteDevServer.ssrLoadModule("./rsc.jsx");
return new Response(await render(), {
headers: {
"content-type": "text/x-component",
},
});
} catch (e) {
return new Response(e.stack, {
status: 500,
headers: {
"content-type": "text/plain",
},
});
}
}
return new Response(
await viteDevServer.transformIndexHtml(request.url, html),
{
headers: {
"content-type": "text/html",
},
}
);
});
در پایان، فقط باید شروع به گوش دادن به درخواست ها با استفاده از سرور توسعه Vite کنیم. به عنوان
viteDevServer.middlewares.use(ssr);
viteDevServer.middlewares.listen(3000).on("listening", () => {
console.log("Listening on http://localhost:3000");
});
React Server Component
چگونه rsc.jsx
به نظر می رسد؟ واقعا خیلی ساده است. ماژول اصلی وارداتی که باید مراقب آن باشیم، است react-server-dom-webpack/server.edge
. ما <App />
کامپوننت یک تابع همگام است، بنابراین ما می توانیم استفاده کنیم await
در داخل آن و در پایان، فقط JSX را برگردانید، جایی که میتوانیم عملکرد فقط سمت سرور را نیز درج کنیم، بنابراین اطلاعات مربوط به سیستمعامل خود و زمان فعلی را به مشتری میدهیم. اما ابتدا پاسخ را کمی به تاخیر می اندازیم.
import { renderToReadableStream } from "react-server-dom-webpack/server.edge";
import * as OS from "node:os";
async function delay(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
async function App() {
await delay(500);
return (
<>
<h1>Hello World!</h1>
<h2>
{OS.type()} {OS.arch()} {OS.release()}
</h2>
{new Date().toISOString()}
</>
);
}
export async function render() {
return renderToReadableStream(<App />);
}
صادر شده render
تابعی است که ما در آن استفاده کردیم index.mjs
کنترل کننده، بارگذاری شده با Vite به عنوان یک ماژول SSR.
مشتری
آخرین قسمتی که باید پیاده سازی کنیم ورودی کلاینت است، جایی که ریشه React خود را ایجاد می کنیم تا پاسخ RSC را ارائه دهیم.
import { Suspense } from "react";
import { createRoot } from "react-dom/client";
import { createFromFetch } from "react-server-dom-webpack/client.browser";
let rsc = null;
function App() {
if (!rsc) {
rsc = createFromFetch(
fetch("/app", {
headers: {
Accept: "text/x-component",
},
})
);
}
return rsc;
}
const root = createRoot(document.getElementById("root"));
root.render(
<Suspense fallback="Loading...">
<App />
</Suspense>
);
باید a اضافه کنیم Suspense
اطراف ما <App />
کامپوننت تا زمانی که کلاینت پاسخ RSC را دریافت می کند، پیام بارگیری مجدد را نشان می دهد.
ما همچنین باید نتیجه را “کش” کنیم createFromFetch
از آنجایی که ما نمیخواهیم این بیش از یک بار اجرا شود و همیشه باید یکسان باشد، بنابراین React میتواند این مشکل را کنترل کند. <App />
جزء به درستی
بهبود آینده
در حال حاضر، رندر RSC ما از اجزای مشتری پشتیبانی نمی کند ('use client'
)، فقط عناصر رندر شده در سمت سرور. ما همچنین از اقدامات سرور در این پیاده سازی پشتیبانی نمی کنیم. اینها موضوعات بسیار پیشرفته تری هستند و شما باید از Next.js 13 برای این یا متا فریمورک دیگری که از این ویژگی ها پشتیبانی می کند استفاده کنید.
مطمئناً این فقط یک است “سلام دنیا!” پیاده سازی سطح و می تواند بهبود یابد، اما شاید این نقطه شروع خوبی باشد که می خواهید با برخی از پیاده سازی های سطح پایین در رابطه با React Server Components بازی کنید.
در این مخزن می توانید به کد دسترسی پیدا کنید
با تشکر از خواندن، لطفا روی دنبال کردن کلیک کنید و روز خوبی داشته باشید!