UNPKG

polen

Version:

A framework for delightful GraphQL developer portals

90 lines 3.4 kB
import { reportError } from '#api/server/report-error'; import { React } from '#dep/react/index'; import { ResponseInternalServerError } from '#lib/kit-temp'; import * as Theme from '#lib/theme/theme'; import { Arr } from '@wollybeard/kit'; import * as ReactDomServer from 'react-dom/server'; import { createStaticRouter, StaticRouterProvider } from 'react-router'; import { templateVariables } from 'virtual:polen/template/variables'; import { view } from './view.js'; export const createPageHtmlResponse = async (staticHandlerContext, hooks, ctx) => { // Set up Polen global data before React SSR if context is provided if (ctx) { const themeManager = Theme.createThemeManager({ cookieName: `polen-theme-preference`, }); const cookies = ctx.req.header(`cookie`) || ``; const cookieTheme = themeManager.readCookie(cookies); const polenData = { serverContext: { theme: cookieTheme || 'system', // No cookie means system preference isDev: !__BUILDING__, }, }; globalThis.__POLEN__ = polenData; } const router = createStaticRouter(view.dataRoutes, staticHandlerContext); let appHtml = ``; try { appHtml = ReactDomServer.renderToString(React.createElement(React.StrictMode, null, React.createElement(StaticRouterProvider, { router, context: staticHandlerContext, }))); } catch (cause) { reportError(new Error(`Failed to server side render the HTML`, { cause })); return ResponseInternalServerError(); } // Create the base HTML document let html = ` <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>${templateVariables.title}</title> <link rel="icon" type="image/svg+xml" href="/favicon.svg"> </head> <body> <div id="app">${appHtml}</div> </body> </html>`; // Apply HTML transformation hook to the full document if (hooks?.transformHtml) { html = await hooks.transformHtml(html); } const headers = getRouteHeaders(staticHandlerContext); headers.set(`Content-Type`, `text/html; charset=utf-8`); // Check for custom status code in route handle const statusCode = getStatusCode(staticHandlerContext); return new Response(`<!DOCTYPE html>${html}`, { status: statusCode, headers, }); }; const getStatusCode = (context) => { // First check if React Router set a status code if (context.statusCode && context.statusCode !== 200) { return context.statusCode; } // Then check for custom status in route handle const handle = Arr.getLast(context.matches)?.route.handle; if (handle?.statusCode) { return handle.statusCode; } return 200; }; const getRouteHeaders = (context) => { const leaf = context.matches[context.matches.length - 1]; if (!leaf) return new Headers(); const actionHeaders = context.actionHeaders[leaf.route.id]; const loaderHeaders = context.loaderHeaders[leaf.route.id]; const headers = new Headers(actionHeaders); if (loaderHeaders) { for (const [key, value] of loaderHeaders.entries()) { headers.append(key, value); } } return headers; }; //# sourceMappingURL=create-page-html-response.js.map