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

# 处理三方依赖

本节介绍如何在 bundle 模式下处理三方依赖。

通常，项目所需的三方依赖可以通过包管理器的 `install` 命令安装。安装成功后，它们通常会出现在项目的 `package.json` 文件中的 `dependencies` 和 `devDependencies` 字段下。

```json title="package.json"
{
  "dependencies": {},
  "devDependencies": {}
}
```

`dependencies` 字段下的依赖通常来说是这个包运行所需的依赖，如果这些三方依赖声明在 `devDependencies` 字段下，那么在生产运行时会出现缺失依赖。

除了 `dependencies` 字段，`peerDependencies` 也可以声明在生产环境中需要的依赖，但它更强调这些依赖在项目运行时的存在，类似于插件机制。

## 三方依赖的默认处理

默认情况下，当生成 CJS 或 ESM 产物时，`dependencies`、`optionalDependencies` 和 `peerDependencies` 字段下的三方依赖不会被 Rslib 打包。

这是因为在 npm 包安装时，其 `dependencies` 也会被安装。通过不打包 `dependencies`，可以减少包的体积。

如果需要打包某些依赖，建议将它们从 `dependencies` 移动到 `devDependencies`，这相当于预打包依赖，并减少依赖安装的体积。

以下是一个简单示例，假设项目依赖 `foo`：

```json title="package.json"
{
  "dependencies": {
    "foo": "^1.0.0"
  },
  // 或
  "peerDependencies": {
    "foo": "^1.0.0"
  }
}
```

当在源代码中使用 `foo` 依赖时：

```tsx title="src/index.ts"
import foo from 'foo';
console.info(foo);
```

此时产物中不会包含 `foo` 的代码:

```js title="dist/index.js"
import foo from 'foo';
console.info(foo);
```

## 自定义三方依赖处理

Rslib 主要通过 [output.autoExternal](/zh/config/rsbuild/output.md#outputautoexternal) 和 [output.externals](/zh/config/rsbuild/output.md#outputexternals) 控制三方依赖是否被打包。

### 配置 autoExternal

如果希望覆盖 `output.autoExternal` 的上述默认行为，使这些依赖被打包进产物，可以将其设置为 `false`：

```ts title="rslib.config.ts"
export default defineConfig({
  lib: [
    {
      output: {
        autoExternal: false,
      },
    },
  ],
});
```

如果只想调整某几类依赖，可以使用对象形式：

```ts title="rslib.config.ts"
export default defineConfig({
  lib: [
    {
      output: {
        autoExternal: {
          dependencies: true,
          optionalDependencies: true,
          peerDependencies: true,
          devDependencies: false,
        },
      },
    },
  ],
});
```

使用 [exclude](https://rsbuild.rs/zh/config/output/auto-external#exclude) 可以从 `output.autoExternal` 自动生成的 external 规则中排除指定包。如果某个包被排除，它的子路径导入也不会被 external：

```ts title="rslib.config.ts"
export default defineConfig({
  lib: [
    {
      output: {
        autoExternal: {
          exclude: ['react', /^@scope\//],
        },
      },
    },
  ],
});
```

### 配置 externals

当你需要指定某些模块不被 Rslib 打包，或需要改变 external 后的请求路径时，可以使用 [output.externals](/zh/config/rsbuild/output.md#outputexternals)。

数组形式适合保留原始请求路径：

```ts title="rslib.config.ts"
export default defineConfig({
  lib: [
    {
      output: {
        externals: ['react', 'react/jsx-runtime'],
      },
    },
  ],
});
```

对象形式可以指定 external 后的请求路径，常用于给 external 的模块改名：

```ts title="rslib.config.ts"
export default defineConfig({
  lib: [
    {
      output: {
        externals: {
          react: 'react-18',
          'react/jsx-runtime': 'react-18/jsx-runtime',
        },
      },
    },
  ],
});
```

:::tip
`react/jsx-runtime` 这类子路径需要单独处理。只配置 `react` 不代表 `react/jsx-runtime` 也会使用相同的 external 规则。
:::

如果要匹配一组模块，可以使用正则：

```ts title="rslib.config.ts"
export default defineConfig({
  lib: [
    {
      output: {
        externals: [/^react($|\/)/],
      },
    },
  ],
});
```

在一些复杂场景中，如果需要根据请求来源、上下文等信息决定是否 external，可以通过 [tools.rspack](/zh/config/rsbuild/tools.md#toolsrspack) 配置 Rspack 的 `externals`：

```ts title="rslib.config.ts"
export default defineConfig({
  lib: [
    {
      tools: {
        rspack: {
          externals: [
            ({ request }, callback) => {
              if (request?.startsWith('react')) {
                callback(null, request);
                return;
              }

              callback();
            },
          ],
        },
      },
    },
  ],
});
```

更多用法可参考 Rspack 的 [Externals](https://rspack.rs/zh/config/externals) 文档。

## 打包通过 `createRequire()` 加载的依赖

Node.js 的 ES 模块环境不提供 CommonJS 的 `require` 函数。若需要在 ES 模块中使用 CommonJS 的加载语义，可以通过 Node.js 的 [`createRequire()`](https://nodejs.org/api/module.html#modulecreaterequirefilename) 创建一个 `require` 函数：

```ts title="src/index.ts"
import { createRequire } from 'node:module';

const require = createRequire(import.meta.url);
const foo = require('foo');

export const bar = foo.bar;
```

Rslib 默认会在产物中保留 `createRequire()` 调用。如果希望 Rspack 分析由它创建的 `require()` 调用，并打包由 `require('foo')` 这类可静态分析的调用所加载的依赖，可以启用 [`module.parser.javascript.createRequire`](https://rspack.rs/zh/config/module-parser#javascriptcreaterequire)。

```ts title="rslib.config.ts"
import { defineConfig } from '@rslib/core';

export default defineConfig({
  tools: {
    rspack: {
      module: {
        parser: {
          javascript: {
            createRequire: true,
          },
        },
      },
    },
  },
});
```

如果被打包的依赖中存在需要保留到运行时的 `createRequire()` 调用，可以改用 `module.rules`，仅对 node\_modules 之外的 JavaScript/TypeScript 模块启用该能力：

```ts title="rslib.config.ts"
import { defineConfig } from '@rslib/core';

export default defineConfig({
  tools: {
    rspack: {
      module: {
        rules: [
          {
            test: /\.[cm]?[jt]sx?$/,
            exclude: /node_modules/,
            parser: {
              createRequire: true,
            },
          },
        ],
      },
    },
  },
});
```
