产物输出格式
Rslib 支持多种 JavaScript 文件的输出格式:ESM、CJS、UMD、MF 和 IIFE。在本章中,我们将介绍这些格式之间的区别以及如何为你的库选择合适的格式。
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 在浏览器之外使用。
阅读 Node.js 包配置指南 了解更多 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 中,只要该入口及其依赖不使用顶层 await,就可以直接通过 require() 加载纯 ESM 包,无需库作者额外发布 CJS 产物:
在需要兼容时发布 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 库?
- 在 Rslib 配置文件中将 lib.format 设置为
umd。 - 如果库需要导出名称,请将 lib.umdName 设置为 UMD 库的名称。
- 使用 output.externals 指定 UMD 库依赖的外部依赖,UMD 的 lib.autoExtension 配置默认启用。
示例
以下是一个构建 UMD 库的 Rslib 配置示例。
lib.format: 'umd': 配置 Rslib 构建 UMD 库。lib.umdName: 'RslibUmdExample': 设置 UMD 库的导出名称。output.externals.react: 'React': 指定外部依赖react可以通过window.React访问。runtime: 'classic': 使用 React 的 classic 运行时,以支持使用 React 版本低于 18 的应用程序。
MF
什么是 MF?
MF 代表 Module Federation。
模块联邦是一种用于 JavaScript 应用程序分解的架构模式(类似于服务器端的微服务),允许你在多个 JavaScript 应用程序(或微前端)之间共享代码和资源。
请参阅 模块联邦 以获取更多详细信息。
IIFE
IIFE 格式代表「立即调用函数表达式」,旨在浏览器中运行。将代码包裹在函数表达式中,可确保代码中的任何变量不会意外与全局作用域中的变量发生冲突。若你的入口点有需要在浏览器中作为全局变量暴露的导出内容,可通过全局名称设置来配置该全局变量的名称。
在 IIFE 格式下,output.globalObject 默认设置为 globalThis,源码中命中了 externals 的 import 语句将被转换为通过 globalThis 上的属性访问,你可以覆盖 output.globalObject 为任意值。
指定 iife 格式时源码及对应产物如下:
