Server Side Rendering (SSR)
Front-Commerce uses SSR to improve SEO and UX by serving HTML pages to users on their first hit to the server. This documentation explains everything you need to know about it when working on a typical Front-Commerce application.
Front-Commerce uses SSR (opposed to
CSR) to improve SEO and UX by serving HTML pages to users on their first hit to the server. You can read A typical request in Front-Commerce to get a better understanding of this process.
To generate this HTML page, Front-Commerce will render the React application as a string. Your React components will trigger Apollo queries that will “fetch” data from the GraphQL layer during this process. It may hit remote APIs and finally generate the HTML content of your page from the data.
While we try to make this process as smooth as possible for developers, so you don’t have to worry about the technical details, there are some things that you should be aware of while creating your theme.
This section details everything frontend developers must keep in mind when authoring components in a SSR context
There is no window
on the server!
Even though it may seem obvious, you are very likely to come across this problem at some point! Browser APIs are not available during
SSR. Keep it in mind when using them, and provide a graceful fallback.
Sometimes, it could be as simple as a default value or returning earlier from your function without any side effect.
Examples:
const doSomethingWithIntersectionObserver = () => {
if (typeof window === "undefined" || !window.IntersectionObserver) {
return;
}
// …
};
const initializePosition = (setPosition) => {
if (typeof navigator === "undefined" || !("geolocation" in navigator)) {
setPosition(DEFAULT_LATITUDE, DEFAULT_LONGITUDE);
} else {
navigator.geolocation.getCurrentPosition((position) => {
setPosition(position.coords.latitude, position.coords.longitude);
});
}
};
branchServerClient
to the rescue!
There may be situations were displaying a totally different component during the server rendering might be relevant.
For instance, instead of displaying a map centered on the user geolocation it might be better to render a placeholder (page skeleton) on the server and load the map with additional data during
CSR. Another use case would be to avoid an unnecessary overhead by not rendering some components during SSR: a social media feed may not make sense on the server.
Front-Commerce provides a branchServerClient
HOC that allow you to conditionally render a component or another one on server and client side.
Example:
import branchServerClient from "web/core/branchServerClient";
const MyClientSideComponent => props => <div>Hi!</div>;
export default branchServerClient(
() => () => null, // do not render anything during SSR
BaseComponent => BaseComponent // render the base component on the client
)(MyClientSideComponent);
Please keep in mind that by default the server version will always be displayed first. This means that if you are on a category page and navigate to a product page, it will first display the server version of the product page. When it's done loading, it will then display the client version. The goal here is to enable faster navigation and display only critical information on page mount.
If you want to change this behavior and display the client version of the
branch, you can use branchServerClient
's third parameter to pass the
{ preferClientSide: true }
option.
The function name (branchServerClient) is a good way to remember that the first parameter is what is rendered on the server, and the second on the client.
If you only need to know the rendering context, you can use Front-Commerce's
withIsServer
HOC to have an isServer
prop injected in your component.
Example:
import { withIsServer } from "web/core/branchServerClient";
const MyIsomorphicComponent => props => <div>
My latest render occured on the {props.isServer ? "server" : "client" }.
</div>;
export default withIsServer()(MyIsomorphicComponent);
In order to reduce the amount of Javascript sent to users, we've found that code
using branchServerClient()
are often good candidates to code splitting. You
may consider using a loadable()
component here. You can use
DEBUG="front-commerce:webpack"
to analyze your bundles and decide wether it would improve your application or
not.
A viewport as consistent as possible
Since version 2.0.0-rc.0
When using the <MediaQuery>
component (a thin wrapper around
react-responsive
's component,
available in "theme/components/helpers/MediaQuery"
), Front-Commerce has to
decide which viewport width to use during
SSR.
We decided to use User-Agent based detection in order to choose a width. Even though it might not be perfect (the best solution still is to use CSS media queries as much as possible over render-time media queries with the above component) we think it brings a good user experience.
This behavior is leveraging
Front-Commerce's configuration system
to provide information about the device. Each req.config
will contain a
device
key with the following information that you can use to if needed:
{
// User-Agent detection is memoized for each header value for this amount of time
memoizationMaxAge: ONE_MINUTE_IN_MS,
type: "phone", // ["phone", "tablet", "pc", "tv", "bot"]
viewportWidthInPx: 360
}
If you want to tweak this behavior, we invite you to browse the
deviceConfigProvider
for implementation details and contact us if you think of any improvements.
SSR Fallback when things go wrong
Since version 2.0.0-rc.0
During SSR you might face some errors (syntax errors, browser API usage, render errors, etc.). By default in dev mode, Front-Commerce provides an error page that makes the mistake obvious to allow you to fix it as early as possible.
Hopefully the previous screen will prevent such errors to occur in production,
but development is not an exact science and things can go wrong! In such
situations, the theme/pages/SsrFallback
component will be rendered instead of
the page. It displays a clean loading area, but you can override it to provide
another visual waiting page to users while the application is being rendered
client side.
If you still want to display the theme/pages/SsrFallback
page in dev mode,
add FRONT_COMMERCE_DEV_SSR_FALLBACK_DISABLE=true
to your environment variables.
Restrictions on pages that will be server-rendered
Since version 2.8
Front-Commerce avoids to unnecessary render a full 404 page server-side for URLs
that don't need it. When bots access random URLs (e.g: dump.sql.gz
,
password.txt
etc…) or outdated static assets, Front-Commerce will return a
simpler 404 error.
Pages are server-rendered when accessed with the following URL patterns:
- without extension (e.g:
/contact
,/faq/our-return-policy
…) - with an
.html
extension (e.g:/contact.html
,/wooden-table-with-chairs.html
…)
If your application contains pages whose URL have extensions other than
.html
, please contact us.
Learn more
If you want to learn more about SSR in Front-Commerce, we recommend you to understand how Server timings could help you to spot performance issues, read the Faster Server Side Rendering documentation page and to have a look at hydration and how to disable it in Front-Commerce.