标准答案
- CommonJS 使用 require 和 module.exports,模块加载偏运行时,Node.js 早期生态大量使用。
- ESM 使用 import 和 export,语法是静态的,更适合 Tree Shaking、静态分析和现代浏览器加载。
- UMD 是兼容格式,通常同时兼容 CommonJS、AMD 和全局变量,早期库为了适配多环境会产出 UMD。
- IIFE 是立即执行函数表达式,常用于把变量包在函数作用域中,避免直接污染全局对象。
- 现代前端应用更偏向 ESM;库包为了兼容不同消费方,可能同时提供 ESM、CJS 和 UMD 产物。
题目解析
模块格式本质上是在回答两个问题:代码如何暴露能力,以及运行环境如何加载它。CommonJS 更像运行时拿模块,ESM 则把依赖关系写成编译期就能看懂的结构。
UMD 和 IIFE 的历史感更强。它们解决的是浏览器脚本标签、老构建工具、不同加载器之间的兼容问题,在现代应用源码里不会作为首选写法,但在库产物和遗留系统里仍然能见到。
理解这些格式有助于排查“为什么库不能被摇树优化”“为什么浏览器直接引入报错”“为什么一个包同时有 main、module、exports”。这些问题通常不是语法问题,而是产物格式和消费环境没有对齐。
代码示例
同一个能力可以用不同模块格式暴露出来。
JavaScript
// CommonJS
const utils = require('./utils')
module.exports = { format: utils.format }
// ESM
import { format } from './utils.js'
export { format }
// IIFE
;(function () {
window.format = function format(value) {
return String(value)
}
})()常见误区
- 把 ESM 和 CommonJS 的差异只理解成 import 与 require 的写法不同。
- 认为所有模块格式都同样适合 Tree Shaking。静态 ESM 通常更容易被构建工具分析。
- 在浏览器里直接使用未打包的 CommonJS 代码,导致 require 或 module 未定义。