CommonJS 与 ESM 全面对比:原理、区别及项目坑点
一、定义
CommonJS(简称 CJS)
-
Node.js 早期自己发明的模块规范
-
专为服务端设计
-
浏览器原生不支持
-
后缀
.js默认就是 CJS(package.json 没有type:module)
ESM(ES Module)
-
JavaScript 官方语言标准
-
ES6 推出
-
浏览器、Node.js 统一标准
-
项目
package.json写了:"type": "module"整个项目所有
.js文件 强制变成 ESM
二、核心语法对比
1. 导入导出
CommonJS
// 导出
module.exports = { name: "张三" };// 导入
const cfg = require("./config.js");
ESM
// 导出
export default { name: "张三" };// 导入
import cfg from "./config.js";
三、最关键 7 大区别(必须记住)
1. 语法不同
-
CJS:
require/module.exports -
ESM:
import/export
2. 有没有缓存
CommonJS
-
require加载模块会缓存 -
可以手动清缓存:
delete require.cache[路径]
ESM
-
import也会缓存,而且不让你清缓存 -
**没有
require.cache给你用 -
想热更新配置,只能:
读文件文本 → vm 执行
3. 有没有 dirname /filename
CommonJS
自带:
console.log(__dirname);
//D:\myCode\pqc-reader 「文件夹路径」console.log(__filename);
//D:\myCode\pqc-reader\config.js 「完整绝对路径 + 文件名」
ESM
没有!必须自己手动算:
import { fileURLToPath } from 'url';
import path from 'path';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
//import.meta.url => 当前 JS 文件的地址(文件网址file:///D:/myCode/...)
// fileURLToPath => 把上面的 “文件网址” 转成 “电脑正常路径”
//path.dirname = > 拿到这个文件所在的 “文件夹路径”
4. 能不能用顶层 await
CommonJS
不支持,只能在函数里用 async
ESM
支持顶层 await
const cfg = await loadConfig();
5. 加载方式
CommonJS
同步加载
适合服务端本地文件
ESM
异步加载
设计给浏览器用,Node 也兼容
6. 文件后缀规则
CommonJS
导入可以省略后缀:
require("./config");
ESM
必须写全后缀
import cfg from "./config.js"; // 必须 .js
7. 浏览器支持
CommonJS
浏览器完全不认识,必须打包(webpack/vite)
ESM
浏览器原生直接支持
<script type="module" src="index.js"></script>
总结:
最简单记忆口诀
-
CommonJS:Node 老规矩,用 require,有 __dirname,能清缓存,同步加载
-
ESM:官方新标准,用 import,无 __dirname,不能清缓存,支持顶层 await,前后端通用
