Server-side rendering utilities for generating HTML strings from React elements, supporting both standard and static markup generation.
[@bs.module "react-dom/server"]
external renderToString: React.element => string = "renderToString";
[@bs.module "react-dom/server"]
external renderToStaticMarkup: React.element => string = "renderToStaticMarkup";[@react.component]
let make = (~title: string, ~content: string) => {
<html>
<head>
<title> {React.string(title)} </title>
<meta charset="utf-8" />
</head>
<body>
<div id="root">
<h1> {React.string(title)} </h1>
<p> {React.string(content)} </p>
</div>
</body>
</html>
};
/* Server-side rendering */
let renderPage = (title, content) => {
let html = ReactDOMServer.renderToString(<App title content />);
"<!DOCTYPE html>" ++ html;
};
/* Usage */
let htmlString = renderPage("My Page", "Welcome to my site!");[@react.component]
let make = (~posts: array(post)) => {
<html>
<head>
<title> {React.string("Blog")} </title>
<meta charset="utf-8" />
</head>
<body>
<main>
<h1> {React.string("Latest Posts")} </h1>
<ul>
{posts->Array.map(post =>
<li key=post.id>
<a href={"/posts/" ++ post.slug}>
{React.string(post.title)}
</a>
</li>
)->React.array}
</ul>
</main>
</body>
</html>
};
/* Generate static HTML (no React hydration data) */
let generateStaticBlog = (posts) => {
let html = ReactDOMServer.renderToStaticMarkup(<BlogPage posts />);
"<!DOCTYPE html>" ++ html;
};[@react.component]
let make = (~initialData: Js.Json.t) => {
<html>
<head>
<title> {React.string("Interactive App")} </title>
<meta charset="utf-8" />
</head>
<body>
<div id="root">
<InteractiveComponent initialData />
</div>
<script
dangerouslySetInnerHTML={
"__html": "window.__INITIAL_DATA__ = " ++ Js.Json.stringify(initialData)
}
/>
<script src="/bundle.js" />
</body>
</html>
};
/* Server-side render with hydration support */
let renderWithHydration = (initialData) => {
let html = ReactDOMServer.renderToString(<HydratedApp initialData />);
"<!DOCTYPE html>" ++ html;
};
/* Client-side hydration */
let hydrateClient = () => {
let initialData = [%raw "window.__INITIAL_DATA__"];
let container = ReactDOM.querySelector("#root");
switch (container) {
| Some(element) =>
ReactDOM.hydrate(<InteractiveComponent initialData />, element)
| None => ()
};
};[@react.component]
let make = (~url: ReasonReactRouter.url) => {
let content = switch (url.path) {
| [] => <HomePage />
| ["about"] => <AboutPage />
| ["posts", slug] => <PostPage slug />
| _ => <NotFoundPage />
};
<html>
<head>
<title> {React.string("My Site")} </title>
<meta charset="utf-8" />
</head>
<body>
<div id="root">
<nav>
<a href="/"> {React.string("Home")} </a>
<a href="/about"> {React.string("About")} </a>
</nav>
<main> {content} </main>
</div>
<script src="/bundle.js" />
</body>
</html>
};
/* Server route handler */
let handleRoute = (requestPath: string) => {
let url = ReasonReactRouter.dangerouslyGetInitialUrl(
~serverUrlString=requestPath,
()
);
let html = ReactDOMServer.renderToString(<RoutedApp url />);
"<!DOCTYPE html>" ++ html;
};let safeRenderToString = (element: React.element) => {
try {
ReactDOMServer.renderToString(element);
} catch {
| Js.Exn.Error(e) =>
Js.log2("SSR Error:", e);
ReactDOMServer.renderToString(
<html>
<body>
<h1> {React.string("Server Error")} </h1>
<p> {React.string("Please try again later.")} </p>
</body>
</html>
);
| _ =>
ReactDOMServer.renderToString(
<html>
<body>
<h1> {React.string("Unknown Error")} </h1>
</body>
</html>
);
}
};let interactiveHTML = ReactDOMServer.renderToString(<App />);
/* Output: <div data-reactroot="">...</div> */
let staticHTML = ReactDOMServer.renderToStaticMarkup(<App />);
/* Output: <div>...</div> */