博客主页:瑕疵的CSDN主页
Gitee主页:瑕疵的gitee主页
⏩ 文章专栏:《热点资讯》
目录
Node.js作为JavaScript运行环境,其模块系统经历了从CommonJS到ES Modules的演变。CommonJS是Node.js早期采用的模块规范,而ES Modules(ESM)则是ECMAScript官方标准,两者在语法、加载机制和性能上存在显著差异。
- 同步加载:通过
require()动态加载模块,适合服务器端同步编程模型。 - 文件作用域:每个文件是一个独立模块,通过
module.exports导出接口。 - 缓存机制:模块首次加载后会被缓存,后续引用直接返回缓存结果。
示例代码:
// math.js
exports.add = (a, b) => a + b;
// app.js
const math = require('./math');
console.log(math.add(2, 3)); // 输出5
- 静态加载:通过
import/export声明式语法,模块依赖关系在编译时确定。 - 异步支持:原生支持异步加载,通过
import()动态导入。 - 树摇优化:打包工具可移除未使用的代码,减少最终输出体积。
示例代码:
// math.js
export const add = (a, b) => a + b;
// app.js
import { add } from './math.js';
console.log(add(2, 3)); // 输出5
CommonJS由于同步加载特性,在模块初始化时会立即执行代码,可能导致启动时间较长。ESM通过延迟加载和按需解析,理论上能减少初始内存占用。

- CommonJS:每次
require()调用都会触发文件系统读取(即使模块已缓存)。 - ESM:通过静态分析提前解析依赖关系,避免重复加载。
测试代码示例(模块重复加载场景):
// CommonJS
for (let i = 0; i < 1000; i++) {
const { add } = require('./math');
add(i, i);
}
// ESM
import { add } from './math.js';
for (let i = 0; i < 1000; i++) {
add(i, i);
}
ESM通过import()支持动态加载,适合按需加载场景,而CommonJS需借助第三方库(如require.ensure)实现类似功能。
// ESM动态加载
button.addEventListener('click', async () => {
const module = await import('./lazy-module.js');
module.init();
});
- 避免重复加载:将
require()调用移至模块顶层。 - 利用缓存:通过
require.cache手动管理模块缓存。 - 合并模块:减少小文件模块数量,降低文件系统开销。
- 静态依赖预解析:在构建阶段通过工具(如Webpack)分析依赖树。
- 按需加载:结合
import()与路由懒加载,减少初始加载体积。 - 启用TypeScript:通过类型检查提前发现模块引用错误。
在大型项目中逐步迁移时,可通过package.json配置"type": "module"区分模块类型,并使用createRequire桥接CommonJS与ESM。
{
"name": "my-project",
"type": "module",
"main": "./src/index.js"
}
随着Node.js v18+对ESM的全面支持,社区工具链(如Vite、Rollup)已深度优化ESM生态。建议新项目优先采用ESM,同时通过以下方式提升性能:
- 使用
esbuild进行快速构建; - 配置
node --experimental-specifier-resolution优化模块解析; - 利用浏览器原生ESM支持实现客户端-服务端同构。

CommonJS与ESM各有适用场景:
- CommonJS:适合传统命令行工具、插件系统等强同步依赖场景;
- ESM:适合现代Web应用、微前端架构等需要动态加载和性能优化的场景。
开发者应根据项目需求选择模块系统,并通过工具链优化实现最佳性能表现。
浙公网安备 33010602011771号