Skip to main content

Server-Side Rendering (SSR)

Many React web platforms allow pages to be rendered on the server and sent to the browser as HTML, so that users don't have to wait for React's JavaScript render to complete in their browser before they can see a page. React then "hydrates" the page by running a client-side render (CSR) over this HTML to enable JavaScript-based interactivity.

Some React web platforms, including NextJS, enable SSR by default; however, a little configuration is needed to ensure styles are rendered correctly. Allium provides a function ssrStyles to help this.

Using ssrStyles

Allium uses two "CSS-in-JS" libraries (Styled Components and React Native Web), which generate style tags containing style rules for their rendered components. To ensure that the server-side render can generate the same styles as the client-side render, they must be wired in to the app's SSR process to observe which styles are needed.

DS Allium offers a utility to help with this - a utility function ssrStyles which provides functions to observe a render and generate the appropriate style tags.

Use with NextJS

In NextJS, ssrStyles should be applied in _document.js. This file does not exist by default so may need to be created - it should sit next to _app.js, usually in the pages/ directory.

Here is a complete example, tested in NextJS 12.0.10:

// In pages/_document.js
import Document from 'next/document'
import { ssrStyles } from '@telus-uds/ds-allium'

export default class MyDocument extends Document {
static async getInitialProps(context) {
// Initialise Allium's SSR style listener utilities
const { renderApp, getStyles } = ssrStyles()

const initialProps = await Document.getInitialProps({
...context,
renderPage: () =>
context.renderPage({
enhanceApp: (App) => (props) => {
// Render the app to a React element with style listeners active
return renderApp(App, props)
}
})
})

// Generate React <style> elements from data gained during the render
const styles = getStyles(initialProps.styles)

// Return Allium generated styles alongside default props and styles
return { ...initialProps, styles }
}
}

Other SSR platforms

The Allium ssrStyles utility should be compatible with any React SSR framework that is customisable enough to allow a custom render and insertion of style tags. Use the utility and its functions in the following order:

  1. Import ssrStyles into the file that manages SSR builds. Be sure that this file is only used during SSR.
import { ssrStyles } from '@telus-uds/ds-allium'
  1. At the start of the SSR process, call ssrStyles:
const { renderApp, getStyles } = ssrStyles()
  1. Where the SSR process renders the root component to a React element, call renderApp:
const element = renderApp(AppRoot, props)
  1. After the main content render, when the SSR process collates <style> tags into the page <head>, call getStyles, which returns an array of style tags as React elements.
const styles = getStyles()

API

ssrStyles

Initialises SSR style observers for an app render.

Parameters

  • appName: string (optional). If multiple 'apps' are rendered in one process, call ssrStyles for each one, with a unique app name string each call so the underlying utilities associate the right styles with the right app.

Returns an object containing two functions: { renderApp, getStyles }:

renderApp

Server-side renders an app, passing data on styles used to Allium's CSS-in-JS libraries.

Parameters

  • AppRoot: React component (required). The root component for the application being rendered. Depending on the framework this could be your App or Main component, or the framework's own wrapper around this root component with framework providers and utilities added (e.g. routing)
  • props: object (optional). The props this root component should be rendered with. For example, NextJS's SSR process may render multiple times passing different routing props to support chunking in the SSR build.

Returns a React element.

getStyles

Uses the data collected during renderApp to generate an array of style tags. Must be called after renderApp is complete.

Parameters

Any number of React elements containing style objects may be passed, which will be included in the returned array.

Returns an array of React elements rendering <style> tags.

Limitations

NextJS dev builds

NextJS enables SSR in development builds by default, but has a feature that hides the SSR builds until the JavaScript has hydrated. This feature is intended to avoid "flashes of unstyled content" during hot refreshes but as a side effect makes it much harder to see SSR during development.

NextJS SSR builds can be seen during development by either:

  • Disabling JavaScript in the browser then reloading the page
  • Generating a local production build

Mobile-first layout

A lot of logic around responsive layout and viewports in UDS and Allium works via JavaScript. SSR is not aware of the size of the user's screen, so in SSR any utilities that are based on the screen viewport will behave as if the viewport is xs.

For small mobile devices, which tend to be slower and most sensitive to layout shifts, if SSR is set up correctly the page should load extremely quickly and correctly first time.

However, for larger viewports, there may be one noticeable shift early in the "hydration" process, as the page becomes aware that the user's screen is wider than the xs default.