当前位置: 首页 > news >正文

Node.js 模块系统:CJS 与 ESM 详解

文章目录

  • 前言
  • 一、CommonJS (CJS)
  • 二、ESM(ES Module)
  • 三、跨模块互相导入(重要坑点)
  • 四、有关路径的要求
  • 总结

前言

Node.js 两套模块系统:CommonJS(CJS)ESM,由package.json和文件后缀共同决定。JavaScript 最初没有模块系统,Node.js 诞生后自行实现 CommonJS(require/module.exports),用于服务端,并非语言官方标准。随后,ES6 推出官方标准 ESM(import/export),支持浏览器与 Node,支持静态分析,但 Node 为兼容海量旧生态没有直接替换 CommonJS。
于是 Node 两套模块共存,依靠package.json type和文件后缀.mjs/.cjs区分,由此产生各类导入语法差异。


一、CommonJS (CJS)

要求如下:

  • package.json: “type”: “commonjs” 默认值,不写type也是CJS
  • 文件后缀:.js -> CJS; .cjs -> 强制 CJS,无视package.json
  • 语法:require() / module.exports,不能用import/export

导出(helpers.js):

// 方式1:整体导出对象(最常用)module.exports={func1,func2};// 方式2:逐个挂载exports.func1=func1;exports.func2=func2;

导入(main.js):

// ✅ 本地文件,必须 ./ 开头;后缀 .js 可以省略,建议写上const{func1,func2}=require("./helpers.js");// ❌ 错误:不带 ./,node会去node_modules查找npm包const{func1}=require("helpers");
  • require("./helpers")省略后缀也可以,Node 自动补.js/.json
  • 只能用.js后缀,不能命名为.mjs
  • 运行命令:node main.js

二、ESM(ES Module)

  • package.json"type":"module"
    • 文件后缀:.mjs→ 强制 ESM,完全忽略 package.json 的 type 配置
    • 语法:import / export,原生不能直接用require()

重点:.mjs永远 ESM;.cjs永远 CJS;普通.jspackage.jsontype字段。

导出(helpers.js):

// 方式1:声明时直接导出exportasyncfunctionloadPackage(){}// 方式2:末尾集中导出export{loadPackage};// 默认导出exportdefault{loadPackage};

导入(main.mjs):

// ✅本地文件:必须 ./ 开头,**后缀 .js 不能省略!ESM不会自动补后缀**import{loadPackage}from"./helpers.js";// 如果导入的是CJS模块(helpers.js是module.exports),也可以default导入importhelpersfrom"./helpers.js";const{loadPackage}=helpers;// ❌错误1:无 ./,当作npm包import{loadPackage}from"helpers";// ❌错误2:省略后缀,ESM直接报模块找不到import{loadPackage}from"./helpers";

当文件是.mjs,就算 package.json 是commonjs,依然执行 ESM 语法。
运行:node generateTestcase.mjs

三、跨模块互相导入(重要坑点)

  • ESM (.mjs) 导入 CJS (.js):
    允许;CJS 的module.exports对象被 ESM 识别,支持解构导入。
import{loadPackage}from"./helpers.js";// 结构导入// 或者使用CJS的原生require导入import{createRequire}from"module";constrequire=createRequire(import.meta.url);// Enable require in ESMconstpkg=require(pkgPath);
  • CJS 导入 ESM
    CJS 的require()不能直接 require ESM 文件,会报错;只能用动态await import()
// CJS里面加载ESM模块只能动态importconstesmModule=awaitimport("./some-esm.js");

四、有关路径的要求

  • ESM 动态导入,await import其路径必须是file://开头的 URL 字符串指向本地磁盘文件。不接受windows系统的反斜杠。
// ✅ 本地磁盘文件,必须转成file:// URLconsturl=pathToFileURL(absDiskPath).href;constmod=awaitimport(url);constabsFsPath="C:\\Users\\LIly\\file.js";// path.resolve得到,带反斜杠 const url = pathToFileURL(absFsPath).href; // ✅API内部自动处理反斜杠 → file:///C:/... const mod = await import(url);awaitimport("./dir/test.js");// ✅ 只能正斜杠 await import("./dir\\test.js");// ❌ 反斜杠不行,同静态import
// Windows反斜杠转换functionnormalizeSlash(p){if(isWindows()){returnp.replace(/\\/g,'/');}returnp;}
  • ESM 静态导入 import xxx from “xxx”
    静态导入不接受 file:// URL,也不接受操作系统磁盘绝对路径(C:\xxx /home/xxx)。不接受Windows的反斜杠。
    静态导入只有两类合法输入:

裸模块名(npm 包、node 内置模块):lodash、fs/promises

importxfrom"lodash"

相对说明符:./xxx.js、…/xxx.js

importxfrom"./dir\\test.js";// ❌错误!\是字符串转义符号,路径直接错乱importxfrom"./dir/test.js";// ✅只能正斜杠 /
  • require的动态导入,操作系统原生磁盘路径,完全接纳 Windows 反斜杠\,唯一坑:给 require 的相对本地文件路径,必须带上./或者../,否则会被识别成npm包。
letpath="./helper.js";constm=require(path);// ✅完全合法if(flag){require("./other.js")}

总结

Node.js 中 CJS 与 ESM 双模块系统共存,核心区分逻辑是package.jsontype字段 + 文件后缀(.mjs/.cjs

  • CJSrequire/module.exportstype: commonjs(或默认),require对本地文件路径带./,后缀.js可省略。
  • ESMimport/exporttype: module(或.mjs后缀强制),import必须写./后缀不可省略
  • 跨模块导入:ESM 导入 CJS 一般没问题,支持解构导入;反过来 CJS 用require加载 ESM 会直接报错,必须用动态await import()

日常开发先确认项目根目录package.jsontype,再决定用哪个文件后缀和导入语法,可以避免绝大多数模块解析错误。

导入方式类型执行时机静态 / 动态路径完整要求Windows 反斜杠支持相对路径要求
CommonJSrequire()运行时函数调用执行到该行才加载✅动态导入1. npm 包:直接写包名

2. 本地文件:操作系统原生磁盘路径;不需要 file:// 协议
✅兼容\/本地相对文件必须带.//../;不带则识别为 npm 包;后缀可省略
ESM 静态导入import xxx from "xxx"JS 语法解析阶段(代码运行前)✅静态导入1. npm 包:直接写包名

2. 本地文件:仅允许.//../相对说明符;禁止 file://、禁止磁盘绝对路径;只能字符串字面量,不能变量
❌禁止\,只能正斜杠/必须.//../前缀;必须写完整.js后缀,不可省略
ESM 动态导入await import(xxx)Promise 函数调用执行到该行才加载✅动态导入1. npm 包:直接写包名

2. 本地磁盘文件:必须传入file://URL;不能直接传操作系统磁盘路径;支持变量传参
❌不要手动处理\;原始磁盘路径交给pathToFileURL()自动转 URL字面量写./xxx.js规则同静态导入;变量加载本地文件必须转为file://
http://www.jsqmd.com/news/1351581/

相关文章:

  • AI内容去味三步法:从塑料感到高级感的实战指南
  • 【二叉树】LC 104.二叉树的最大深度
  • 维修工程师的示波器实战:11 为什么有些问题,一测反而消失了?
  • AirLLM:在4GB显存的GPU上跑70B大模型,不需要量化
  • 泰安本地防水补漏哪家好?屋顶 卫生间 外墙 地下室 阳台堵漏师傅对比(2026年8月新) - 金信达
  • 0372-Raylib-调色板
  • 符合 GB 标准亲肤鞋品 - 中媒介
  • 2026年heic转png工具盘点:哪几款在线转换和免费方法更省心 - 软件小管家
  • 混合模型ANOVA:固定与随机效应的统计分析实践
  • 前端测试实战:从单元测试到E2E的完整指南
  • 广东做智能照明系统哪家不错? - 中媒介
  • 从《索尼克速度模拟器》新角色更新,解析Roblox游戏的长线运营与玩家留存策略
  • 数字绘画流程深度解析:从角色设计到AI辅助创作实践
  • 宁波靠谱的市政管道CCTV检测批发厂家推荐有哪些 - geo交流
  • 几十页英文行业报告怎么快速看?比逐页翻译更高效的方法
  • AI记忆卡项目:本地部署与测试指南,打造个性化智能助手
  • 【办公类110-04】20260806园园通小班分班后“待处理问题”(批量信息、默认省市区、待添加地址)
  • 从 SEGW 到真实 HTTP 响应,彻底搞懂 SAP Gateway Client 如何测试 OData Service
  • 伊宁纯实木定制与整装怎么选?2026年本地家装市场现状与机构分析 - 优质品牌商家
  • 2026年滚筒线设备源头厂家实力解析:重载/动力/积放式/转弯/伸缩/分拣/不锈钢全场景应用 - 卓企推荐
  • 惠州套餐哪家分量足? - 中媒介
  • 2026湖南影视剪辑培训机构综合评测报告:5家机构全能班赛道全维度对比 - 第三方测评
  • 2026杭州诚信的数字化变电站制造商推荐哪家专业?这份场景化甄选指南教你择优避坑 - geo交流
  • 从 SEGW 到 Fiori Elements,彻底理解 SAP OData 的 Model Provider Classes
  • Word域代码全解析:从核心原理到自动化文档实战
  • 喝酒这4种混搭碰都别碰,每种都在给身体埋雷,第二种骗了很多人
  • 泉州洪濑鸡爪 - 中媒介
  • 2026甄选:超高压手动泵实力厂家——福顿(江苏)工业装备有限公司 - 优企名品
  • 2026年国家级绿色工厂申报政策全解读
  • 从 CDS 元数据到 Fiori 页面,Framework-Specific Annotations 到底是谁在读取