implement ssr
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
import { renderToString } from "react-dom/server";
|
||||
import { StaticRouter } from "react-router-dom";
|
||||
import { AuthProvider } from "./providers/AuthProvider";
|
||||
import { SsrDataProvider } from "./ssr/context";
|
||||
import { matchSsrRoute, type ApiFetch } from "./ssr/routes";
|
||||
import type { SsrData, SsrHead } from "./ssr/types";
|
||||
import App from "./app";
|
||||
|
||||
type RenderResult =
|
||||
/** Not a server-rendered route - serve the client-only shell. */
|
||||
| { kind: "spa" }
|
||||
/** Server-rendered route whose content is missing - shell, with a 404. */
|
||||
| { kind: "not-found" }
|
||||
| { kind: "ssr"; html: string; data: SsrData; head: SsrHead };
|
||||
|
||||
async function render(url: string, api: ApiFetch): Promise<RenderResult> {
|
||||
const pathname = new URL(url, "http://ssr.invalid").pathname;
|
||||
const matched = matchSsrRoute(pathname);
|
||||
if (!matched) return { kind: "spa" };
|
||||
|
||||
const loaded = await matched.route.load(api, matched.params);
|
||||
if (!loaded) return { kind: "not-found" };
|
||||
|
||||
// The visitor's session is deliberately not resolved here: auth-dependent
|
||||
// chrome renders logged-out on the server and AuthProvider fills it in after
|
||||
// hydration, which keeps these pages cacheable and hydration-safe.
|
||||
const html = renderToString(
|
||||
<SsrDataProvider data={loaded.data}>
|
||||
<AuthProvider>
|
||||
<StaticRouter location={url}>
|
||||
<App />
|
||||
</StaticRouter>
|
||||
</AuthProvider>
|
||||
</SsrDataProvider>,
|
||||
);
|
||||
|
||||
return { kind: "ssr", html, data: loaded.data, head: loaded.head };
|
||||
}
|
||||
|
||||
export { render };
|
||||
export { defaultHead } from "./ssr/routes";
|
||||
export type { RenderResult };
|
||||
Reference in New Issue
Block a user