Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions e2e/cases/cli/config-loader/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { execSync } from 'node:child_process';
import path from 'node:path';
import { globContentJSON, rspackOnlyTest } from '@e2e/helper';
import { expect, test } from '@playwright/test';

rspackOnlyTest('should use Node.js native loader to load config', async () => {
// TODO: fix this test on Windows
if (process.platform === 'win32') {
test.skip();
}

execSync('npx rsbuild build --config-loader native', {
cwd: __dirname,
env: {
...process.env,
NODE_OPTIONS: '--experimental-strip-types',
},
});

const outputs = await globContentJSON(path.join(__dirname, 'dist-custom'));
const outputFiles = Object.keys(outputs);

expect(outputFiles.length > 1).toBeTruthy();
});
9 changes: 9 additions & 0 deletions e2e/cases/cli/config-loader/rsbuild.config.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import type { RsbuildConfig } from '@rsbuild/core';

export default {
output: {
distPath: {
root: 'dist-custom',
},
},
} satisfies RsbuildConfig;
1 change: 1 addition & 0 deletions e2e/cases/cli/config-loader/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
console.log('hello!');
9 changes: 9 additions & 0 deletions packages/core/src/cli/commands.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import cac, { type CAC, type Command } from 'cac';
import type { ConfigLoader } from '../config';
import { logger } from '../logger';
import { onBeforeRestartServer } from '../server/restart';
import type { RsbuildMode } from '../types';
Expand All @@ -8,6 +9,7 @@ export type CommonOptions = {
root?: string;
mode?: RsbuildMode;
config?: string;
configLoader?: ConfigLoader;
envDir?: string;
envMode?: string;
open?: boolean | string;
Expand Down Expand Up @@ -36,6 +38,13 @@ const applyCommonOptions = (cli: CAC) => {
'-c, --config <config>',
'specify the configuration file, can be a relative or absolute path',
)
.option(
'--config-loader <loader>',
'specify the loader to load the config file, can be `jiti` or `native`',
{
default: 'jiti',
},
)
.option(
'-r, --root <root>',
'specify the project root directory, can be an absolute path or a path relative to cwd',
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/cli/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export async function init({
cwd: root,
path: commonOpts.config,
envMode: commonOpts.envMode,
loader: commonOpts.configLoader,
});

const command = process.argv[2];
Expand Down
18 changes: 17 additions & 1 deletion packages/core/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,13 @@ export type LoadConfigOptions = {
* @default process.env.NODE_ENV
*/
envMode?: string;
/**
* Specify the config loader, can be `jiti` or `native`.
* - 'jiti': Use `jiti` as loader, which supports TypeScript and ESM out of the box
* - 'native': Use native Node.js loader, requires TypeScript support in Node.js >= 22.6
* @default 'jiti'
*/
loader?: ConfigLoader;
};

export type LoadConfigResult = {
Expand All @@ -439,11 +446,14 @@ export type LoadConfigResult = {
filePath: string | null;
};

export type ConfigLoader = 'jiti' | 'native';

export async function loadConfig({
cwd = process.cwd(),
path,
envMode,
meta,
loader = 'jiti',
}: LoadConfigOptions = {}): Promise<LoadConfigResult> {
const configFilePath = resolveConfigPath(cwd, path);

Expand All @@ -461,11 +471,17 @@ export async function loadConfig({

let configExport: RsbuildConfigExport;

if (/\.(?:js|mjs|cjs)$/.test(configFilePath)) {
if (/\.(?:js|mjs|cjs)$/.test(configFilePath) || loader === 'native') {
try {
const exportModule = await import(`${configFilePath}?t=${Date.now()}`);
configExport = exportModule.default ? exportModule.default : exportModule;
} catch (err) {
if (loader === 'native') {
logger.error(
`Failed to load file with native loader: ${color.dim(configFilePath)}`,
);
throw err;
}
logger.debug(
`Failed to load file with dynamic import: ${color.dim(configFilePath)}`,
);
Expand Down
1 change: 1 addition & 0 deletions website/docs/en/api/javascript-api/core.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ function loadConfig(params?: {
path?: string;
meta?: Record<string, unknown>;
envMode?: string;
loader?: 'jiti' | 'native';
}): Promise<{
content: RsbuildConfig;
filePath: string | null;
Expand Down
19 changes: 10 additions & 9 deletions website/docs/en/guide/basic/cli.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,16 @@ Commands:

Rsbuild CLI provides several common flags that can be used with all commands:

| Flag | Description |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| `-c, --config <config>` | Specify the configuration file, can be a relative or absolute path, see [Specify config file](/guide/basic/configure-rsbuild#specify-config-file) |
| `-r, --root <root>` | Specify the project root directory |
| `-m, --mode <mode>` | Specify the build mode (`development`, `production` or `none`), see [mode](/config/mode) |
| `--env-mode <mode>` | Specify the env mode to load the `.env.[mode]` file, see [Env mode](/guide/advanced/env-vars#env-mode) |
| `--env-dir <dir>` | Specify the directory to load `.env` files, see [Env directory](/guide/advanced/env-vars#env-directory) |
| `--environment <name>` | Specify the name of environment to build, see [Build specified environment](/guide/advanced/environments#build-specified-environment) |
| `-h, --help` | Display help for command |
| Flag | Description |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| `-c, --config <config>` | Specify the configuration file, can be a relative or absolute path, see [Specify config file](/guide/basic/configure-rsbuild#specify-config-file) |
| `--config-loader <loader>` | Specify the config loader, can be `jiti` or `native`, see [Specify config loader](/guide/basic/configure-rsbuild#specify-config-loader) |
| `-r, --root <root>` | Specify the project root directory |
| `-m, --mode <mode>` | Specify the build mode (`development`, `production` or `none`), see [mode](/config/mode) |
| `--env-mode <mode>` | Specify the env mode to load the `.env.[mode]` file, see [Env mode](/guide/advanced/env-vars#env-mode) |
| `--env-dir <dir>` | Specify the directory to load `.env` files, see [Env directory](/guide/advanced/env-vars#env-directory) |
| `--environment <name>` | Specify the name of environment to build, see [Build specified environment](/guide/advanced/environments#build-specified-environment) |
| `-h, --help` | Display help for command |

## rsbuild dev

Expand Down
24 changes: 20 additions & 4 deletions website/docs/en/guide/basic/configure-rsbuild.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,6 @@ export default defineConfig({
});
```

:::tip
When you use the `.ts`, `.mts`, and `.cts` extensions, Rsbuild will use [jiti](https://github.com/unjs/jiti) to load configuration files, providing interoperability between ESM and CommonJS. The behavior of module resolution differs slightly from the native behavior of Node.js.
:::

## Specify config file

Rsbuild CLI uses the `--config` option to specify the config file, which can be set to a relative path or an absolute path.
Expand All @@ -117,6 +113,26 @@ You can also abbreviate the `--config` option to `-c`:
rsbuild build -c rsbuild.prod.config.mjs
```

## Specify config loader

When you use a configuration file with the `.ts`, `.mts`, and `.cts` extensions, Rsbuild will use [jiti](https://github.com/unjs/jiti) to load configuration files, providing interoperability between ESM and CommonJS. The behavior of module resolution differs slightly from the native behavior of Node.js.

If your JavaScript runtime already natively supports TypeScript, you can use the `--config-loader native` option to use the Node.js native loader to load the configuration file. This can ensure that the module resolution behavior is consistent with the native behavior of Node.js and has better performance.

For example, Node.js v22.6.0+ already natively supports TypeScript, you can use the following command to use the Node.js native loader to load the configuration file:

```bash
# Node.js v23.6.0+
# No need to set --experimental-strip-types
npx rsbuild build --config-loader native

# Node.js v22.6.0 - v23.5.0
# Need to set --experimental-strip-types
NODE_OPTIONS="--experimental-strip-types" npx rsbuild build --config-loader native
```

> See [Node.js - Running TypeScript Natively](https://nodejs.org/en/learn/typescript/run-natively#running-typescript-natively) for more details.

## Using environment variables

In the configuration file, you can use Node.js environment variables such as `process.env.NODE_ENV` to dynamically set different configurations:
Expand Down
1 change: 1 addition & 0 deletions website/docs/zh/api/javascript-api/core.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ function loadConfig(params?: {
path?: string;
meta?: Record<string, unknown>;
envMode?: string;
loader?: 'jiti' | 'native';
}): Promise<{
content: RsbuildConfig;
filePath: string | null;
Expand Down
19 changes: 10 additions & 9 deletions website/docs/zh/guide/basic/cli.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,16 @@ Commands:

Rsbuild CLI 提供了一些公共选项,可以用于所有命令:

| 选项 | 描述 |
| ----------------------- | ------------------------------------------------------------------------------------------------------------ |
| `-c, --config <config>` | 指定配置文件路径,可以为相对路径或绝对路径,详见 [指定配置文件](/guide/basic/configure-rsbuild#指定配置文件) |
| `-r, --root <root>` | 指定项目根目录,可以是绝对路径或者相对于 cwd 的路径 |
| `-m, --mode <mode>` | 指定构建模式,可以是 `development`,`production` 或 `none`,详见 [mode](/config/mode) |
| `--env-mode <mode>` | 指定 env 模式来加载 `.env.[mode]` 文件,详见 [Env 模式](/guide/advanced/env-vars#env-模式) |
| `--env-dir <dir>` | 指定目录来加载 `.env` 文件,详见 [Env 目录](/guide/advanced/env-vars#env-目录) |
| `--environment <name>` | 指定需要构建的 environment 名称,详见 [构建指定环境](/guide/advanced/environments#构建指定环境) |
| `-h, --help` | 显示命令帮助 |
| 选项 | 描述 |
| -------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| `-c, --config <config>` | 指定配置文件路径,可以为相对路径或绝对路径,详见 [指定配置文件](/guide/basic/configure-rsbuild#指定配置文件) |
| `--config-loader <loader>` | 指定配置文件加载方式,可以为 `jiti` 或 `native`,详见 [指定加载方式](/guide/basic/configure-rsbuild#指定加载方式) |
| `-r, --root <root>` | 指定项目根目录,可以是绝对路径或者相对于 cwd 的路径 |
| `-m, --mode <mode>` | 指定构建模式,可以是 `development`,`production` 或 `none`,详见 [mode](/config/mode) |
| `--env-mode <mode>` | 指定 env 模式来加载 `.env.[mode]` 文件,详见 [Env 模式](/guide/advanced/env-vars#env-模式) |
| `--env-dir <dir>` | 指定目录来加载 `.env` 文件,详见 [Env 目录](/guide/advanced/env-vars#env-目录) |
| `--environment <name>` | 指定需要构建的 environment 名称,详见 [构建指定环境](/guide/advanced/environments#构建指定环境) |
| `-h, --help` | 显示命令帮助 |

## rsbuild dev

Expand Down
24 changes: 20 additions & 4 deletions website/docs/zh/guide/basic/configure-rsbuild.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,6 @@ export default defineConfig({
});
```

:::tip
当你使用 `.ts`, `.mts` 和 `.cts` 后缀时,Rsbuild 会使用 [jiti](https://github.com/unjs/jiti) 来加载配置文件,提供 ESM 与 CommonJS 的互操作性,模块解析的行为与 Node.js 原生行为存在一定差异。
:::

## 指定配置文件

Rsbuild CLI 通过 `--config` 选项来指定配置文件,可以设置为相对路径或绝对路径。
Expand All @@ -117,6 +113,26 @@ Rsbuild CLI 通过 `--config` 选项来指定配置文件,可以设置为相
rsbuild build -c rsbuild.prod.config.mjs
```

## 指定加载方式

当你使用 `.ts`, `.mts` 和 `.cts` 后缀的配置文件时,Rsbuild 会使用 [jiti](https://github.com/unjs/jiti) 来加载配置文件,提供 ESM 与 CommonJS 的互操作性,模块解析的行为与 Node.js 原生行为存在一定差异。

如果你使用的 JavaScript 运行时已经原生支持 TypeScript,可以使用 `--config-loader native` 选项来使用 Node.js 原生 loader 来加载配置文件。这可以保证模块解析的行为与 Node.js 原生行为一致,并且性能更好。

例如,Node.js 从 v22.6.0 开始已经原生支持 TypeScript,你可以如下命令来使用 Node.js 原生 loader 来加载配置文件:

```bash
# Node.js v23.6.0+
# 不需要设置 --experimental-strip-types
npx rsbuild build --config-loader native

# Node.js v22.6.0 - v23.5.0
# 需要设置 --experimental-strip-types
NODE_OPTIONS="--experimental-strip-types" npx rsbuild build --config-loader native
```

> 详见 [Node.js - Running TypeScript Natively](https://nodejs.org/en/learn/typescript/run-natively#running-typescript-natively)。

## 使用环境变量

在配置文件中,你可以使用 `process.env.NODE_ENV` 等 Node.js 环境变量,来动态写入不同的配置:
Expand Down