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:现代标准,未来趋势
相关推荐
Once_day2 小时前
node.js(1)ubuntu安装node和npm
ubuntu·npm·node.js
oh LAN2 小时前
Windows 11 多 Node.js 版本切换教程
node.js
程序员讲BPM工作流3 小时前
npm非全局方式安装小龙虾OpenClaw
前端·npm·node.js
田井中律.3 小时前
Node.js的安装教程(完整图文)
node.js
何中应3 小时前
CentOS7安装高版本Node.js
前端·centos·node.js
南宫码农3 小时前
Node.js和npm本地安装详细教程(全系统适配)
前端·npm·node.js
一叶萩Charles4 小时前
MCP 实战:国家统计局数据查询 Server 从开发到发布
javascript·人工智能·python·node.js
认真的小羽❅4 小时前
Node.js完全指南:从入门到精通
node.js
willow4 小时前
Nodejs使用
node.js