CommonJS
解释 Node 传统 CommonJS 模块的导出/导入、同步加载与和 ESM 的互操作边界。
#type / concept
#status / growing
#tech / dev
#resource / javascript
#resource / nodejs
[!info] 关联笔记
- 所属:模块与工程化 MOC
- 对照:ES Module · 历史格式 · 模块模式
CommonJS
这个概念为什么出现
Node 早期用 require/module.exports 解决“文件如何变成可复用模块”。今天 ESM 是语言标准,但大量包与旧代码仍是 CJS,工程上必须会读会互操作。
[!abstract] 一句话理解 CommonJS 以同步
require加载模块,并通过exports/module.exports暴露值;它是 Node 历史默认,不是浏览器原生模块系统。
最小可运行示例
场景:把库存计价函数拆成工具模块
// pricing.cjs
function priceWithTax(base, rate) {
return base * (1 + rate)
}
module.exports = { priceWithTax }
// main.cjs
const { priceWithTax } = require('./pricing.cjs')
console.log(priceWithTax(100, 0.03))
node main.cjs
期望:103。
核心模型
- 每个文件是模块,有自己的作用域
require同步执行目标模块并缓存module.exports是导出对象;exports.x =是其上的快捷写法- 循环依赖时可能拿到不完整导出
与 ESM 边界
| 点 | CJS | ESM |
|---|---|---|
| 语法 | require/exports | import/export |
| 加载 | 同步为主 | 静态分析/异步能力 |
| 浏览器 | 不原生 | 原生 type=module |
| 互操作 | 需 Node 解析规则 | 有条件导出等 |
常见误区
[!warning] 常见误区:exports = {} 重绑定 应
module.exports = {},只给exports赋值不会改变导出。
工程实践
- 新 Node 代码优先 ESM(项目策略允许时)
- 维护双包时理解
exports字段条件导出 - 打包工具会处理 CJS/ESM 转换,但不要盲目
本节总结
CJS 是 Node 历史模块合同;会它是为了生态与迁移,不是为了在新前端项目继续扩散。
自测题
- 为什么 require 有缓存?
- ESM 浏览器能否直接 require?
参考答案
- 避免重复执行与共享实例。
- 不能;浏览器原生是 ESM。