Node.js 编程实战:CommonJS 与ES6 模块

在构建 Node.js 项目时,"模块化"是开发者必须掌握的基础能力。随着生态的发展,Node.js 同时支持两套模块体系:CommonJS(CJS)ES6 Module(ESM)。它们的出现背景不同,语法也不同,甚至在行为上存在显著差异。对模块系统理解得越深,构建大型项目时就越得心应手。

本文将从模块概念、使用方式、差异点到实际项目中的选择策略,帮助你系统掌握 Node.js 中两种模块体系的核心逻辑。


一、模块化的意义

在没有模块机制前,代码需要通过 script 标签或全局变量共享,容易发生命名污染、文件耦合和维护困难。模块化解决了这些痛点,带来了:

  • 清晰的项目结构
  • 代码隔离与作用域安全
  • 可复用与可维护的代码组织方式
  • 更易扩展的大型工程能力

Node.js 天生以模块为单位组织代码,因此掌握模块系统是学习 Node.js 的必备基础。


二、CommonJS:Node.js 默认模块系统

CommonJS 是 Node.js 诞生之初采用的模块机制,主要特点是:

  • 同步加载
  • 运行时执行
  • 使用 require 导入
  • 使用 module.exports 导出

Node.js 的核心模块(fs、path 等)都基于 CommonJS 构建。

1. CommonJS 导入

js 复制代码
const fs = require("fs");

2. CommonJS 导出

js 复制代码
module.exports = {
  sum(a, b) {
    return a + b;
  }
};

也可以使用简写:

js 复制代码
exports.test = () => {};

CommonJS 是"执行时加载",模块在第一次被 require 时执行并缓存。


三、ES6 模块:现代 JavaScript 模块体系

ES6 Module 是 ECMAScript 官方推出的模块标准,旨在统一前后端 JavaScript 的模块化规范。

特点包括:

  • 静态解析(编译时确定导入导出)
  • 支持 tree-shaking
  • 语法更简洁
  • 异步加载能力更好

1. ES6 导入

js 复制代码
import fs from "fs";

2. ES6 导出

默认导出:

js 复制代码
export default function () {}

命名导出:

js 复制代码
export function sum(a, b) {}
export const PI = 3.14;

ESM 具有可在编译阶段分析依赖的优势,使其更符合现代工程化趋势。


四、CJS 与 ESM 之间的差异

虽然两者都能实现模块化,但它们在机制和行为上有明显不同。

1. 加载方式不同

  • CommonJS:同步加载
  • ES Module:异步且静态解析

因此 ESM 更适合浏览器和未来的 Node.js 优化场景。


2. 语法差异

功能 CommonJS ES6 Module
导入 require() import
导出 module.exports export
默认导出 module.exports = obj export default obj

3. 导入路径限制不同

CommonJS 可以省略文件后缀:

js 复制代码
require("./util");

ESM 必须写完整后缀:

js 复制代码
import "./util.js";

4. this 指向不同

  • CommonJS 中的 this 指向 module.exports
  • ES Module 中的 thisundefined

反映了两者的设计理念差异。


5. 顶层 await 支持

ESM 支持在模块顶层使用 await

js 复制代码
const data = await fetchData();

而 CommonJS 不支持,只能通过 async 包裹。


五、在 Node.js 中如何选择模块体系?

目前 Node.js 同时支持 CJS 与 ESM,两者各有适用场景。

1. 选择 CommonJS 的场景

  • 旧项目或需要兼容早期 Node.js
  • 使用大量历史库,CJS 生态更完整
  • 工具类、脚本类程序,启动速度要求高

CommonJS 更稳定,也更符合 Node.js 的传统开发模式。


2. 选择 ES6 Module 的场景

  • 新项目倾向现代规范
  • 更好配合 bundler(如 Webpack、Vite)
  • 需要顶层 await
  • 项目需要压缩 tree-shaking

现代项目逐渐转向 ESM,也符合前后端统一的趋势。


六、如何配置 Node.js 以使用 ES Module?

Node.js 默认使用 CommonJS,如果需要启用 ES Module,可以采用两种方式:

方式 1:将 package.json 配置为 ES Module

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

方式 2:使用 .mjs 扩展名

复制代码
app.mjs
utils.mjs

两者都可以,让 Node.js 按 ESM 规范解析文件。


七、在同一项目中混用 CJS 和 ESM

在某些情况下,你可能需要混用模块。

从 CJS 导入 ESM

需要异步动态导入:

js 复制代码
(async () => {
  const module = await import("./esm-module.js");
})();

从 ESM 导入 CJS

支持默认导入:

js 复制代码
import pkg from "./cjs-module.cjs";

混用不推荐作为长期方案,但在迁移阶段非常常见。


八、总结

CommonJS 和 ES6 Module 代表了 Node.js 的过去与未来:

  • CommonJS 稳定、成熟,是 Node.js 的传统基础。
  • ES6 Module 现代、可优化,是未来趋势。

两者在加载方式、语法、依赖解析、工具链支持等方面都有不同。理解两者的设计逻辑,才能在项目中做出正确选择。

在实际开发中:

  • 新项目优先 ESM
  • 旧项目继续使用 CJS 更稳
  • 混用时注意异步 import 与导入路径规则

掌握模块系统,是深入 Node.js 的重要一步。


相关推荐
用户67570498850225 分钟前
Celery 太重了?这可能是你一直在找的 asyncio 任务队列
后端·python·消息队列
Cloud_Shy61826 分钟前
Python 数据分析基础入门:《Excel Python:飞速搞定数据分析与处理》学习笔记系列(第十一章 Python 包跟踪器 下篇)
前端·后端·python·数据分析·excel
神奇小汤圆1 小时前
为什么Redis能称霸缓存界?揭秘其每秒10万+读写的核心技术
后端
楼田莉子1 小时前
C++17新特性:结构化绑定/inline变量/if相关的变化
c++·后端·学习
无限进步_1 小时前
【C++】C++11的类功能增强与STL变化
java·前端·数据结构·c++·后端·算法
字节跳动数据库1 小时前
TRAE × 火山引擎 Supabase:为你的 AI 应用装上“数据引擎”
人工智能·后端
濮水大叔1 小时前
告别 Django Admin!这个 NodeJS 全栈框架让你在 DTO 中直接配置 Table/Form 渲染
前端·typescript·node.js
用户6757049885021 小时前
Python 统一大业:uv 如何整合 Pip、Pyenv 和 Venv?
后端·python
倚栏听风雨1 小时前
Spring AI 流式工具调用:你的 TOOL_CALLS Chunk 去哪了?
后端
归故里1 小时前
harmony-next.skills 为 AI 而生!
前端·后端·github