This document describes the control flow in the Force application, from boot to screen rendering, including Express middleware, Relay middleware, server-side rendering (SSR), and route rendering.
Force is a React-based application with server-side rendering capabilities that runs on Node.js with Express. The application uses Relay for GraphQL data fetching and implements a sophisticated middleware chain for request processing.
graph TD
A[Application Boot] --> B[Express Server Initialization]
B --> C[Middleware Chain Setup]
C --> D[Route Matching]
D --> E[Server Router Setup]
E --> F[Relay Environment Creation]
F --> G[SSR Processing]
G --> H[HTML Template Generation]
H --> I[Response to Client]
C --> C1[Security & Basic Middleware]
C --> C2[Authentication Middleware]
C --> C3[Request Context Middleware]
C --> C4[Asset Middleware]
E --> E1[Route Hooks Execution]
E --> E2[Context Creation]
E --> E3[Relay Resolver Setup]
F --> F1[Network Layer Configuration]
F --> F2[Cache Middleware Setup]
F --> F3[Authentication Headers]
G --> G1[Component Tree Rendering]
G --> G2[Asset Collection]
G --> G3[Style Generation]
G --> G4[Script Tags Preparation]
The application starts by:
- Importing instrumentation for monitoring
- Creating an Express app instance
- Initializing the Unleash feature flag client
- Setting up middleware via
initializeMiddleware() - Configuring routes and error handling
sequenceDiagram
participant Boot as Application Boot
participant Express as Express App
participant Middleware as Middleware Setup
participant Unleash as Feature Flags
Boot->>Express: Create app instance
Boot->>Unleash: Initialize client
Boot->>Middleware: initializeMiddleware(app)
Boot->>Express: Setup routes & error handling
The middleware chain processes requests in the following order:
graph TD
A[Request] --> B[Server Timing Headers]
B --> C[Compression & Body Parsing]
C --> D[IP Filtering & Timeout]
D --> E[SSL & Security Headers]
E --> F[Session Management]
F --> G[Async Context Setup]
G --> H[Sharify Data Injection]
H --> I[Asset Middleware]
I --> J[Passport Authentication]
J --> K[User Permissions]
K --> L[App Preferences]
L --> M[Context Locals Bootstrap]
M --> N[Request Logging]
N --> O[Routing Middleware]
O --> P[CSRF Protection]
P --> Q[Static Asset Serving]
Key middleware components:
- Security: SSL enforcement, HSTS, frame protection
- Authentication: Passport.js with multiple OAuth providers
- Context: Sharify for shared data, async locals for request context
- Assets: Static file serving and asset manifest handling
When a route is matched, the application:
- Executes Route Hooks (
executeRouteHooks) - Creates Server Context (
getServerAppContext) - Initializes Relay Environment (
createRelaySSREnvironment) - Sets up Routing (Found.js with Farce)
sequenceDiagram
participant Route as Route Handler
participant Hooks as Route Hooks
participant Context as Server Context
participant Relay as Relay Environment
participant Router as Found Router
Route->>Hooks: executeRouteHooks(req, res, next)
Route->>Context: getServerAppContext(req, res, context)
Route->>Relay: createRelaySSREnvironment(config)
Route->>Router: getFarceResult(config)
Router-->>Route: Element or Redirect result
The Relay environment is configured with multiple middleware layers:
graph LR
A[GraphQL Request] --> B[URL Middleware]
B --> C[SSR Cache Middleware]
C --> D[Query Response Cache]
D --> E[Error Handlers]
E --> F[Cache Headers]
F --> G[Logging]
G --> H[Metaphysics API]
B --> B1[Authentication Headers]
B --> B2[Request Headers]
C --> C1[Server-side Cache]
C --> C2[Client Hydration]
Key features:
- Authentication: Conditional header injection based on request cacheability
- Caching: Multi-layer caching with TTL and mutation invalidation
- Error Handling: Principal field errors and Metaphysics-specific error handling
- SSR/Client Sync: Cache hydration from server to client
The SSR process involves several steps:
graph TD
A[Server Router] --> B[Boot Component Wrapping]
B --> C[Asset Collection]
C --> D[Style Generation]
D --> E[Script Tag Preparation]
E --> F[HTML Template Building]
C --> C1[Loadable Components]
C --> C2[Styled Components]
C --> C3[Relay Data Serialization]
B --> B1[Context Providers]
B --> B2[Theme Provider]
B --> B3[Feature Flag Provider]
B --> B4[Relay Environment Provider]
The Boot component sets up the complete React context:
graph TD
Boot --> AppPreferences[App Preferences Provider]
AppPreferences --> Theme[Theme Provider]
Theme --> Head[Head Provider]
Head --> System[System Context Provider]
System --> Relay[Relay Environment Provider]
Relay --> Error[Error Boundary]
Error --> Features[Feature Flag Provider]
Features --> Media[Media Context Provider]
Media --> Toasts[Toasts Provider]
Toasts --> Sticky[Sticky Provider]
Sticky --> Auth[Auth Providers]
Auth --> Cookie[Cookie Consent Manager]
Cookie --> App[Application Content]
The asset collection process (collectAssets) handles:
sequenceDiagram
participant Collector as Asset Collector
participant Loadable as Loadable Components
participant Styles as Styled Components
participant Relay as Relay SSR
participant Manifest as Asset Manifest
Collector->>Loadable: Extract chunk dependencies
Collector->>Styles: Collect CSS styles
Collector->>Relay: Serialize hydration data
Collector->>Manifest: Get script/asset URLs
Note over Collector: Generate script tags with CDN URLs
Note over Collector: Prepare Relay hydration script
The final HTML template (buildHtmlTemplate) includes:
- Head Section: Meta tags, preload hints, CSS links
- Body Section: SSR content, script tags, React mount point
- Optimization: Resource preloading, CDN integration, font optimization
graph LR
A[HTML Template] --> B[Head Section]
A --> C[Body Section]
B --> B1[Meta Tags]
B --> B2[Preload Links]
B --> B3[Stylesheets]
B --> B4[Sharify Data]
C --> C1[Analytics Scripts]
C --> C2[SSR Content]
C --> C3[Runtime Scripts]
C --> C4[React Mount Point]
Streaming SSR (Disabled/Experimental)
When enabled (ENABLE_SSR_STREAMING), the application supports streaming server-side rendering. This feature is currently disabled and considered experimental.
sequenceDiagram
participant Client as Client Browser
participant Server as Express Server
participant Stream as SSR Stream
participant React as React Renderer
Client->>Server: Request
Server->>Stream: Initialize stream
Server->>Client: Send HTML head
Stream->>React: Begin component rendering
React->>Stream: Stream rendered chunks
Stream->>Client: Stream HTML content
React->>Stream: Complete rendering
Stream->>Client: Send closing tags
The application behavior is controlled by various environment variables and configuration:
- CDN_URL: Asset CDN configuration
- NODE_ENV: Environment-specific behavior
- ENABLE_SSR_STREAMING: Streaming SSR toggle
- SEGMENT_WRITE_KEY: Analytics configuration
- Feature flags: Runtime behavior modification via Unleash
Force uses a two-tier error boundary system so that errors render inside the normal layout (with nav/footer) instead of dumping users to a logo-only page.
Boot.tsx
|
+-- ErrorBoundary (outer)
| | Catches: chunk load failures, Layout crashes.
| | Replaces entire page. Last resort.
| |
| +-- Providers -> Router -> AppShell
| |
| +-- Layout (NavBar + footer)
| |
| +-- ContentErrorBoundary (inner)
| | Catches: component crashes, HttpErrors.
| | Only replaces content area. Nav stays.
| | Resets on pathname change.
| |
| +-- Route content
| Error type | Caught by | Nav preserved? | HTTP |
|---|---|---|---|
@principalField 404 |
Route render() via renderRouteError() |
Yes | 404 |
| Component crash | ContentErrorBoundary |
Yes | 200* |
| Chunk load failure | Outer ErrorBoundary (bubbled up) |
No | 200* |
| Layout crash | Outer ErrorBoundary |
No | 200* |
| Unmatched Express route | errorHandlerMiddleware |
No | 404 |
*Client-side -- page already delivered.
Error handling for simple routes is automatic -- buildAppRoutes injects a default error render on any route with a query but no custom render. Routes with custom render functions must handle errors explicitly via renderRouteError(). See adding_new_app.md.
For a detailed deep-dive, see error-handling.md.
For detailed information about Force's caching architecture, see architecture-caching.md.
This architecture ensures robust request processing from initial server boot through final HTML delivery to the client, with comprehensive caching, authentication, and rendering capabilities.