Multi-Environment Builds

Rsbuild supports building outputs for multiple environments at the same time. You can use environments to build multiple environments in parallel and set a different Rsbuild config for each environment.

Environment configs

Rsbuild supports defining different Rsbuild configs for each environment through environments.

For example, if your project wants to support the SSR function, you need to define different configs for client and SSR respectively. You can define a web and node environment respectively.

rsbuild.config.ts
export default {
  environments: {
    // Configure the web environment for browsers
    web: {
      source: {
        entry: {
          index: './src/index.client.js',
        },
        alias: {
          '@common': './src/client/common',
        },
      },
      output: {
        // Use 'web' target for the browser outputs
        target: 'web',
      },
    },
    // Configure the node environment for SSR
    node: {
      source: {
        entry: {
          index: './src/index.server.js',
        },
        alias: {
          '@common': './src/server/common',
        },
      },
      output: {
        // Use 'node' target for the Node.js outputs
        target: 'node',
      },
    },
  },
};

Config Merging

If you configure environments, Rsbuild will merge the config in environments with the outer base config. When merging, the config in environments has higher priority.

In the example above, after merging the configs, Rsbuild generates two standalone environment configs for building web and node environments.

  • web environments config: Generated by merging base config with environments.web
  • node environments config: Generated by merging base config with environments.node

Then, Rsbuild will use these environments configs to internally generate two Rspack configs and execute a single build using Rspack’s MultiCompiler.

Debug Config

When you execute the command npx rsbuild inspect in the project root directory, you will find the following output:

  • rsbuild.config.[name].mjs: Indicates the Rsbuild config used for a certain environment during build.
  • rspack.config.[name].mjs: Indicates the Rspack config corresponding to a certain environment when building.
➜ npx rsbuild inspect

Inspect config succeed, open following files to view the content:

  - Rsbuild Config (web): /project/dist/rsbuild.config.web.mjs
  - Rsbuild Config (node): /project/dist/rsbuild.config.node.mjs
  - Rspack Config (web): /project/dist/rspack.config.web.mjs
  - Rspack Config (node): /project/dist/rspack.config.node.mjs

Default environment

When environments is not specified, Rsbuild will by default create an environment with the same name based on the currently target type (the value of output.target).

rsbuild.config.ts
export default {
  output: {
    target: 'web',
  },
};

The above config is equivalent to a simplification of the following config:

rsbuild.config.ts
export default {
  environments: {
    web: {
      output: {
        target: 'web',
      },
    },
  },
};

Plugin API

Update environment config

Rsbuild supports modifying or adding environment config through the modifyRsbuildConfig hook.

const myPlugin = () => ({
  setup: (api) => {
    api.modifyRsbuildConfig((config, { mergeRsbuildConfig }) => {
      return mergeRsbuildConfig(config, {
        environments: {
          web1: {
            source: {
              entry: {
                index: './src/web1/index',
              },
            },
          },
        },
      });
    });
  },
});

Configuring a specific environment

Rsbuild supports modifying the Rsbuild config of a specific environment through the modifyEnvironmentConfig hook.

const myPlugin = () => ({
  setup: (api) => {
    api.modifyEnvironmentConfig((config, { name }) => {
      if (name !== 'web') {
        return config;
      }
      config.html ||= {};
      config.html.title = 'My Default Title';
    });
  },
});

Environment context

Environment context is a read-only object that provides some context infos about the current environment. Rsbuild supports obtaining environment context information in plugin hooks.

For some plugin hooks related to the build environment (such as modifyRspackConfig and modifyBundlerChain), Rsbuild supports obtaining the current environment context through the environment parameter.

const myPlugin = () => ({
  setup: (api) => {
    api.modifyRspackConfig((rspackConfig, { environment }) => {
      if (environment.name === 'node') {
        // do some thing
      }
    });
  },
});

For some global plugin hooks (such as onDevCompileDone, onBeforeStartDevServer, etc.), Rsbuild supports obtaining the context of all environments through the environments parameter.

const myPlugin = () => ({
  setup: (api) => {
    api.onDevCompileDone(({ environments }) => {
      environments.forEach((environment) => {
        console.log('environment', environment);
      });
    });
  },
});

Environment API

Rsbuild server provides a series of APIs related to the build environment. Users can operate the build artifacts in a specific environment on the server side through the Rsbuild environment API.

You can use the environment API in Rsbuild DevMiddleware or Custom Server.

For example, you can quickly implement an SSR function through the Rsbuild environment API in development mode:

import express from 'express';
import { createRsbuild, loadConfig } from '@rsbuild/core';

const serverRender = (serverAPI) => async (_req, res) => {
  const indexModule = await serverAPI.environments.ssr.loadBundle('index');

  const markup = indexModule.render();

  const template = await serverAPI.environments.web.getTransformedHtml('index');

  const html = template.replace('<!--app-content-->', markup);

  res.writeHead(200, {
    'Content-Type': 'text/html',
  });
  res.end(html);
};

export async function startDevServer() {
  const { content } = await loadConfig({});

  // Init Rsbuild
  const rsbuild = await createRsbuild({
    rsbuildConfig: content,
  });

  const app = express();

  // Create Rsbuild DevServer instance
  const rsbuildServer = await rsbuild.createDevServer();

  const serverRenderMiddleware = serverRender(rsbuildServer);

  app.get('/', async (req, res, next) => {
    try {
      await serverRenderMiddleware(req, res, next);
    } catch (err) {
      logger.error('SSR render error, downgrade to CSR...\n', err);
      next();
    }
  });

  // Apply Rsbuild’s built-in middlewares
  app.use(rsbuildServer.middlewares);

  // ...
}

For detailed usage, please refer to: SSR + Express Example.