CommonJS

解释 Node 传统 CommonJS 模块的导出/导入、同步加载与和 ESM 的互操作边界。

#type / concept #status / growing #tech / dev #resource / javascript #resource / nodejs

[!info] 关联笔记

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 边界

CJSESM
语法require/exportsimport/export
加载同步为主静态分析/异步能力
浏览器不原生原生 type=module
互操作需 Node 解析规则有条件导出等

常见误区

[!warning] 常见误区:exports = {} 重绑定 应 module.exports = {},只给 exports 赋值不会改变导出。

工程实践

  • 新 Node 代码优先 ESM(项目策略允许时)
  • 维护双包时理解 exports 字段条件导出
  • 打包工具会处理 CJS/ESM 转换,但不要盲目

本节总结

CJS 是 Node 历史模块合同;会它是为了生态与迁移,不是为了在新前端项目继续扩散。

自测题

  1. 为什么 require 有缓存?
  2. ESM 浏览器能否直接 require?
参考答案
  1. 避免重复执行与共享实例。
  2. 不能;浏览器原生是 ESM。
创建于 2025/1/1 更新于 2026/7/15