Node.js 的模块系统是其核心功能之一,它允许开发者将代码组织成可重用的模块。在 Node.js 的发展历程中,主要经历了两种模块系统:CommonJS 和 ES Modules(ESM)。本文将深入探讨这两种模块系统的特点、差异以及如何在 Node.js 中使用它们。
CommonJS 模块系统
CommonJS 是 Node.js 最初采用的模块系统,它采用同步加载的方式,非常适合服务器端环境。
基本语法
javascript
// 导出模块
module.exports = {
function1,
function2
};
// 或者
exports.function1 = function1;
exports.function2 = function2;
// 导入模块
const myModule = require('./myModule');
特点
- 同步加载:模块在 require 时同步加载和执行
- 运行时解析:模块路径在运行时解析
- 动态导入:可以在代码的任何位置使用 require
- 缓存机制:模块在第一次加载后会被缓存
ES Modules (ESM)
ES Modules 是 ECMAScript 标准的一部分,随着 Node.js 的发展,逐渐被引入并成为官方支持的模块系统。
基本语法
javascript
// 导出模块
export function function1() { /* ... */ }
export const constant1 = 'value';
// 或者
export default {
function1,
constant1
};
// 导入模块
import { function1, constant1 } from './myModule.js';
import myModule from './myModule.js';
特点
- 静态分析:导入导出语句必须在顶层作用域,可以被静态分析
- 异步加载:支持异步加载模块
- 严格模式:默认在严格模式下执行
- 浏览器兼容:与浏览器端的 ES Modules 保持一致
主要差异对比
特性 | CommonJS | ES Modules |
---|---|---|
加载方式 | 同步 | 异步 |
解析时机 | 运行时 | 静态分析(编译时) |
导入语法 | require() | import |
导出语法 | module.exports/exports | export/export default |
动态导入 | 支持 | 通过 import() 函数支持 |
顶层 await | 不支持 | 支持 |
文件扩展名 | 可省略 | 必须包含(.js/.mjs) |
严格模式 | 默认非严格 | 默认严格 |
在 Node.js 中使用 ES Modules
要在 Node.js 中使用 ES Modules,有以下几种方式:
- 使用
.mjs
文件扩展名 - 在
package.json
中设置"type": "module"
- 使用
--input-type=module
标志
json
// package.json
{
"type": "module"
}
互操作性
Node.js 提供了两种模块系统之间的互操作性:
- 在 ES Modules 中导入 CommonJS 模块:可以直接使用 import 语法
- 在 CommonJS 中导入 ES Modules:需要使用动态 import() 函数
javascript
// 在 CommonJS 中导入 ES Module
(async () => {
const esModule = await import('./es-module.mjs');
})();
最佳实践
- 新项目:推荐使用 ES Modules,因为它是 ECMAScript 标准且功能更强大
- 现有项目:如果项目基于 CommonJS,可以逐步迁移或保持现状
- 库开发:考虑同时支持两种模块系统以最大化兼容性
总结
Node.js 的模块系统从 CommonJS 发展到 ES Modules,反映了 JavaScript 生态系统的演进。了解这两种模块系统的特点和差异,有助于开发者根据项目需求做出合理选择。随着 Node.js 对 ES Modules 支持的不断完善,ES Modules 正逐渐成为 Node.js 模块系统的未来方向。