Disclaimer: This website requires Please enable JavaScript in your browser settings for the best experience.

Dev GuideAPI Reference
Dev GuideAPI ReferenceUser GuideGitHubDev CommunityOptimizely AcademySubmit a ticketLog In
Dev Guide

Server-side rendering (SSR) guidelines for Spire

Describes server-side rendering (SSR) guidelines for Spire in Optimizely Configured Commerce.

Only pages accessed by SEO crawlers are required for server-side rendering (SSR) in Optimizely Configured Commerce Spire CMS. These are:

  • Product detail pages
  • Brand and brand detail pages
  • Content pages
  • Product and category list pages

Other pages with fast APIs and hidden behind logins are nice to have, including the following:

  • My Account and its children
  • Cart and Checkout
  • Lists

Authenticated content that depends on slow API calls should not use SSR, or all users see a blank until all APIs respond.

React functionality

As of React 16.13.1, most React functionality works for SSR, except for useEffectuseLayoutEffect. The components otherwise work, but the hooks do not run until client-side hydration. If the logic behind those hooks is required for SEO, you must instead implement the component as a class component and move API-calling
logic into UNSAFE_componentWillMount. You can split a component into separate classes and functional components if you want to use the functional approaches for part of it.

Spire supports SSR in react components that use UNSAFE_componentWillMount to load data. It has a render loop that rerenders the site while persisting the redux store between renders. It continues the loop until no new promises are created during a render. If it renders 10 times, or until it has rendered 10 times, then it either logs a warning or throws an exception.

The content of the warning or exception look something like this:

During SSR of /MyCustomPage there was a new promise added on loop 10.
This usually indicates a problem with react state management that will affect performance.
The new promise was added at the following location:

It logs a warning in production as long as the environment variable FAIL_ON_PROMISE_LOOPS is not true. When not in production, it throws an exception unless the environment variable BYPASS_FAIL_ON_PROMISE_LOOPS is true.

The following is an example of code that causes a promise loop:

UNSAFE_componentWillMount(): void {
    // this dispatches a redux action that loads data from an API
    loadCategories();
}

Fixing the promise loop requires checking if data is currently loading, or was already loaded.

UNSAFE_componentWillMount(): void {
    const { categoriesDataView, loadCategories } = this.props;
    if (!categoriesDataView.isLoading && !categoriesDataView.value) {
        // this will now only dispatch an action on the first render in the loop
        loadCategories();
    }
}

Verify SSR functionality by refreshing the page. The initial HTML returned by the server should have the desired content, and the client-side JavaScript should not alter that content. Test links and other functionality with JavaScript disabled to ensure that SEO crawlers can navigate.

📘

Note

It is expected that React 17 will offer an alternative to UNSAFE_componentWillMount that enables functional components to be used in all scenarios.

Enable Server-Side Rendering for All User Agents setting

Configured Commerce received a new setting in release 5.2.2411, Enable Server-Side Rendering for All User Agents. This setting lets website administrators determine if SSR should be applied to all users, or only users whose User-Agent headers match that of a known web crawler.

SSR context

In Classic, administrators had to manage content for two types of visitors: human users and website crawlers. Spire eliminates the need to manage two different content versions because SSR loads the content in a way that website crawlers can consume.

While Optimizely designed Spire to user SSR for every end user, some customers found that real-time integrations with third party systems can lead to long page load times. To resolve this issue, the Configured Commerce engineering team used SSR based on the User Agent header of the initial request. If the User Agent was a web crawler, Spire used SSR.

This approach worked until Google started measuring websites using Core Web Vitals. Optimizely wanted to score well on these metrics because Google makes indexing decisions based on them. To do this, the engineering team lets you use Spire's original SSR design with new seetings in 5.2.2411.

One setting lets you opt in to using SSR for all requests, not just web crawlers. To handle limitations of real-time integrations, Configured Commerce has three sub-settings that determine if catalog data, pricing, or inventory data is loaded on the server.

Technical considerations

Spire supports selectively loading catalog, pricing, and inventory data during SSR with the application state in Redux. When an initial page request is being rendered server-side, the following logic is applied individually for catalog, pricing, and inventory:

During SSR

  1. Check the appropriate setting during the handler that loads the data.
  2. Add a value to the redux state if the setting is false indicating that some data must be loaded once the page is hydrated on the client. The page is rendered as though the data is still loading.
  3. Return the hydrated page.

During client-side hydration

  1. Check the Redux state for any data that has been deferred from loading on the server.
  2. Run the respective handler to load the data if needed.

Examples of this can be found in base code. The UNSAFE_componentWillMount method of the ProductDetailsPage and the DeferCallIfNecessary step of the DisplayProduct handler show how catalog data can be delayed from loading on the server to loading once the client is being hydrated.

If you enable the Enable Server-Side Rendering for All Users setting for the first time, double-check any customizations that use class components and the UNSAFE_componentWillMount function. The implementation partner must ensure that these customizations load data as expected when running during server-side rendering.

This behavior would have already been in place for any web crawlers visiting the site. However, it should be ensured that there are no adverse behaviors that could impact a human visitor’s experience.