Node.js 模块系统:CommonJS vs ES Modules

Node.js 模块系统:CommonJS vs ES Modules

理解两种模块系统的区别和使用场景

概述

Node.js 支持两种模块系统:

特性 CommonJS ES Modules
关键字 require / module.exports import / export
加载方式 运行时同步加载 编译时静态加载
文件扩展名 .js .mjs.cjs
Node.js 支持 默认支持 v13.2+ 稳定支持

CommonJS (CJS)

导出

javascript 复制代码
// math.js

// 方式1:导出单个值
module.exports = function add(a, b) {
  return a + b;
};

// 方式2:导出多个属性
module.exports.add = function(a, b) { return a + b; };
module.exports.subtract = function(a, b) { return a - b; };

// 方式3:使用 exports(注意:不能直接赋值)
exports.PI = 3.14159;
exports.multiply = function(a, b) { return a * b; };

导入

javascript 复制代码
// app.js

// 导入整个模块
const math = require('./math');
console.log(math.add(1, 2));

// 解构导入
const { add, PI } = require('./math');
console.log(PI);

// 导入内置模块
const fs = require('fs');
const path = require('path');

// 导入第三方模块
const express = require('express');

package.json 配置

json 复制代码
{
  "type": "commonjs"  // 默认,可省略
}

ES Modules (ESM)

导出

javascript 复制代码
// math.js 或 math.mjs

// 命名导出
export const PI = 3.14159;

export function add(a, b) {
  return a + b;
}

export function subtract(a, b) {
  return a - b;
}

// 默认导出
export default function(a, b) {
  return a + b;
}

// 或者集中导出
const PI = 3.14159;
const add = (a, b) => a + b;
export { PI, add };

导入

javascript 复制代码
// app.js 或 app.mjs

// 默认导入
import add from './math.js';

// 命名导入
import { add, subtract, PI } from './math.js';

// 重命名导入
import { add as sum } from './math.js';

// 导入所有
import * as math from './math.js';

// 副作用导入(只执行,不导入)
import './polyfill.js';

package.json 配置

json 复制代码
{
  "type": "module"
}

或使用 .mjs 扩展名(自动启用 ESM)


主要区别

1. 加载时机

javascript 复制代码
// CommonJS - 运行时加载
const math = require('./math');  // 同步执行

// ES Modules - 编译时加载
import { add } from './math';    // 静态分析

2. 导出方式

javascript 复制代码
// CommonJS - 值拷贝
let count = 0;
module.exports = { count };
count = 1;  // 导出值不变,仍是 0

// ES Modules - 动态引用
export let count = 0;
count = 1;  // 导出值同步更新为 1

3. this 指向

javascript 复制代码
// CommonJS - this 指向 module.exports
console.log(this === module.exports);  // true

// ES Modules - this 是 undefined
console.log(this);  // undefined

实战示例

CommonJS 项目结构

复制代码
project/
├── package.json (默认 commonjs)
├── utils/
│   └── math.js
└── app.js
javascript 复制代码
// utils/math.js
module.exports.add = (a, b) => a + b;

// app.js
const { add } = require('./utils/math');
console.log(add(1, 2));

ES Modules 项目结构

复制代码
project/
├── package.json ("type": "module")
├── utils/
│   └── math.js
└── app.js
javascript 复制代码
// utils/math.js
export const add = (a, b) => a + b;

// app.js
import { add } from './utils/math.js';
console.log(add(1, 2));

混用技巧

在 CJS 中使用 ESM

javascript 复制代码
// 需要 dynamic import
async function loadModule() {
  const { add } = await import('./math.mjs');
  return add(1, 2);
}

在 ESM 中使用 CJS

javascript 复制代码
// 可以直接导入
import express from 'express';
import { readFile } from 'fs';

选择建议

使用 CommonJS 当:

  • 需要动态加载模块
  • 兼容旧项目或工具
  • 编写简单的脚本工具

使用 ES Modules 当:

  • 开始新项目
  • 使用现代前端框架(React、Vue)
  • 需要_tree-shaking_ 优化
  • 编写可同时在浏览器和 Node.js 运行的代码

快速参考

javascript 复制代码
// CommonJS
module.exports = { value: 1 };
const { value } = require('./file');

// ES Modules
export const value = 1;
import { value } from './file.js';

总结

  • CommonJS:Node.js 传统方式,成熟稳定
  • ES Modules:现代标准,未来趋势
相关推荐
终将老去的穷苦程序员12 小时前
npm : 无法加载文件 C:\Program Files\nodejs\npm.ps1,因为在此系统上禁止运行脚
前端·npm·node.js
之歆12 小时前
Day10_Node.js 与 Express 开发实战指南:从零到一构建专业级 Web 服务
前端·node.js·express
之歆1 天前
Node.js 与 NPM 包管理完全指南
前端·npm·node.js
12点一刻1 天前
npx 使用入门教程:是什么、怎么用、和 npm 有什么区别
前端·npm·node.js
Sca_杰1 天前
速通抖音开放平台API-生活服务商应用
javascript·node.js
console.log('npc')1 天前
核心实战篇 生成式 UI+A2UI 协议 + 全栈 Agent 项目落地
node.js·react·#生成式ui·a2ui协议·ui agent·ai前端实战
Rain5091 天前
1.3. Next.js与Nest.js在AI数据分析中的角色
前端·javascript·人工智能·后端·数据分析·node.js·ai编程
向上的车轮1 天前
TypeORM 1.0 正式发布:新一代 Node.js ORM 框架全面解析
typescript·node.js·typeorm
晚风叙1 天前
使用Gemini快速修复Node.js 代码报错
node.js
之歆1 天前
Node.js HTTP 模块深度解析与实战指南
网络协议·http·node.js