CommonJS (module.exports)
基本概念
- CommonJS 是 Node.js 早期的模块系统标准。
- 每个文件是一个模块,模块内部通过 module.exports 导出内容。
- 使用 require() 导入模块。
// util.js (CommonJS)
module.exports = {
foo() { console.log(‘foo’); },
bar() { console.log(‘bar’); }
};
// main.js
const util = require(‘./util.js’);
util.foo(); // 输出 ‘foo’
特点
1/ 每个模块导出的是 一个对象,可以直接赋值给 module.exports。
2/ 导入的时候得到的就是这个对象。
3/ 没有概念上的 “default”,整个 module.exports 就是模块本身。
ES Module (export default / export)
基本概念
ES Module(简称 ESM)是 JavaScript 官方标准模块系统。
支持 静态分析(在编译时就能确定依赖),语法是 import / export。
有两种导出方式:
默认导出:export default …
命名导出:export const foo = …
// util.js (ES Module)
export default {
foo() { console.log(‘foo’); },
bar() { console.log(‘bar’); }
};
// main.js
import util from ‘./util.js’;
util.foo(); // 输出 ‘foo’
特点
1/ 可以同时有 一个默认导出 和 多个命名导出:
export const x = 1;
export default function() {}
2/ ESM 是静态的,编译器可以提前知道依赖关系,方便 tree-shaking。
3/ 默认导出 (export default) 在语法上和 CommonJS 的 module.exports 类似,但概念上是 ESM 模块的 default 成员。
为什么它们不一样?
| 属性 | CommonJS | ES Module |
|---|---|---|
| 导出语法 | module.exports = {...} |
export default {...} / export const ... |
| 导入语法 | const x = require('./module') |
import x from './module' |
| 默认导出 | 没有默认导出概念,整个模块对象就是导出值 | 有 default 和命名导出概念 |
| 加载方式 | 动态加载(运行时 require) | 静态加载(编译时 import) |
| 兼容性 | Node.js 内置,适合老项目 | 浏览器原生、现代 JS 打包工具 |
所以它们本质上 是不同模块系统:
- CommonJS:模块是一个对象,运行时加载
- ESM:模块是静态结构,支持默认和命名导出
为什么有兼容问题?
当你用 import 导入一个 CommonJS 模块时,ESM 会把整个 module.exports 当作 一个默认成员,因此有时你要用:
import util from ‘./util.js’;
util.default.foo(); // 因为 util = { default: { foo(), bar() } }
同理,ESM 的 export default 如果用 require() 导入,有时也会得到一个对象包裹在 .default 下:
const util = require(‘./util.js’);
util.default.foo(); // 可能需要这样访问
这就是“兼容问题”的来源。
总结
CommonJS
早期 Node.js 模块系统
module.exports = 整个模块
require() 导入
ES Module
官方标准模块系统
export default 是模块的默认导出
import 导入,可同时有命名导出
区别
CommonJS 是对象导出,动态加载
ESM 有默认/命名导出,静态加载
兼容问题
CommonJS 导出的模块用 import 可能需要 .default
ESM 导出的模块用 require 可能需要 .default