Type to search pages and rules.

Browse pages

Frontend Rendering and Routes

A route answers three questions: what address is this, what data does it need, and which floorplan draws it.

Markdown12 provisions

Intent#

A route answers three questions: what address is this, what data does it need, and which floorplan draws it. Everything else belongs in a module.

The render boundary follows the audience the route serves. A console serves a signed-in reader from a cache its route fills. A public page arrives from a link, so its first response already describes itself.

Standards#

Load route data before rendering#

ruleguidance

Requirement A route MUST load each read it needs through one shared cache before its view renders.

Rationale The page then renders with its data rather than showing a spinner after it appears. The cache owns freshness, so the router never holds a second copy.

Example An entity route loads its record and every read the record's own sections need.

litespec/frontend/rendering#load-route-data-before-rendering

Read route data from the route cache#

ruleguidance

Requirement A view MUST read route data through the same cache entry its route filled.

Rationale A read naming another key issues a second request, and the two answers can disagree. A failed read reaches the route's error boundary, which draws the shared problem state.

litespec/frontend/rendering#read-route-data-from-the-route-cache

Keep address parameters validated by a schema#

ruleguidance

Requirement A route MUST declare its address parameters in a validated schema, including its filters and its page.

Rationale A filtered list is then a link somebody can share, bookmark, and reopen. A filter in component state reaches nobody and is lost on the first navigation away.

Example The list schema declares its own text field and spreads the shared paging fields.

litespec/frontend/rendering#keep-address-parameters-validated-by-a-schema

Load each route and each language separately#

ruleguidance

Requirement A frontend MUST load each route and each language as its own download, with no icon set or language loaded whole.

Rationale A signed-in user opens one address and reads one language. A reader in Dutch who never leaves the dashboard should not download English.

Example A dictionary loader returns one language. Each route file or folder ships as its own download.

litespec/frontend/rendering#load-each-route-and-each-language-separately

Prefetch a route on intent#

ruleguidance

Requirement A frontend MUST prefetch the route the reader signals intent toward, without treating that prefetch as a cache beyond the shared cache.

Rationale Most navigations then render from the cache the routes already fill. A router caching a second time serves a stale answer beside a fresh one.

litespec/frontend/rendering#prefetch-a-route-on-intent

Represent route states#

ruleguidance

Requirement A data-driven route MUST define its loading, empty, error, forbidden, not-found, and ready behavior.

Rationale A blank region while a request is pending or failed gives the reader no signal at all. The root not-found handling draws the shared outcome page.

These six are the states a route has. A control adds disabled and pending under litespec/frontend/components#render-complete-states, because both describe a control rather than a route. A route adds not-found, which a control does not, because a missing target resolves at the route.

litespec/frontend/rendering#represent-route-states

Keep authenticated caching explicit#

ruleguidance

Requirement Actor-specific data MUST declare its cache key, partition, invalidation owner, and security review before caching, beside the read definition setting the key.

Rationale Shared route behavior otherwise serves one actor's data to another. An uncached read is the safe default, and a cache partitioned per request is the safe server shape.

litespec/frontend/rendering#keep-authenticated-caching-explicit

Keep proxy behavior at the edge#

ruleguidance

Requirement A development or edge proxy rule MUST route only, and never decide who the actor is or what the actor may read.

Rationale The proxy runs before the request reaches the API, so it cannot see the resource authorization depends on.

Example A development proxy forwards /api and /auth to the API and changes nothing else.

litespec/frontend/rendering#keep-proxy-behavior-at-the-edge

Build the server data cache per request#

ruleguidance

Requirement A server-rendered frontend MUST construct its data cache inside each request.

Rationale Two readers served at the same time must not read each other's data. A cache outliving one request would serve the next reader the previous reader's answer.

litespec/frontend/rendering#build-the-server-data-cache-per-request

Conventions#

Use a shared layout for a shell#

conventionguidance

Default Give a shell a layout holding the frame every child route shares.

Replacement A consumer can replace this default with an explicit local convention.

Rationale A layout adds no address segment, so the shell never appears in a link.

litespec/frontend/rendering#use-a-shared-layout-for-a-shell

Keep layouts stable#

conventionguidance

Default Keep a layout to the frame and the providers every child route needs.

Replacement A consumer can replace this default with an explicit local convention.

Rationale A feature-specific provider wrapping the whole application forces unrelated routes to carry its cost.

litespec/frontend/rendering#keep-layouts-stable

Keep server-only code identifiable#

conventionguidance

Default Keep a module reading a request header, a cookie, or a server secret in a file whose name and place show the server ownership.

Replacement A consumer can replace this default with an explicit local convention.

Rationale The server marking turns an accidental browser import into a build error, and the file name carries the same fact to a reader.

litespec/frontend/rendering#keep-server-only-code-identifiable

Verification#

IDMarkEvidence
litespec/frontend/rendering#load-route-data-before-renderingguidanceDoes each route that reads load it through one shared cache before its view renders?
litespec/frontend/rendering#read-route-data-from-the-route-cacheguidanceDoes each read name the entry its route filled?
litespec/frontend/rendering#keep-address-parameters-validated-by-a-schemaguidanceDoes each route declare its address parameters in a schema, with no direct reads?
litespec/frontend/rendering#load-each-route-and-each-language-separatelyguidanceDoes each route and each language load as its own download?
litespec/frontend/rendering#prefetch-a-route-on-intentguidanceDoes the router prefetch the route the reader signals intent toward, with no second cache?
litespec/frontend/rendering#represent-route-statesguidanceDoes an absent address render the shared outcome page?
litespec/frontend/rendering#keep-authenticated-caching-explicitguidanceDoes each cached actor-specific read declare its key, boundary, owner, and review?
litespec/frontend/rendering#keep-proxy-behavior-at-the-edgeguidanceDoes any proxy rule decide the actor or what the actor may read?
litespec/frontend/rendering#build-the-server-data-cache-per-requestguidanceDoes each server request construct its own data cache?
litespec/frontend/rendering#use-a-shared-layout-for-a-shellguidanceDoes each shell sit in a shared layout?
litespec/frontend/rendering#keep-layouts-stableguidanceIs each provider required by every child route?
litespec/frontend/rendering#keep-server-only-code-identifiableguidanceDoes each server-owned module sit in a file named for the server?