> For AI agents: the complete documentation index is available at /zh/llms.txt, the full documentation bundle is available at /zh/llms-full.txt.

# DefinePlugin

`DefinePlugin` 在编译时将代码中的变量替换为其他值或表达式。这对于允许开发构建和生产构建之间的不同行为非常有用。如果你在开发构建中执行日志记录，但在生产构建中则不执行，你可能会使用一个全局常量来决定是否进行日志记录。这正是 `DefinePlugin` 的用武之地，为开发和生产构建设置一成不变的规则。

## 示例

### 基本使用

传入 `DefinePlugin` 的每个键都是一个标识符或多个标识符用 `.` 连接。

- 如果值是一个字符串，它将被用作代码片段。
- 如果值不是字符串，它会被转化为字符串（包括函数）。
- 如果值是一个对象，所有键都以相同的方式定义。
- 如果你在键前加上 `typeof`，它只在 typeof 调用中被定义。

这些值将被内联到代码中，允许在压缩阶段删除掉那些冗余的条件判断。

```js
new rspack.DefinePlugin({
  PRODUCTION: JSON.stringify(true),
  VERSION: JSON.stringify('5fa3b9'),
  BROWSER_SUPPORTS_HTML5: true,
  TWO: '1+1',
  'typeof window': JSON.stringify('object'),
  'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
});
```

```js
console.log('Running App version ' + VERSION);
if (!BROWSER_SUPPORTS_HTML5) require('html5shiv');
```

:::warning 警告
在为 `process` 定义值时，推荐使用 `'process.env.NODE_ENV': JSON.stringify('production')` 而不是 `process: { env: { NODE_ENV: JSON.stringify('production') } }`。使用后者会重写 `process` 对象，这可能会破坏对某些模块的兼容性，这些模块期望 process 对象上的其他值被定义。
:::

:::tip 提示
请注意，由于插件直接执行文本替换，因此提供给它的值必须包含字符串内部的实际引号。通常，这是通过使用交替引号，如 `'"production"'`，或使用 `JSON.stringify('production')` 来完成。
:::

```js
if (!PRODUCTION) {
  console.log('Debug info');
}

if (PRODUCTION) {
  console.log('Production log');
}
```

通过 Rspack，但不进行压缩后的结果为：

```js
if (!true) {
  console.log('Debug info');
}
if (true) {
  console.log('Production log');
}
```

在压缩后的结果为：

```js
console.log('Production log');
```

### 特性标志

使用[特性标志](https://en.wikipedia.org/wiki/Feature_toggle)在生产/开发构建中启用/禁用功能。

```js
new rspack.DefinePlugin({
  NICE_FEATURE: JSON.stringify(true),
  EXPERIMENTAL_FEATURE: JSON.stringify(false),
});
```

### 服务 URL

在生产/开发构建中使用不同的服务 URL：

```js
new rspack.DefinePlugin({
  SERVICE_URL: JSON.stringify('https://dev.example.com'),
});
```

## 选项

- **类型：**

```ts
type CodeValue = RecursiveArrayOrRecord<CodeValuePrimitive>;
type CodeValuePrimitive =
  null | undefined | RegExp | Function | string | number | boolean | bigint;
type RecursiveArrayOrRecord<T> =
  | { [index: string]: RecursiveArrayOrRecord<T> }
  | Array<RecursiveArrayOrRecord<T>>
  | T;

type DefinePluginOptions = Record<string, CodeValue>;
```

将标识符或属性路径映射为编译时替换它们的代码片段。对象中的每个键都是一项定义，例如 `DEBUG` 或 `process.env.NODE_ENV`。

## 使用 `JSON.stringify`

当你希望注入的是字面量值，而不是代码片段时，应使用 `JSON.stringify`。

常见场景包括：

- 注入字符串常量，例如环境名、版本号、接口地址。
- 注入对象或数组，并在业务代码中直接读取其内容。
- 注入 `process.env.*` 这类来自环境变量的字符串值。

这是因为 `DefinePlugin` 中的字符串会被直接当作代码插入，而不会自动补上引号。

```js
new rspack.DefinePlugin({
  MODE: 'production',
  MODE_STRINGIFIED: JSON.stringify('production'),
});
```

```js
const mode = MODE;
const modeStringified = MODE_STRINGIFIED;

// 会变成
const mode = production;
const modeStringified = 'production';
```

上面的 `MODE` 会被当作标识符 `production`，而不是字符串 `'production'`，通常会导致运行时错误。`MODE_STRINGIFIED` 则会被替换为合法的字符串字面量，是更安全的写法。

如果需要注入对象或数组，也建议使用 `JSON.stringify`：

```js
new rspack.DefinePlugin({
  APP_INFO: JSON.stringify({
    name: 'demo',
    features: ['a', 'b'],
  }),
});
```

这样生成的 `APP_INFO` 会是一个可直接使用的对象字面量。否则，像 `APP_INFO: { ... }` 这样的写法会被 `DefinePlugin` 当作嵌套定义配置递归处理，而不是按对象字面量注入到业务代码中。


本页改编自 [webpack 文档](https://webpack.docschina.org/plugins/define-plugin/)，遵循 [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/)，且已作修改。

