# CommonJS与ESM是什么关系?
CommonJS 和 ESM(ECMAScript Modules) 本质上是 JavaScript 的两套模块规范。
它们解决的是同一个问题:
如何把代码拆分成多个文件,并且互相引用。
# 模块化发展历史
第一阶段:没有模块
以前 JavaScript 只有:
<script src="a.js"></script>
<script src="b.js"></script>
<script src="c.js"></script>
1
2
3
2
3
所有变量都挂在全局:
var user = {}
1
容易冲突。
第二阶段:Node.js 推出 CommonJS
2009年,Node.js 出现。
当时浏览器没有模块标准。
Node.js 自己设计了一套:
// user.js
module.exports = {
name: 'Tom'
}
1
2
3
4
2
3
4
// app.js
const user = require('./user')
console.log(user.name)
1
2
3
4
2
3
4
这就是:CommonJS
特点:
require()
module.exports
exports
1
2
3
2
3
第三阶段:ES6推出ESM
2015年,JavaScript 官方(ECMAScript)终于推出标准模块:
export default {
name: 'Tom'
}
1
2
3
2
3
import user from './user.js'
1
这就是:
ESM ES Module ECMAScript Module
特点:
import export export default
# 两者关系
可以理解为:
CommonJS = Node.js 自己发明的模块系统
ESM = JavaScript 官方标准模块系统
1
2
3
2
3
就像:
微信支付 ← 企业方案
银行卡支付 ← 国家标准
后来大家逐渐统一到标准方案。
# 语法对比
CommonJS
导出:
module.exports = {
name: 'Tom'
}
1
2
3
2
3
导入:
const user = require('./user')
1
ESM
导出:
export default {
name: 'Tom'
}
1
2
3
2
3
导入:
import user from './user.js'
1
# 加载机制区别
这是最大的区别。
CommonJS
同步加载
const user = require('./user')
1
执行到这里:
停下来
↓
读取文件
↓
执行文件
↓
返回结果
↓
继续执行
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
所以:
同步
1
适合服务器。
因为磁盘读取很快。
ESM
静态加载
import user from './user.js'
1
运行前就已经知道依赖关系:
编译阶段
↓
分析 import
↓
建立依赖图
↓
运行
1
2
3
4
5
6
7
2
3
4
5
6
7
因此:
Tree Shaking
按需加载
代码分割
1
2
3
2
3
都能实现。