UNPKG

everything-dev

Version:

A consolidated product package for building Module Federation apps with oRPC APIs.

152 lines (150 loc) • 5.51 kB
import { readAcceptLanguage, resolveLocale } from "./locale.mjs"; import { collectHeadData } from "./router.mjs"; import { createApiClient } from "./api.mjs"; import { createAuthClient } from "./auth.mjs"; import { defaultNotFoundComponent, defaultPendingComponent, defaultQueryClient } from "./router-defaults.mjs"; import { RouterError } from "./router-error.mjs"; import { jsx } from "react/jsx-runtime"; import { createMemoryHistory, createRouter } from "@tanstack/react-router"; import { QueryClient, QueryClientProvider, dehydrate, hydrate } from "@tanstack/react-query"; import { RouterServer, createRequestHandler, renderRouterToStream } from "@tanstack/react-router/ssr/server"; //#region src/ui/router-server.tsx /** * SSR router factory — creates request-scoped server routers and server-side * API/auth clients per request. Mirrors the client router shape for * hydration consistency. The app injects its generated route tree and (for * a byte-identical child surface) its error component. */ function createServerRouterModule(options = {}) { const defaultRouteTree = options.defaultRouteTree; const createRouter$1 = (opts) => { const context = opts?.context; const queryClient = context?.queryClient ?? defaultQueryClient(); const history = opts?.history ?? createMemoryHistory(); const cspNonce = context?.cspNonce; return { router: createRouter({ routeTree: opts?.routeTree ?? defaultRouteTree, history, basepath: opts?.basepath, context: { queryClient, runtimeConfig: context?.runtimeConfig, apiClient: context?.apiClient, authClient: context?.authClient ?? createAuthClient({ runtimeConfig: context?.runtimeConfig, cspNonce: context?.cspNonce }), session: context?.session, cspNonce, locale: context?.locale, pluginNav: context?.pluginNav }, ...cspNonce ? { ssr: { nonce: cspNonce } } : {}, defaultPreload: "intent", scrollRestoration: true, defaultStructuralSharing: true, defaultPreloadStaleTime: 0, defaultErrorComponent: RouterError, defaultOnCatch: (error, errorInfo) => { console.error("[SSR] Router error boundary caught:", error, { componentStack: errorInfo.componentStack }); }, defaultNotFoundComponent, defaultPendingComponent, defaultPendingMinMs: 0, dehydrate: () => { if (typeof window === "undefined") return { queryClientState: dehydrate(queryClient) }; return { queryClientState: {} }; }, hydrate: (dehydrated) => { if (typeof window !== "undefined" && dehydrated?.queryClientState) hydrate(queryClient, dehydrated.queryClientState); } }), queryClient }; }; const buildRouter = options.createRouter ?? createRouter$1; const getRouteHead = async (pathname, context) => { const history = createMemoryHistory({ initialEntries: [pathname] }); const queryClient = new QueryClient(); const runtimeConfig = context?.runtimeConfig; if (!runtimeConfig?.hostUrl || !runtimeConfig.rpcBase) throw new Error("Missing runtime config for route head generation"); const router = createRouter({ routeTree: context?.routeTree ?? defaultRouteTree, history, context: { queryClient, runtimeConfig, apiClient: context?.apiClient ?? createApiClient({ hostUrl: runtimeConfig.hostUrl, rpcBase: runtimeConfig.rpcBase }), authClient: context?.authClient ?? createAuthClient({ runtimeConfig, cspNonce: context?.cspNonce }), session: context?.session, locale: context?.locale } }); return collectHeadData(router); }; const renderToStream = async (request, renderOptions) => { const url = new URL(request.url); const history = createMemoryHistory({ initialEntries: [url.pathname + url.search] }); let queryClientRef = null; const response = await createRequestHandler({ request, createRouter: () => { const localQueryClient = queryClientRef ?? options.createQueryClient?.() ?? defaultQueryClient(); const built = buildRouter({ history, routeTree: renderOptions.routeTree, basepath: renderOptions.basepath, context: { queryClient: localQueryClient, runtimeConfig: renderOptions.runtimeConfig, apiClient: renderOptions.apiClient, authClient: createAuthClient({ runtimeConfig: renderOptions.runtimeConfig, headers: request.headers, cspNonce: renderOptions.cspNonce }), session: renderOptions.session, cspNonce: renderOptions.cspNonce, pluginNav: renderOptions.pluginNav, locale: options.locale ? resolveLocale({ ...options.locale, cookie: request.headers.get("cookie") ?? "", browserLocales: readAcceptLanguage(request.headers.get("accept-language")) }) : void 0 } }); queryClientRef = built.queryClient ?? localQueryClient; return built.router; } })(({ request, responseHeaders, router }) => renderRouterToStream({ request, responseHeaders, router, children: /* @__PURE__ */ jsx(QueryClientProvider, { client: queryClientRef, children: /* @__PURE__ */ jsx(RouterServer, { router }) }) })); if (options.locale) response.headers.append("Vary", "Cookie, Accept-Language"); return { stream: response.body, statusCode: response.status, headers: response.headers }; }; return { createRouter: createRouter$1, getRouteHead, renderToStream }; } //#endregion export { createServerRouterModule }; //# sourceMappingURL=router-server.mjs.map