ESM(ECMAScript Modules)和 CJS(CommonJS)是 JavaScript 中两种不同的模块系统,它们的主要区别在于语法、加载机制、执行时机、适用环境等方面。下面是详细对比:
📦 1. 基本概念
| 模块系统 | 全称 | 简介 |
|---|
| ESM | ECMAScript Modules | JavaScript 官方标准模块系统(ES6 引入) |
| CJS | CommonJS | Node.js 最初使用的模块系统 |
🧾 2. 语法对比
✅ ESM(推荐使用)
export const name = 'vite'
export function sayHello() {}
export default function () {
console.log('default export')
}
import { name, sayHello } from './module.js'
import defaultFn from './module.js'
✅ CJS(传统 Node.js)
const name = 'vite'
function sayHello() {}
module.exports = { name, sayHello }
const { name, sayHello } = require('./module')
⚙️ 3. 加载机制
| 特性 | ESM | CJS |
|---|
| 加载方式 | 静态加载(编译时确定依赖) | 动态加载(运行时 require) |
| 是否异步 | 是(import 是异步) | 否(require 是同步) |
| 是否支持 tree-shaking | ✅ 支持 | ❌ 不支持 |
| 是否支持顶层 await | ✅ 支持 | ❌ 不支持(需额外配置) |
🧪 4. 执行时机
- ESM 是在代码执行前解析所有 import(提前加载)。
- CJS 是在代码执行时遇到 require 才加载(懒加载)。
🌍 5. 适用环境
| 环境 | 支持情况 |
|---|
| 浏览器 | ✅ 原生支持 ESM(import) |
| Node.js | ✅ 支持 ESM(需要 .mjs 或 "type": "module") |
| Webpack/Vite 等构建工具 | ✅ 推荐使用 ESM |
| 老旧 Node.js 项目 | ✅ 默认使用 CJS |
🛠️ 6. 文件扩展名和 package.json 配置
在 Node.js 中使用 ESM:
- 文件扩展名为
.mjs,或
- 在 package.json 中添加:
{
"type": "module"
}
否则 Node.js 默认使用 CJS 模式。
📚 7. 示例对比总结
| 特性 | ESM | CJS |
|---|
| 导入语法 | import/export | require/module.exports |
| 加载方式 | 静态 | 动态 |
| 执行顺序 | 先加载再执行 | 边执行边加载 |
| Tree-shaking | ✅ 支持 | ❌ 不支持 |
| 顶层 await | ✅ 支持 | ❌ 不支持 |
| 浏览器支持 | ✅ | ❌(需打包) |
✅ 总结:什么时候用哪个?
| 场景 | 推荐模块系统 |
|---|
| 前端项目(Vite、Webpack) | ✅ ESM(import/export) |
| Node.js 新项目 | ✅ ESM(推荐) |
| 老旧 Node.js 项目 | ✅ CJS(兼容性) |
| 发布 npm 包 | ✅ 同时支持 ESM + CJS(双构建) |