Server-Side Rendering (SSR)

Server-Side Rendering (SSR)

Our web application leverages Server-Side Rendering (SSR) using React Router v7 (Framework Mode) and the Hono web framework. This provides fast initial page loads, improved SEO, and a robust foundation for server-side logic.

Core Rendering Flow (entry.server.tsx)

When a request hits the server:

  1. i18n Initialization: The server determines the user's locale (i18next.server.ts) and initializes an i18next instance with the necessary translations for the requested route.
  2. React Rendering: renderToPipeableStream from react-dom/server is used to render the React component tree defined by React Router's <ServerRouter />.
  3. Streaming Response: The rendering process streams the HTML response back to the client as it's generated.
    • onShellReady (for regular users) sends the initial HTML shell quickly.
    • onAllReady (for bots) waits for all data loading to complete before sending the full HTML.
  4. Error Handling: Shell errors and general rendering errors are caught and handled appropriately.

Server Implementation (Hono)

We use the Hono framework for building our server-side logic:

  • server.node.ts: This is the main Hono application entry point used for standard Node.js environments (including local development).
    • It uses @hono/node-server.
    • Mounts middleware for logging (hono/logger) and static file serving (@hono/node-server/serve-static) with caching headers.
    • Mounts the API routes from @repo/api via ./api.ts at /api/v1.
    • Mounts an S3 image proxy via ./s3image.ts at /images.
    • Integrates the React Router SSR handler (createRequestHandler) to handle rendering for application routes.
  • app.server.ts: This Hono entry seems specifically tailored for Vercel deployments, using @hono/node-server/vercel. It primarily focuses on mounting the React Router SSR handler.
  • api.ts / api.vercel.ts: Defines the Hono router for API endpoints, mounting routes from the shared @repo/api package. api.vercel.ts wraps it for Vercel.
  • s3image.ts / s3image.vercel.ts: Defines the Hono router for proxying images from S3. s3image.vercel.ts wraps it for Vercel.

Development Environment (viteDevPlugin.ts)

During development (pnpm dev):

  • Our custom Vite plugin (customHonoDevPlugin) integrates the Hono server (server.node.ts) into Vite's development server middleware.
  • It intercepts requests that aren't for static assets or Vite internals.
  • It loads the Hono app using server.ssrLoadModule and uses @hono/node-server's getRequestListener to process the request through our Hono application, enabling SSR with HMR.

Build Process & Deployment

The build process is configured in vite.config.ts and orchestrated by @react-router/dev using react-router.config.ts.

  • react-router.config.ts: Defines ssr: true and utilizes presets to tailor the build for different environments:
    • preset.node.ts: Used for standard Node.js deployments.
      • It uses buildUtils.ts (buildEntry) to bundle the server.node.ts entry point using esbuild.
      • Creates a minimal package.json in the build output with only necessary production dependencies.
    • preset.vercel.ts: Used when VERCEL=1 is set.
      • Creates individual Vercel Serverless Functions (.func folders) for different parts of the application (e.g., _node_root, _node_admin_users, _extra_api_v1, _extra_images). This optimizes cold starts and resource usage.
      • Uses reactRouterConfig.serverBundles to determine which server bundle serves which top-level route path (with special handling for /admin/*).
      • Bundles the app.server.ts entry for the main application routes and specific entries (api.vercel.ts, s3image.vercel.ts) for extra functions (/api/v1, /images).
      • Uses @vercel/nft (nodeFileTrace) to trace dependencies for each function, copying only the necessary files into the .vercel/output/functions directory.
      • Generates Vercel configuration files (.vc-config.json, config.json) to define runtimes, routing rules, and other deployment settings.
  • buildUtils.ts: Contains shared esbuild logic used by both presets for bundling server entries efficiently.

Data Loading & Actions

  • make-loader.ts: A helper function to create React Router loaders. It handles authentication checks (redirecting if necessary), fetches user data, validates query parameters using Zod, and passes context to the specific loader handler.
  • make-action.ts: A similar helper for creating React Router actions. It handles authentication/authorization, parses request data (JSON or FormData), validates data using Zod, and executes the action handler.

This setup provides a performant and flexible SSR architecture optimized for both local development with Vite and deployment to Node.js or Vercel platforms.