Walkthrough: Rendering a JSS app server-side using the headless JSS proxy
JSS supports headless server-side rendering (SSR) using any service that supports hosting Node.js applications. The JSS app receives an incoming HTTP request that is rewritten and proxied into a Layout Service request to a Sitecore server. The reply from Layout Service is then provided to the app's SSR infrastructure to render to HTML. Finally, the resulting HTML is returned to the client.
Sitecore provides a sample application to simplify the setup process. The application uses the NPM package sitecore-jss-proxy
.
Node.js is a third-party technology that you must configure according to your specific use-case scenarios for Headless mode.
To use this technique, you must have:
-
A Sitecore instance with Headless Services installed.
-
A React, Vue.js, or Angular application built with JSS that supports server-side rendering in integrated mode.
This walkthrough describes how to:
-
Serve the JSS application with the headless JSS proxy.
-
Use middleware to work around potential KeepAlive errors.
-
Handle headers returned by the proxy app.
-
Exclude the server host from media URLs.
Serve the JSS application with the headless JSS proxy
Rendering React, Angular, or Vue.js applications server-side requires that you have a server implementation that can serve the production build output of your application. The node-headless-ssr-proxy
application sample contains a Node.js server implementation to support this scenario.
To server-side render a JSS React, Angular, or Vue.js app using the sample node-headless-ssr-proxy
:
-
In a terminal, run the following JSS command to create an application based on the
node-headless-ssr-proxy
sample providing a name for the application, such asjss-proxy-ssr
:RequestResponsenpx create-sitecore-jss node-headless-ssr-proxy --appName jss-proxy-ssr
-
In the JSS app that you want to SSR, in the
scjssconfig.json
file, set thelayoutServiceHost
option to the hostname of thejss-proxy-ssr
proxy not directly to Sitecore.ImportantThe
scjssconfig.json
file might not exist if you have never connected your JSS app to Sitecore.For local testing, the hostname defaults to
http://localhost:3000
. In production, it is the address where you deploy the proxy application, for example,https://www.mysite.com
.NoteIt is also possible to make requests directly to Sitecore if you do not want to run everything through the reverse proxy. However, proxying the data APIs has the advantage of allowing your Sitecore instance to live behind a firewall.
-
In a terminal, in the root directory of the JSS app you want to render server-side, build your JSS app for production by running the following script:
RequestResponsejss build
-
Copy the resulting directory, for example,
dist
orbuild
, to the root directory of the SSRjss-proxy-ssr
app, for example, in adist/<JSS app name>/
directory.Alternatively, in the JSS app, in the
scjssconfig.json
file, change theinstancePath
to the SSR sample root path. In the terminal, run thejss deploy files
command to deploy the build result to the proxy app. -
In the SSR
jss-proxy-ssr
app, inspect theconfig.js
file and modify it (or use environment variables) to specify values for the following properties:-
appName
- the value for your JSS application, as set in thepackage.json
file in theconfig.appName
configuration. -
bundlePath
- the path where you copied the directory resulting from the build processserver.bundle.js
. For example:'./dist/<JSS app name>/server.bundle'
. -
apiHost
- your Sitecore instance host name. You must use HTTPS in production. -
apiKey
- the Sitecore SSC API key. -
In the
createViewBag()
function, set the dictionary service path to the JSS app's dictionary service URL. The function enables dictionary caching. If you are not using dictionaries, you can remove the entirecreateViewBag()
function.
-
-
If proxying to a development Sitecore instance using a privately signed certificate, configure Sitecore CA certificates for Node.js.
Alternatively, in the SSR application
jss-proxy-ssr
, in theconfig.js
file, in theproxyOptions
object, you can disable SSL validation entirely by setting thesecure
tofalse
option. For example:RequestResponseproxyOptions: { // NEVER EVER do this in production. It will make your SSL completely insecure. secure: false }
-
In a terminal, in the root directory of the SSR
jss-proxy-ssr
app, run the following script to test the SSR application:RequestResponsenpm run start
Use middleware to work around potential KeepAlive errors
Because of an issue affecting node-http-proxy
, if you try to add a middleware with a Keep-Alive agent, you can get an error that causes the server to crash. The issue affects the usage of proxyOptions.onProxyReq
with Keep-Alive.
To work around this issue:
-
In the
src/index.ts
file, implement a custom middleware that modifies the request before proxying to contain the values you want to proxy, then call thenext()
function. For example:RequestResponseserver.use((req, res, next) => { // add custom logic for changing the request next(); });
Handle headers returned by the proxy app
You can explicitly control what headers the proxy app returns.
To modify the returned headers:
-
In the headless proxy application, in the
src/config.ts
file, modify the body of thesetHeaders
function to control the headers returned by the proxy application. For example, the default implementation of the function removes thecontent-security-policy
header:RequestResponsesetHeaders: (req, serverRes, proxyRes) => { delete proxyRes.headers['content-security-policy']; }
You can modify the body of the function to remove additional headers.
Exclude the server host from media URLs
For a Sitecore server at http://siteco.re
, for example, an image in a media field or rich text field has the source URL http://sitecor.re/-/media/jss.jpg
, because the Layout Service returns URLs to images with the Sitecore server URL included and exposes the Sitecore server publicly.
When proxying requests in headless mode, however, if the proxy host is http://custom-proxy.host
, the desired URL is http://custom-proxy.host/-/media/jss.jpg
or better yet /-/media/jss.jpg
.
To use the headless proxy without exposing the Sitecore server publicly, you can configure the Layout Service with a Sitecore configuration patch.
To instruct Sitecore not to include the server host as part of media requests:
-
In the JSS application you want to render server-side with the proxy application, create a configuration patch file, for example,
sitecore/config/Include/RemoveMediaURLs.config
, with the following content:RequestResponse<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"> <sitecore> <layoutService> <configurations> <config name="jss"> <rendering> <renderingContentsResolver> <IncludeServerUrlInMediaUrls>false</IncludeServerUrlInMediaUrls> </renderingContentsResolver> </rendering> </config> </configurations> </layoutService> </sitecore> </configuration>
ImportantThis configuration is appropriate for servers that run headless JSS apps. Enabling this configuration causes images to break when running JSS apps in connected mode because the images are served as if local. Do not use this configuration for servers used in active development.
-
Deploy the configuration to your Sitecore instance by running the JSS CLI command:
RequestResponsejss deploy config
Depending on how you created the application, this configuration might already be present. Verify the files contained in the following folders:
-
/src/platform/App_Config/Include
, for apps contained in a full-stack container-based solution. -
/sitecore/config
, for a standalone JSS app.