输出格式:ESM、CJS 与 UMD
🎯 引言
学完这篇文章,你将理解 es、cjs、umd、iife 四种输出格式的区别,知道什么环境该选哪种格式,并能一次打包同时输出多份产物。
🧱 为什么需要输出格式
你写的库会被别人在各种环境里使用:
- 有人在 Vite / Webpack 项目里
import它; - 有人在 Node.js 老项目里
require它; - 还有人直接在浏览器里用
<script>标签引入它。
这些环境“说”的模块语言不一样,所以 Rollup 提供了 output.format 选项,把同一份源码翻译成不同的模块格式。
⚡ 四种常用格式对比
| 格式 | 全称 | 适用环境 | 典型用法 |
|---|---|---|---|
es | ES Module | 现代浏览器、打包工具 | import { add } from 'my-utils' |
cjs | CommonJS | Node.js 传统环境 | const { add } = require('my-utils') |
umd | Universal Module Definition | 浏览器 + Node.js 通吃 | <script> 标签引入 |
iife | Immediately Invoked Function Expression | 纯浏览器 | <script> 标签引入,立即执行 |
简单记忆:
- 写库给别人用:至少输出
es+cjs,照顾打包工具和 Node.js。 - 直接在浏览器用:输出
umd或iife。
umd 和 iife 都能给浏览器用,区别在于 umd 同时兼容 Node.js 和 AMD 环境,而 iife 只在浏览器里跑。拿不准就选 umd。🛠 一次输出多种格式
output 可以写成数组,一次打包生成多份产物:
export default {
input: 'src/index.js',
output: [
{
file: 'dist/bundle.esm.js',
format: 'es'
},
{
file: 'dist/bundle.cjs.js',
format: 'cjs'
},
{
file: 'dist/bundle.umd.js',
format: 'umd',
name: 'MyUtils'
}
]
};
执行 npm run build 后,dist 目录下会同时生成三个文件,分别对应三种环境。
umd 和 iife 格式必须配置 name,它是暴露给浏览器的全局变量名。比如上面配置 name: 'MyUtils' 后,浏览器里就能通过 window.MyUtils.add(1, 2) 调用你的函数。漏掉它会直接报错。💡 三种格式的产物长什么样
同一份源码,三种格式的产物风格差异很大,看一眼就有直观感受。
ES 格式几乎就是源码原样合并,export 保留:
function add(a, b) {
return a + b;
}
export { add };
CJS 格式把 export 转成了 Node.js 认识的 exports:
'use strict';
function add(a, b) {
return a + b;
}
exports.add = add;
UMD 格式外面包了一层环境判断,自动适配不同环境:
(function (global, factory) {
// 判断当前是 Node.js、AMD 还是浏览器,选择对应的导出方式
typeof exports === 'object' && typeof module !== 'undefined'
? factory(exports)
: (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.MyUtils = {})));
})(this, function (exports) {
'use strict';
// ...
});
UMD 看起来复杂,但你不用手写,Rollup 会自动生成。
🧾 小节总结
- 不同环境使用不同的模块格式,Rollup 用
output.format控制产物格式。 es给打包工具和现代浏览器,cjs给 Node.js,umd/iife给浏览器直接引用。output写成数组可以一次输出多份产物。umd和iife格式必须配置name,作为浏览器的全局变量名。
❓ 知识问答
Q1:我的库只用在新项目里,可以只输出 es 格式吗?
A:可以。如果确定使用方都会通过 Vite / Webpack 引入,只输出 es 最简单。开源库为了兼容性一般会同时提供 cjs。
Q2:format: 'es' 和 format: 'esm' 有区别吗?
A:没有区别,esm 是 es 的别名,写哪个都行。同理 cjs 也可以写成 commonjs。
Q3:UMD 的 name 可以带横线吗,比如 my-utils?
A:不建议。name 会变成全局变量名,必须是一个合法的 JavaScript 标识符,推荐用大驼峰写法,如 MyUtils。
Q4:输出多种格式会让打包变慢吗?
A:会略微变慢,因为要写多份文件。但 Rollup 的依赖分析只做一次,实际影响很小,可以放心使用。
🧪 小练习
改造 rollup-demo 项目的配置,一次输出两种格式:
- 在
output数组中添加es和cjs两份输出,文件名分别为bundle.esm.js和bundle.cjs.js。 - 执行
npm run build,对比两份产物中export的写法差异。
export default {
input: 'src/index.js',
output: [
{
file: 'dist/bundle.esm.js',
format: 'es'
}
// 请在这里补充 cjs 格式的输出
]
};
🎉 恭喜你已经掌握了 Rollup 的输出格式!下一篇我们会学习插件系统,让 Rollup 能处理 JSON 文件和第三方依赖。
