React4XP - Configuration - Build time



Several aspects of React4xp can be configured with a file react4xp.config.js.

If you’re using the starter or your project is based on it, this is already set up and you can skip the following section:

Including react4xp.config.js in your project

Put react4xp.config.js at the root of your XP project. A template can be copied from here, or from node_modules/@enonic/react4xp/examples/react4xp.config.js after installing the React4xp NPM package.

In order to take effect, it must be handled by gradle during the build:

  • Add this to your build.gradle:

    task react4xp(type: NpmTask, dependsOn: npmInstall) {
      args = [
        'build:react4xp' // This script must exist in the package.json file
      description 'Compile react4xp resources'
      environment = [
        'R4X_APP_NAME': "${appName}",
        'R4X_BUILD_LOG_LEVEL': gradle.startParameter.logLevel.toString(),
        'R4X_DIR_PATH_ABSOLUTE_PROJECT': project.projectDir.toString(),
        'NODE_ENV': project.hasProperty('dev') || project.hasProperty('development') ? 'development' : 'production'
      group 'react4xp'
      // It also watches package.json and package-lock.json :)
      inputs.dir 'node_modules/@enonic/react4xp'
      inputs.dir 'src/main/resources'
      outputs.dir 'build/resources/main'
    jar.dependsOn 'react4xp'

    This will not only make sure react4xp.config.js is handled, but also give a full react4xp build setup.

  • Add this to your package.json:

      "scripts": {
        "build:react4xp": "npm explore @enonic/react4xp -- npm run build:react4xp",


entryDirs: ['myComponents', '../otherComponents']

By default, React4xp will look for (ie. sets up webpack to look for) .TSX/.JSX files to turn into entries below src/main/resources/site/.

Adding comma separated values under entryDirs adds more folder names/paths (relative to src/main/resources/react4xp/) where TSX/JSX files will also become entries.


By default, React4xp will look for (ie. sets up webpack to look for) resources imported by the entries. These are bundled into separate assets that React4xp automatically loads at both server- and clientside rendering: chunks, by this pattern:

  • If they are react and reactDOM, they are bundled separately into globals.*.js (where the * is a content-dependent hash).

  • node_modules/@enonic/react-components/ is bundled into templates.*.js

  • Other packages under node_modules are bundled into vendors.*.js

  • And everything else that’s not under a chunkDir marked here is bundled into react4xp.*.js

(Of course, non-JS bundles split out by webpack will have different extensions, such as .css)

The idea is to use chunkDirs to add a comma-separated list of names/paths of directories (relative to src/main/resources/react4xp/) that will be bundled into chunks of their own. The chunk name will be the name of the last directory in the path:

chunkDirs: ['chunk1', 'bundle2', 'other/stuff']

This example adds these folders as chunkDirs, and anything the entries import from below them is bundled separately into:

  • src/main/resources/react4xp/chunk1/chunk1.*.js

  • src/main/resources/react4xp/bundle2/bundle2.*.js

  • src/main/resources/react4xp/other/stuff/stuff.*.js


React4xp comes with a minimal set of webpack rules built-in, for compiling react components in TSX/JSX files into vanilla JS.

If you need to change/expand this setup, write a custom webpack config file <Project.Dir>/webpack.config.react4xp.js

There can be several reasons to this:

  • Most commonly, the built-in webpack setup is pretty minimal, only adding loaders for compiling react from TSX/JSX. It’s likely you will need to add loaders of your own, maybe use additional plugins etc

  • You may want to adjust other aspects of the compilation rules, or even replace the built-in rules entirely

  • The assets that are built during the compilation are the same ones that are run on the server and in the browser. It’s possible you may need adjustments here to account for corner cases - if the problem is missing feature support in the server, perhaps you can polyfill them.

Config file shape: syntax variation!

Usually, webpack.config.js files tend to have a certain shape, something like:

module.exports = function(env) {
    var config = {
        entry: (...)
        output: (...)
        resolve: (...)
        module: {
            rules: (...)

    return config;
// ...etc, etc

webpack.config.react4xp.js can follow the same shape, but the exported function can also take a second config argument:

module.exports = function(env, config) {
    // ...

The extra incoming config object contains the built-in rules from React4xp. This enables you to both manipulate those rules and/or add your own, or entirely replace them by returning a different object.

Webpack caching

It is possible to decrease build time by using Webpack filesystem caching. The first build after clean, may be slower, but the subsequent (incremental) builds (without clean) should be faster.

module.exports = function(env, config) {
		if (process.env.NODE_ENV === 'development') {
		config.cache = {
			type: 'filesystem'
  return config;

Command line arguments

Build environment

Use the gradle commandline flag -Pdev or -Pdevelopment to enable building in development mode.

enonic project gradle build deploy -Pdev

This switches between React4xp build modes (not to be confused with XP’s run modes).

  • production: assets are compiled more compact (and faster), with source maps

  • development: assets are compiled for more human-readability, without minification, making errors easier to track down.

Default value is production.


Use the gradle commandline flag -i or --info to enable a more verbose output when compiling React4xp components and globals.