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

# 产物输出格式

Rslib 支持多种 JavaScript 文件的输出格式：[ESM](#esm--cjs)、[CJS](#esm--cjs)、[UMD](#umd)、[MF](#mf) 和 [IIFE](#iife)。在本章中，我们将介绍这些格式之间的区别以及如何为你的库选择合适的格式。

## ESM / CJS

库作者需要仔细考虑支持哪种模块格式。让我们了解一下 ESM (ECMAScript Modules) 和 CJS (CommonJS)，以及何时使用它们。

### 什么是 ESM 和 CJS？

- **ESM**: <ESM />

- **CommonJS**: <CJS />

::: tip

阅读 [Node.js 包配置指南](https://nodejs.github.io/package-examples/) 了解更多 ESM 和 CJS 的相关信息，包括文件结构组织、`package.json` 配置、模块互操作性以及最佳实践。

:::

### 选择模块格式

模块格式通常取决于目标消费者的使用方式。对于新包，建议优先发布纯 ESM；只有存在明确的兼容需求时，再提供 ESM/CJS 双格式。

#### 优先发布纯 ESM

ESM 是 JavaScript 的标准模块格式，受到现代浏览器、Node.js 和主流构建工具的支持，并支持静态分析和摇树优化。与 CommonJS 相比，`import` 和 `export` 语句更简洁直观，也更易于阅读。此外，只维护一种格式还能减少构建配置、包导出和测试组合。

如果消费者仍然使用 CommonJS，并且 `package.json#exports` 允许 `require()` 解析到 ESM 入口，那么在 [Node.js `^20.19.0` 或 `>=22.12.0`](https://nodejs.org/api/modules.html#loading-ecmascript-modules-using-require) 中，只要该入口及其依赖不使用顶层 `await`，就可以直接通过 `require()` 加载纯 ESM 包，无需库作者额外发布 CJS 产物：

```js
const packageExports = require('pure-esm-package');
```

#### 在需要兼容时发布 ESM/CJS 双格式

以下场景可以考虑同时发布 ESM 和 CJS：

- CommonJS 消费者使用的 Node.js 版本、工具或运行时无法通过 `require()` 同步加载 ESM。
- 消费者明确要求独立的 CJS 文件。

双格式可以扩大兼容范围，并帮助消费者逐步迁移到 ESM，但也需要分别构建、配置和测试两套产物。如果同一个包的 ESM 和 CJS 版本被同时加载，还可能产生独立的模块实例，导致状态或身份判断不一致。因此，添加 CJS 产物前应先确认目标消费者确实需要它。

## UMD

### 什么是 UMD？

UMD 代表 [通用模块定义](https://github.com/umdjs/umd)，这是一种编写 JavaScript 模块的模式，可以在不同的环境中通用，例如浏览器和 Node.js。其主要目标是确保与最流行的模块系统兼容，包括 AMD（异步模块定义）、CommonJS（CJS）和浏览器全局变量。

### 何时使用 UMD？

如果你正在构建一个需要在浏览器和 Node.js 环境中使用的库，UMD 是一个不错的选择。UMD 可以作为独立的脚本标签在浏览器中使用，也可以作为 CommonJS 模块在 Node.js 中使用。

StackOverflow 上的详细回答：[什么是通用模块定义 (UMD)？](https://stackoverflow.com/a/77284527/8063488)

> 然而，对于前端库，你仍然可以提供一个单一文件，方便用户从 CDN 下载并直接嵌入到他们的网页中。这通常仍然采用 UMD 模式，只是现在不再由库作者手动编写/复制到源代码中，而是由转译器/打包器自动添加。
>
> 同样地，对于需要在 Node.js 中运行的后端/通用库，你仍然可以通过 npm 分发一个 CommonJS 模块构建，以支持所有仍在使用旧版 Node.js 的用户（他们不想/不需要自己使用转译器）。这在新库中不太常见，但现有库会尽力保持向后兼容，不会导致应用程序被破坏。

### 如何构建 UMD 库？

- 在 Rslib 配置文件中将 [lib.format](/zh/config/lib/format.md) 设置为 `umd`。
- 如果库需要导出名称，请将 [lib.umdName](/zh/config/lib/umd-name.md) 设置为 UMD 库的名称。
- 使用 [output.externals](/zh/config/rsbuild/output.md#outputexternals) 指定 UMD 库依赖的外部依赖，UMD 的 [lib.autoExtension](/zh/config/lib/auto-extension.md) 配置默认启用。

### 示例

以下是一个构建 UMD 库的 Rslib 配置示例。

- `lib.format: 'umd'`: 配置 Rslib 构建 UMD 库。
- `lib.umdName: 'RslibUmdExample'`: 设置 UMD 库的导出名称。
- `output.externals.react: 'React'`: 指定外部依赖 `react` 可以通过 `window.React` 访问。
- `runtime: 'classic'`: 使用 React 的 classic 运行时，以支持使用 React 版本低于 18 的应用程序。

```ts title="rslib.config.ts"
import { pluginReact } from '@rsbuild/plugin-react';
import { defineConfig } from '@rslib/core';

export default defineConfig({
  lib: [
    {
      // [!code highlight:6]
      format: 'umd',
      umdName: 'RslibUmdExample',
      output: {
        externals: {
          react: 'React',
        },
        distPath: './dist/umd',
      },
    },
  ],
  output: {
    target: 'web',
  },
  plugins: [
    pluginReact({
      swcReactOptions: {
        runtime: 'classic', // [!code highlight]
      },
    }),
  ],
});
```

## MF

### 什么是 MF？

MF 代表 Module Federation。模块联邦是一种用于 JavaScript 应用程序分解的架构模式（类似于服务器端的微服务），允许你在多个 JavaScript 应用程序（或微前端）之间共享代码和资源。

请参阅 [模块联邦](https://rsbuild.rs/zh/guide/advanced/module-federation) 以获取更多详细信息。

## IIFE


IIFE 格式代表「立即调用函数表达式」，旨在浏览器中运行。将代码包裹在函数表达式中，可确保代码中的任何变量不会意外与全局作用域中的变量发生冲突。若你的入口点有需要在浏览器中作为全局变量暴露的导出内容，可通过全局名称设置来配置该全局变量的名称。

在 IIFE 格式下，[output.globalObject](https://rspack.rs/zh/config/output#outputglobalobject) 默认设置为 [globalThis](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/globalThis)，源码中命中了 [externals](/zh/config/rsbuild/output.md#outputexternals) 的 `import` 语句将被转换为通过 `globalThis` 上的属性访问，你可以覆盖 [output.globalObject](https://rspack.rs/zh/config/output#outputglobalobject) 为任意值。

指定 `iife` 格式时源码及对应产物如下:

```js title="源码"
// externals 已经将 parent-sdk 作为外部依赖
// externals: ['parent-sdk']
import { version } from 'parent-sdk';
alert(version);
```

```js title="IIFE 产物"
(
  () => {
    const external_parent_sdk_namespaceObject = globalThis['parent-sdk'];
    alert(external_parent_sdk_namespaceObject.version);
  },
)();
```
