多环境构建

Rsbuild 支持同时为多个环境构建产物。你可以使用 environments 来并行构建多个环境,并为每个环境设置不同的 Rsbuild 配置。

什么是 environment

environment 指的是构建产物的运行环境,常见的运行环境有浏览器、Node.js 和 Workers。Rsbuild 允许你定义任意的 environment 名称,并为这些 environment 分别设置构建选项。

一个典型的场景是服务器端渲染(SSR),你可以定义 webnode 两个 environments,它们的构建目标(output.target)分别是 webnode,并用于客户端渲染(CSR)和服务器端渲染(SSR)场景。

此外,你还可以为同一个构建目标定义不同的 environment,例如:

  • 定义 rscssr 两个环境,它们的构建目标都是 node,分别用于 React Server Components 和 SSR。
  • 定义 desktopmobile 两个环境,它们的构建目标都是 web,分别用于桌面端浏览器和移动端浏览器。

如果没有 environments 配置,你需要为这些场景定义多份配置,并执行多次独立的 Rsbuild 构建。现在通过 environments 配置,你可以在一次 Rsbuild 构建中完成多种产物的构建(Rsbuild 基于 Rspack 的 MultiCompiler 来实现这一点)。

Rsbuild 中的每个 environment 关联一份 Rsbuild 配置、一份 Rspack 配置和一份构建产物。Rsbuild 插件的开发者可以基于 environment 名称,对指定环境的构建流程进行定制,如修改 Rsbuild 或 Rspack 配置、注册或移除插件、调整 Rspack 规则和查看静态资源信息等。

多环境配置

Rsbuild 支持通过 environments 为每个环境定义不同的 Rsbuild 配置。

例如,假如你的项目希望支持 SSR 功能,你需要分别为 client 和 SSR 定义不同的配置,你可以分别定义一个 web 和 node 的 environment。

rsbuild.config.ts

  1. export default {
  2. environments: {
  3. // 配置 web 环境,用于浏览器端
  4. web: {
  5. source: {
  6. entry: {
  7. index: './src/index.client.js',
  8. },
  9. alias: {
  10. '@common': './src/client/common',
  11. },
  12. },
  13. output: {
  14. // 浏览器产物的 target 类型为 'web'
  15. target: 'web',
  16. },
  17. },
  18. // 配置 node 环境,用于 SSR
  19. node: {
  20. source: {
  21. entry: {
  22. index: './src/index.server.js',
  23. },
  24. alias: {
  25. '@common': './src/server/common',
  26. },
  27. },
  28. output: {
  29. // Node.js 产物的 target 类型为 'node'
  30. target: 'node',
  31. },
  32. },
  33. },
  34. };

配置合并

当你配置 environments 时,Rsbuild 会将 environments 里的配置与外层的基础配置进行合并。合并时,environments 中的配置具有更高的优先级。

在上述例子中,在合并配置后,Rsbuild 会生成两份独立的 environments 配置,分别用于构建 web 和 node 环境的产物。

  • web environments config:由 base config 和 environments.web 合并生成
  • node environments config:由 base config 和 environments.node 合并生成

接着,Rsbuild 会基于这些 environments 配置,在内部生成两份 Rspack 配置,并通过 Rspack 的 MultiCompiler 来执行单次构建。

配置调试

当你在项目根目录下执行命令 npx rsbuild inspect 后,会发现有如下输出:

  • rsbuild.config.[name].mjs: 表示在构建时某个 environment 对应使用的 Rsbuild 配置。
  • rspack.config.[name].mjs: 表示在构建时某个 environment 对应使用的 Rspack 配置。
  1. npx rsbuild inspect
  2. Inspect config succeed, open following files to view the content:
  3. - Rsbuild Config (web): /project/dist/.rsbuild/rsbuild.config.web.mjs
  4. - Rsbuild Config (node): /project/dist/.rsbuild/rsbuild.config.node.mjs
  5. - Rspack Config (web): /project/dist/.rsbuild/rspack.config.web.mjs
  6. - Rspack Config (node): /project/dist/.rsbuild/rspack.config.node.mjs

默认 environment

当 environments 未指定时,Rsbuild 默认会根据当前的产物类型 (output.target 的值) 创建一个同名的环境。

rsbuild.config.ts

  1. export default {
  2. output: {
  3. target: 'web',
  4. },
  5. };

以上配置相当于下面配置的语法糖:

rsbuild.config.ts

  1. export default {
  2. environments: {
  3. web: {
  4. output: {
  5. target: 'web',
  6. },
  7. },
  8. },
  9. };

仅构建指定环境

默认情况下,当你执行 rsbuild devrsbuild build 时,Rsbuild 会构建所有 Rsbuild 配置中的环境。你可以通过 --environment <name> 仅构建指定环境。

  1. # 构建所有环境
  2. rsbuild dev
  3. # 仅构建 web 环境
  4. rsbuild dev --environment web
  5. # 构建 web 和 ssr 环境
  6. rsbuild dev --environment web --environment node
  7. # 构建多个环境可以简写为:
  8. rsbuild dev --environment web,node

为指定环境添加插件

通过 plugins 字段配置的插件支持在所有环境下运行,如果你希望某个插件仅在指定环境下运行时,将该插件配置在特定 environment 下即可。

例如,仅在 web 环境下开启 React 插件:

rsbuild.config.ts

  1. import { pluginReact } from '@rsbuild/plugin-react';
  2. export default {
  3. environments: {
  4. web: {
  5. output: {
  6. target: 'web',
  7. },
  8. plugins: [pluginReact()],
  9. },
  10. node: {
  11. output: {
  12. target: 'node',
  13. },
  14. },
  15. },
  16. };

如果你是插件开发者,可查看 开发 Environment 插件 了解详情。

插件 API

更新配置

Rsbuild 支持通过 modifyRsbuildConfig 钩子新增或修改 environment 配置。

  1. const myPlugin = () => ({
  2. setup: (api) => {
  3. api.modifyRsbuildConfig((config, { mergeRsbuildConfig }) => {
  4. return mergeRsbuildConfig(config, {
  5. environments: {
  6. web1: {
  7. source: {
  8. entry: {
  9. index: './src/web1/index',
  10. },
  11. },
  12. },
  13. },
  14. });
  15. });
  16. },
  17. });

配置特定 environment

Rsbuild 支持通过 modifyEnvironmentConfig 钩子修改特定 environment 的 Rsbuild 配置。

  1. const myPlugin = () => ({
  2. setup: (api) => {
  3. api.modifyEnvironmentConfig((config, { name }) => {
  4. if (name !== 'web') {
  5. return config;
  6. }
  7. config.html.title = 'My Default Title';
  8. });
  9. },
  10. });

Environment 上下文

Environment context 是一个只读对象,提供一些和当前环境有关的上下文信息。Rsbuild 支持在 plugin hook 中获取 environment context 信息。

对于一些与构建环境相关的 plugin hooks(如 modifyRspackConfigmodifyBundlerChain 等), Rsbuild 支持通过 environment 参数获取当前 environment 上下文。

  1. const myPlugin = () => ({
  2. setup: (api) => {
  3. api.modifyRspackConfig((rspackConfig, { environment }) => {
  4. if (environment.name === 'node') {
  5. // do some thing
  6. }
  7. });
  8. },
  9. });

对于一些全局的 plugin hooks(如 onDevCompileDoneonBeforeStartDevServer 等), Rsbuild 支持通过 environments 参数获取所有环境的上下文。

  1. const myPlugin = () => ({
  2. setup: (api) => {
  3. api.onDevCompileDone(({ environments }) => {
  4. environments.forEach((environment) => {
  5. console.log('environment', environment);
  6. });
  7. });
  8. },
  9. });

Environment API

Rsbuild Server 提供了一系列和构建环境相关的 API,用户可通过 Rsbuild environment API 在服务器端操作特定环境下的构建产物。

你可以在 Rsbuild DevMiddleware自定义 Server 中使用 environment API。

例如,你可以通过 Rsbuild environment API 在开发模式下快速实现一个 SSR 功能:

  1. import express from 'express';
  2. import { createRsbuild, loadConfig } from '@rsbuild/core';
  3. const serverRender = (serverAPI) => async (_req, res) => {
  4. const indexModule = await serverAPI.environments.ssr.loadBundle('index');
  5. const markup = indexModule.render();
  6. const template = await serverAPI.environments.web.getTransformedHtml('index');
  7. const html = template.replace('<!--app-content-->', markup);
  8. res.writeHead(200, {
  9. 'Content-Type': 'text/html',
  10. });
  11. res.end(html);
  12. };
  13. export async function startDevServer() {
  14. const { content } = await loadConfig({});
  15. // Init Rsbuild
  16. const rsbuild = await createRsbuild({
  17. rsbuildConfig: content,
  18. });
  19. const app = express();
  20. // Create Rsbuild DevServer instance
  21. const rsbuildServer = await rsbuild.createDevServer();
  22. const serverRenderMiddleware = serverRender(rsbuildServer);
  23. app.get('/', async (req, res, next) => {
  24. try {
  25. await serverRenderMiddleware(req, res, next);
  26. } catch (err) {
  27. logger.error('SSR render error, downgrade to CSR...\n', err);
  28. next();
  29. }
  30. });
  31. // Apply Rsbuild’s built-in middlewares
  32. app.use(rsbuildServer.middlewares);
  33. // ...
  34. }

详细使用情况可参考:SSR + Express 示例

添加 environment 依赖

默认情况下,Rsbuild 会并行构建所有环境。如果你的项目中某一个环境依赖其他环境预先编译完成,可以将你需要依赖的环境名称添加到 Rspack 的 dependencies 配置中。

例如,node 环境依赖 web 环境预先编译完成,可以添加如下配置:

rsbuild.config.ts

  1. export default {
  2. environments: {
  3. web: {},
  4. node: {
  5. tools: {
  6. rspack: {
  7. dependencies: ['web'],
  8. },
  9. },
  10. },
  11. },
  12. };