رندر سمت سرور
کامپوننتهای ranui به shadow DOM اعلانی سریالسازی میشوند، پس سرور میتواند نشانهگذاری واقعی را بیرون بدهد و نخستین ترسیم، پیش از آنکه هیچ جاوااسکریپتی اجرا شود، درست باشد.
کجا به کارش ببرید: وقتی صفحهها را روی سرور یا در زمان ساخت رندر میکنید (یک SSG، مسیری در Express/Hono/Workers، کاری برای پیشنمایش ایمیل) و میخواهید عناصر
<r-*>بهشکل نشانهگذاری دیدنی برسند، نه تگهای خالیای که منتظر hydrationاند.
شروع سریع
import 'ranui'; // فهرست SSR را پر میکند — نخست همین
import { renderHTMLToString } from 'ranui/ssr-stream';
const html = await renderHTMLToString(`
<r-button type="primary">Submit</r-button>
<r-progress percent="65"></r-progress>
`);هر تگ <r-*>ِ ثبتشده نمونهسازی میشود، ویژگیهایش اعمال میشود، فرزندانش بهشکل بازگشتی رندر میشوند، و نتیجه با یک <template shadowrootmode="closed"> در درونش بیرون میآید. تگهای ناشناخته دستنخورده رد میشوند، پس اجرای آن روی یک صفحهٔ کامل از HTML معمولی امن است.
جریانسازی
renderToStream همان رندرکننده است، منتها بهشکل مولد ناهمگام؛ پس تکههای ایستا در حالی به کلاینت میرسند که کامپوننتهای بعدی هنوز در حال رندرند:
import { renderToStream } from 'ranui/ssr-stream';
for await (const chunk of renderToStream(pageHtml)) response.write(chunk);یک کامپوننت در هر بار
ranui/ssr نمونهای را رندر میکند که خودتان ساختهاید؛ وقتی بهجای قالبگذاری یک رشته، درختی را در Node سرهم میکنید به کار میآید:
import { renderToString } from 'ranui/ssr';
import { Button } from 'ranui';
const html = renderToString(new Button());مرجع API
| خروجی | نقطهٔ ورود | امضا | توضیح |
|---|---|---|---|
renderHTMLToString(html) | ranui/ssr-stream | (html: string) => Promise<string> | هر تگ <r-*>ِ ثبتشده را در یک رشتهٔ HTML باز میکند. |
renderToStream(html) | ranui/ssr-stream | (html: string) => AsyncGenerator<string> | همان، تکهتکه. |
renderToString(el) | ranui/ssr | (component) => string | یک نمونهٔ کامپوننت را سریالسازی میکند. |
RanElement | ranui/ssr | کلاس | در مرورگر HTMLElement، در Node ماکِت SSR. |
h(tag, props, …children) | ranui/ssr | (tag, props?, ...children) => string | ابزار کوچکی برای ساخت دستی نشانهگذاری. |
سرور چه میتواند و چه نمیتواند
کلاینت از نو میسازد؛ بازاستفاده نمیکند. ranui شادو روتهای بسته میچسباند، و فراخوانی attachShadow روی عنصری که پیشتر shadow root اعلانی دارد، وقتی حالت بسته باشد فرزندان آن root را حذف میکند. پس درختی که سرور رندر کرده نخستین فریم را میکشد و سپس با درختی همسان که کلاینت ساخته جایگزین میشود. دو پیامد دارد:
- آنچه به دست میآورید نخستین ترسیم درست است، نه بازاستفادهٔ hydration: شادو روت بسته را به دلیل بالا کلاینت نمیتواند بازاستفاده کند. راهنمای کدنویسی را ببینید.
- هرگز وضعیت را در نشانهگذاری shadowِ رندرشده در سرور نگذارید به این امید که کلاینت آن را بازبخواند. وضعیت را از راه ویژگیها بدهید؛ آنها جان به در میبرند.
هیچ چیز اندازهگیریشدهای روی سرور وجود ندارد. هرچه به getBoundingClientRect یا offsetWidth وابسته است، پس از mount و در مرورگر حل میشود. کامپوننتها دقیقاً به همین دلیل چنان نوشته شدهاند که چیدمان اولیهشان از CSS بیاید.
امروز چهار عنصر روی سرور رندر نمیشوند، هرکدام چون در سازندهاش به یک API مرورگر دست میزند: <r-content> (MutationObserver)، <r-link> (document)، <r-modal> (متدی از اسلات که ماکِت SSR پیاده نکرده) و <r-radar> (ResizeObserver). اینها بهشکل تگ ساده رد میشوند و روی کلاینت ارتقا مییابند. برای هر عنصر دیگری آزمونی هست که اگر رندر شدنش قطع شود شکست میخورد، پس این فهرست نمیتواند بیسروصدا بلند شود.
پوسته و جهش
initTheme() روی سرور کاری نمیکند (هر دسترسی به document / localStorage / matchMedia محافظتشده است)، پس پوسته را کلاینت اعمال میکند. برای پرهیز از جهشِ پوستهٔ نادرست، در قالب سروریتان data-ran-theme را روی <html> بگذارید (از روی یک کوکی، یا از یک اسکریپت درونخطی کوچک که پیش از نخستین ترسیم localStorage را میخواند) و پس از آن کار را به initTheme بسپارید.
بهترین شیوهها
- پیش از رندر،
ranui(یا نقاط ورود مشخصranui/<component>) را import کنید. فهرست با اثر جانبی همان import پر میشود؛ بدون آن هر تگ بازنشده رد میشود و صفحه بیصدا نشانهگذاریاش را از دست میدهد. - صفحه را رندر کنید، نه یک تکه را.
renderHTMLToStringروی هر HTML دلخواهی امن است، پس نیازی به جدا کردن بخشهای ranui نیست. - شیوهنامه را هم بفرستید. نشانهگذاری DSD استایلهای کامپوننت را با خود دارد، اما توکنهای سطح صفحه از
ranui/style(و برای قلمها ازranui/fonts) میآیند.