Configuring and debugging the Node.js rendering engine

Abstract

Overview of configuration methods and options for integrated SSR of JSS apps

When running in integrated mode, Sitecore JSS applications are server-side rendered (SSR) using a Node.js instance before being provided to the client.

You can configure the Node.js instance used for SSR with the help of Sitecore configuration files.

Configuration options include enabling Node.js debugging, allowing you to use any debugger that can attach to a Node.js instance.

Default configuration

The default Node.js configuration is used for all Node.js instances that do not have an instance-specific configuration defined. The default configuration can also be inherited and overridden by instance-specific configurations. In most cases, especially if you have multiple JSS apps running in the same Sitecore instance, we do not generally recommended to modify the options in the default configuration. Instead, you can create an instance-specific configuration that inherits the defaults and modify options in the instance-specific configuration.

You can find the default Node.js configuration in your Sitecore instance in the file App_Config/Sitecore/JavaScriptServices/Sitecore.JavaScriptServices.ViewEngine.Node.config. The file contains configuration options for the Node.js rendering engine. For example:

<javaScriptServices>
  <renderEngines>
    <renderEngine name="nodejs">
      <instance id="defaults">
        <!--
          If true, the Node.js instance will accept incoming V8 debugger connections (e.g., from node-inspector).
          The node process is invoked with the "inspect" flag.
        -->
        <LaunchWithDebugging>false</LaunchWithDebugging>
        <!--
          If "launchWithDebugging" is true, the Node.js instance will listen for V8 debugger connections on this port.
          IMPORTANT: Node instances _must_ have unique debugging ports. If you try to create multiple node instances with the same debugger port, those node processes will exit.
          Therefore, it is recommended that you create <instance /> configurations for individual JSS apps / renderings if you wish to use remote SSR debugging features.
        -->
        <DebuggingPort></DebuggingPort>
        <!-- If set, the Node.js instance should restart when any matching file on disk within your project changes. -->
        <WatchFileExtensions>.js|.json|.html</WatchFileExtensions>
        <!--
          If set, starts the Node.js instance with the specified environment variables.
        -->
        <EnvironmentVariables>
          <var name="NODE_ENV" value="production" />
        </EnvironmentVariables>
        <!-- Specifies the maximum duration, in milliseconds, that your .NET code should wait for Node.js RPC calls to return. -->
        <InvocationTimeoutMs>60000</InvocationTimeoutMs>
      </instance>
    </renderEngine>
  </renderEngines>
</javaScriptServices>

Node.js instance configuration

Instance-specific Node.js configurations allow you to inherit default configuration options and modify them for specific JSS apps or JavaScript renderings.

For instance-specific Node.js configurations, you assign an id attribute to the <instance /> element and an optional inherits attribute that refers to the name of an <instance /> node to inherit options from.

JSS app instances

For JSS apps, the id attribute is the name of the JSS app the Node.js instance is associated with - each JSS app has its own Node.js instance. The name of a JSS app is defined in the Sitecore config file for the app, usually in the sitecore/config/<app-name>.config file. For instance, the sample React app, named JssReactWeb is registered as follows:

<javaScriptServices>
  <apps>
    <!-- note: other app attributes omitted for brevity -->
    <app name="JssReactWeb" inherits="defaults" />
  </apps>
</javaScriptServices>

Therefore, an instance-specific Node.js configuration might look like the following. All configuration options defined within the <instance /> element are then specific to the JssReactWeb app.

<javaScriptServices>
  <renderEngines>
    <renderEngine name="nodejs">
      <instance id="JssReactWeb" inherits="defaults">
        <LaunchWithDebugging>true</LaunchWithDebugging>
        <DebuggingPort>9229</DebuggingPort>
        <WatchFileExtensions inherits="true">
          <ext>.vbs</ext>
        </WatchFileExtensions>
        <EnvironmentVariables inherits="true">
          <var name="MY_VAR" value="some value" />
        </EnvironmentVariables>
      </instance>
    </renderEngine>
  </renderEngines>
</javaScriptServices>

JavaScript rendering instances

When using Node.js to render individual JavaScript renderings, the id attribute assigned to an <instance /> element is the value specified within the rendering Server Script Path field, for example, /dist/myComponents/components.bundle.js. This means that, on the Sitecore server, there is at least one Node.js instance per script path.

<instance id="/dist/myComponents/components.bundle.js" inherits="defaults">
  <LaunchWithDebugging>true</LaunchWithDebugging>
  <DebuggingPort>9230</DebuggingPort>
  <WatchFileExtensions inherits="true">
    <ext>.vbs</ext>
  </WatchFileExtensions>
  <EnvironmentVariables inherits="true">
    <var name="MY_VAR" value="some value" />
  </EnvironmentVariables>
</instance>

Important

It is easy to imagine a scenario where there are multiple JavaScript renderings for each route/item, each using a separate Node.js instance. Therefore, we strongly recommend that your individual JavaScript renderings are bundled into as few files as possible to prevent the creation of an overwhelming number of node instances.

Configuration inheritance

Assigning an inherits attribute to the <instance /> element results in the instance-specific configuration inheriting configuration option values from the inherited configuration.

For the WatchFileExtensions and EnvironmentVariables configuration options, you can also specify an inherits attribute on the option definition itself to determine how that option inherits values.

Setting the inherits attribute to true on the WatchFileExtensions or EnvironmentVariables elements merges the instance-specific options with any inherited options.

For example, imagine you have the following base configuration:

<instance id="base">
  <WatchFileExtensions>
    <ext>.js|.json</ext>
  </WatchFileExtensions>
  <EnvironmentVariables>
    <var name="NODE_ENV" value="production" />
  </EnvironmentVariables>
</instance>

You add a configuration that inherits the base configuration. For example:

<instance id="my-jss-app" inherits="base">
  <WatchFileExtensions inherits="true">
    <ext>.html</ext>
  </WatchFileExtensions>
  <EnvironmentVariables>
    <var name="MY_VAR" value="some value" />
  </EnvironmentVariables>
</instance>

This configuration results in the following values for the my-jss-app configuration:

  • For WatchFileExtensions, .js|.json|.html.

  • For EnvironmentVariables :

    <var name="NODE_ENV" value="production" />
    <var name="MY_VAR" value="some value" />

Considering the same base configuration, setting the inherits attribute to false on the WatchFileExtensions or EnvironmentVariables elements means the instance-specific options are the only option values used. For example:

<instance id="my-jss-app" inherits="base">
  <WatchFileExtensions inherits="false">
    <ext>.html</ext>
  </WatchFileExtensions>
  <EnvironmentVariables>
    <var name="MY_VAR" value="some value" />
  </EnvironmentVariables>
</instance>

This configuration results in the following configuration:

  • Because for WatchFileExtensions the attribute inherits is false, the server only watches for .html file changes.

  • Because for EnvironmentVariables the attribute inherits is true:

    <var name="NODE_ENV" value="production" />
    <var name="MY_VAR" value="some value" />
    

If any of the variable names/keys collide, the server uses the instance-specific value.

For example, if the configuration my-jss-app sets the NODE_ENV variable value to development, having the same variable defined as production in the base configuration, the resulting value for the variable is:

<var name="NODE_ENV" value="development" />

Debugging

By default, Node.js debugging is disabled. To enable debugging, you must configure the Node.js instance configuration options.

Node.js instances started by Sitecore JSS use the --inspect switch when debugging is enabled.

When Node.js debugging is enabled for an instance, you can attach a debugger client.

Note

Refer to the Node.js Debugging Guide for more information on Node.js debugging.

If you use VS Code as your code editor, it has built-in support for attaching a debugger to a Node.js instance.

To configure the Node.js debugging process, you can use the following configuration options:

Option name

Default value

Description

LaunchWithDebugging

false

If true, the Node.js instance accepts incoming V8 debugger connections, for example, from node-inspector. The node process is invoked with the inspect flag.

DebuggingPort

null

If LaunchWithDebugging is true, the Node.js instance listens for V8 debugger connections on this port.

Important

Node instances must have unique debugging ports. If you try to create multiple node instances with the same debugger port, those node processes exit.

WatchFileExtensions

.js, .json, .html

If set, the Node.js instance restarts when any matching file within your project changes on the disk.

Note

This does not recycle the IIS process nor does it reload your app in a browser. Instead, the Node.js instance used for SSR is restarted, clearing any caches or removing resource locks held by the Node.js process.

EnvironmentVariables

<var name="NODE_ENV" value="production" />

Environment variables that are passed to the Node.js instance on startup.

InvocationTimeoutMs

60000

Specifies the maximum duration, in milliseconds, that your .NET code must wait for Node.js RPC calls to return.