For AI agents: the complete documentation index is available at /zh/llms.txt, the full documentation bundle is available at /zh/llms-full.txt, and this page is available as Markdown at /zh/guide/basic/output-format.md.
close
  • 简体中文
  • 产物输出格式

    Rslib 支持多种 JavaScript 文件的输出格式:ESMCJSUMDMFIIFE。在本章中,我们将介绍这些格式之间的区别以及如何为你的库选择合适的格式。

    ESM / CJS

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

    什么是 ESM 和 CJS?

    • ESM:

      ESM 代表 ECMAScript modules,这是一种在 ES2015 中引入的现代模块系统,允许将 JavaScript 代码组织成可重用的、自包含的模块。ESM 现在是 浏览器Node.js 环境的标准,取代了旧的模块系统,如 CommonJS (CJS)AMD

    • CommonJS:

      CJS 代表 CommonJS modules,这是一种在 JavaScript 中使用的模块系统,特别是在像 Node.js 这样的服务器端环境中。它的诞生是为了通过提供一种管理模块和依赖项的方法,允许 JavaScript 在浏览器之外使用。

    Tip

    阅读 Node.js 包配置指南 了解更多 ESM 和 CJS 的相关信息,包括文件结构组织、package.json 配置、模块互操作性以及最佳实践。

    选择模块格式

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

    优先发布纯 ESM

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

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

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

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

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

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

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

    UMD

    什么是 UMD?

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

    何时使用 UMD?

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

    StackOverflow 上的详细回答:什么是通用模块定义 (UMD)?

    然而,对于前端库,你仍然可以提供一个单一文件,方便用户从 CDN 下载并直接嵌入到他们的网页中。这通常仍然采用 UMD 模式,只是现在不再由库作者手动编写/复制到源代码中,而是由转译器/打包器自动添加。

    同样地,对于需要在 Node.js 中运行的后端/通用库,你仍然可以通过 npm 分发一个 CommonJS 模块构建,以支持所有仍在使用旧版 Node.js 的用户(他们不想/不需要自己使用转译器)。这在新库中不太常见,但现有库会尽力保持向后兼容,不会导致应用程序被破坏。

    如何构建 UMD 库?

    示例

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

    • lib.format: 'umd': 配置 Rslib 构建 UMD 库。
    • lib.umdName: 'RslibUmdExample': 设置 UMD 库的导出名称。
    • output.externals.react: 'React': 指定外部依赖 react 可以通过 window.React 访问。
    • runtime: 'classic': 使用 React 的 classic 运行时,以支持使用 React 版本低于 18 的应用程序。
    rslib.config.ts
    import { pluginReact } from '@rsbuild/plugin-react';
    import { defineConfig } from '@rslib/core';
    
    export default defineConfig({
      lib: [
        {
          format: 'umd',
          umdName: 'RslibUmdExample',
          output: {
            externals: {
              react: 'React',
            },
            distPath: './dist/umd',
          },
        },
      ],
      output: {
        target: 'web',
      },
      plugins: [
        pluginReact({
          swcReactOptions: {
            runtime: 'classic',
          },
        }),
      ],
    });

    MF

    什么是 MF?

    MF 代表 Module Federation。

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

    请参阅 模块联邦 以获取更多详细信息。

    IIFE

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

    在 IIFE 格式下,output.globalObject 默认设置为 globalThis,源码中命中了 externalsimport 语句将被转换为通过 globalThis 上的属性访问,你可以覆盖 output.globalObject 为任意值。

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

    源码
    // externals 已经将 parent-sdk 作为外部依赖
    // externals: ['parent-sdk']
    import { version } from 'parent-sdk';
    alert(version);
    IIFE 产物
    (
      () => {
        const external_parent_sdk_namespaceObject = globalThis['parent-sdk'];
        alert(external_parent_sdk_namespaceObject.version);
      },
    )();