Node系列 · Node基础:ES 模块化
Node系列 · Node基础ES 模块化CommonJS 是 Node 默认的模块系统但 ESM 才是 ECMAScript 规范本身。理解 ESM 的异步加载 静态分析特性就能解释为什么它能 tree-shaking、为什么必须写文件后缀、为什么与 CJS 互操作时要写default解构。一、ESM 与 CommonJS 的关键差异维度CommonJSESM规范归属Node 自定义实现ECMAScript 标准加载方式同步、运行时异步、静态分析关键字require/module.exportsimport/export文件后缀自动补全必须显式写Tree-shaking困难运行时才知道导出什么天然支持顶层await不支持支持Node 14.8适用老项目、Node CLI、配置文件现代前端、库发布、tree-shaking 场景::: infoESM 在 Node 14 已经很稳定。新项目默认 ESM维护老 CJS 项目不必迁移除非需要 tree-shaking 或与.mjs包互操作。:::二、启用 ESM 的两种方式2.1 用.mjs后缀文件后缀.mjs强制按 ESM 解析与package.json配置无关project/ ├── package.json └── app.mjsimport { readFile } from node:fs/promises; const data await readFile(./config.json, utf-8);2.2 在package.json加type: module整个项目除.cjs文件按 ESM 解析{ name: my-app, version: 1.0.0, type: module }project/ ├── package.json └── src/ ├── index.js ← 现在按 ESM 解析 └── util.cjs ← 显式按 CJS 解析即便在 typemodule 项目下::: tip混用场景项目主入口是 ESM但某个老依赖只能以 CJS 形式发布——把那个文件改成.cjs后缀即可。:::三、import语法3.1 命名导入 / 默认导入// 命名导出可以有多个 export const PI 3.14; export function add(a, b) { return a b; } // 默认导出一个模块只能有一个 export default class User { constructor(name) { this.name name; } }// 命名导入必须用花括号 import { PI, add } from ./export-demo.js; // 默认导入花括号外可以任意命名 import User from ./export-demo.js; // 混合导入 import User, { PI, add } from ./export-demo.js; // 重命名导入 import { add as sum } from ./export-demo.js; // 整体导入为一个命名空间对象 import * as utils from ./export-demo.js; console.log(utils.PI); // 3.143.2 路径规则ESM 下import的路径有 3 个强约束写法是否合法说明import x from ./foo.js✅必须带.js后缀import x from ./foo❌必须显式后缀CJS 会自动补全ESM 不会import x from foo⚠️走 npm 包解析同 CJS 的node_modules查找import x from node:fs✅Node 内置模块用node:前缀更规范::: warningESM 不补全后缀。老 CJS 项目里到处是require(./foo)迁到 ESM 后必须改成import x from ./foo.js。否则运行时报ERR_MODULE_NOT_FOUND。:::四、export语法4.1 命名导出 vs 默认导出// 命名导出导入时必须用同名 export const name Alice; export function greet() {} // 默认导出导入时任意命名 export default function () { return default function; }4.2 重导出聚合模块barrel 文件一个文件聚合多个子模块的导出export { Button } from ./Button.js; export { Input } from ./Input.js; export { Select } from ./Select.js;使用方只要import { Button } from ./components/index.js即可。4.3 重新导出并重命名export { foo as bar } from ./source.js; // 导出 source 的 foo但消费方叫 bar五、ESM 互操作实际项目里经常要 CJS 和 ESM 混用两种场景的互操作语法不一样。5.1 在 ESM 中importCJS 模块CJS 模块的module.exports整体被 ESM 当成默认导出// 一个普通 CJS 模块 module.exports { hello: () world, PI: 3.14, };// 在 ESM 里引用 CJS import cjs from ./cjs-module.js; console.log(cjs.hello()); // world console.log(cjs.PI); // 3.14如果 CJS 用module.exports.something ...拆成多个具名导出ESM 也能通过import { something }解构exports.foo 1; exports.bar 2;import { foo, bar } from ./cjs-named.js;::: warningNode 不做 CJS 的静态分析import { something }引用一个 CJS 模块时实际是运行后从module.exports解构。如果 CJS 用了动态赋值比如if (cond) exports.x ...ESM 拿不到。:::5.2 在 CJS 中requireESM 模块不允许——CJS 是同步加载ESM 是异步加载。Node 提供了两种方式绕过动态import()表达式import()不是声明是表达式返回 Promiseasync function load() { const { add } await import(./esm-module.mjs); console.log(add(1, 2)); // 3 } load();createRequire构造一个 CJS 风格的 require只用于加载 CJS 模块不能 require 一个 ESM。5.3 互操作矩阵调用方 \ 被调用方CJS 模块ESM 模块CJS 模块require()✅❌ 用动态await import()ESM 模块import default from ...✅import { ... } from ...✅六、顶层awaitESM 模块顶层允许直接await——这是 CJS 完全没有的能力const response await fetch(https://api.example.com/data); const data await response.json(); console.log(data);限制与注意点必须用在 ESM 模块.mjs或package.jsontypemodule模块的加载完成变成异步——所有依赖它的模块都必须等待不要在顶层await不会立即 resolve 的 Promise否则所有 import 它的模块都会被卡住// ❌ 危险长时间阻塞 await new Promise((resolve) setTimeout(resolve, 60_000)); console.log(所有人都得等我 60 秒);::: tip顶层await的最佳场景读配置文件作为模块初始化的依据一次性预热缓存 / 拉取启动数据单实例服务启动前的健康检查不适合长任务用户请求、消息队列消费不确定的资源获取:::七、ESM 的加载流程ESM 的异步、静态分析体现在加载流程文件系统Node ESM Loader入口 .mjs文件系统Node ESM Loader入口 .mjs所有依赖加载完成后才执行任意模块import ./a.js静态分析入口文件找出所有 import 语句并行读取 ./a.js / ./b.js / ./c.js文件内容构建依赖图拓扑排序执行入口文件CJS 是同步串行require(./a.js)一进来就读文件、执行完才返回。ESM 是并行预加载所有依赖文件并行读最后按依赖图顺序执行。八、ESM 与 CJS 的选择建议场景推荐理由新建 Node 项目ESM规范方向、生态趋势、tree-shaking写一个发到 npm 的库ESM同时支持 CJS via dual package下游用户两种生态都有维护老 CJS 项目继续 CJS迁移成本高收益有限CLI 工具CJS / ESM 都行单文件执行无依赖必须用同步requireCJSESM 不支持同步加载必须用__dirname/__filenameCJS或 ESM 下用import.meta.url转换见下一节九、ESM 下的__dirname等价物ESM 没有__dirname/__filename但能用import.meta拿到当前模块的 URLimport { fileURLToPath } from node:url; import { dirname } from node:path; const __filename fileURLToPath(import.meta.url); const __dirname dirname(__filename);import.meta携带了当前模块的元信息属性含义import.meta.url当前模块的file://URLimport.meta.dirname当前模块目录的路径Node 21.2import.meta.filename当前模块文件的路径Node 21.2import.meta.resolve(specifier)解析一个 specifier 为 URLNode 20.6Node 21.2 直接提供了import.meta.dirname和import.meta.filename不需要再fileURLToPath。十、常见错误错误信息原因解决ERR_MODULE_NOT_FOUND路径缺后缀或拼错写完整./foo.js检查文件名The requested module ./foo does not provide an export named XCJS 模块没module.exports.X改成import foo from ./foo默认导入await is only valid in async functions顶层 await 用在 CJS改.mjs或加type: moduleCannot use import statement outside a moduleCJS 文件里写了import改.mjs后缀或用requirerequire() of ES Module ... not supportedCJS 里同步 require ESM改用await import()十一、小结ESM 是 ECMAScript 标准CJS 是 Node 自定义实现。新项目默认 ESM启用 ESM 两种方式.mjs后缀 /package.json typemoduleESM 必须写文件后缀./foo.jsCJS 不会自动补全——这是迁移最常见的报错互操作ESMimportCJS ✅CJSrequireESM ❌用动态import()顶层await是 ESM 独有但只用于启动期一次性任务Node 21.2 提供import.meta.dirname/import.meta.filename简化 ESM 下的路径处理

相关新闻

视频动作迁移保姆级教程:三步让静态照片跳出你的舞蹈

视频动作迁移保姆级教程:三步让静态照片跳出你的舞蹈

视频动作迁移保姆级教程:三步让静态照片跳出你的舞蹈 【免费下载链接】ComfyUI-MimicMotionWrapper 项目地址: https://gitcode.com/gh_mirrors/co/ComfyUI-MimicMotionWrapper 你有没有遇到过这样的尴尬时刻——精心拍摄的舞蹈视频,却只能由同一…

2026/8/15 19:58:14 阅读更多 →
3分钟搞定GitHub Desktop汉化:这款免费开源工具让英文界面秒变全中文

3分钟搞定GitHub Desktop汉化:这款免费开源工具让英文界面秒变全中文

3分钟搞定GitHub Desktop汉化:这款免费开源工具让英文界面秒变全中文 【免费下载链接】GitHubDesktop2Chinese GithubDesktop语言本地化(汉化)工具 【GitHub桌面客户端中文汉化】 项目地址: https://gitcode.com/gh_mirrors/gi/GitHubDesktop2Chinese 如果你…

2026/8/15 19:58:14 阅读更多 →
手把手用OpenGlass从零搭建AI智能眼镜:不到25美元解锁人物识别与实时翻译

手把手用OpenGlass从零搭建AI智能眼镜:不到25美元解锁人物识别与实时翻译

手把手用OpenGlass从零搭建AI智能眼镜:不到25美元解锁人物识别与实时翻译 【免费下载链接】OpenGlass Turn any glasses into AI-powered smart glasses 项目地址: https://gitcode.com/GitHub_Trending/op/OpenGlass 副标题:一份零件清单加三条命…

2026/8/15 19:58:14 阅读更多 →

最新新闻

Draw.io Mermaid插件安装与实战指南:文本驱动图表一步到位

Draw.io Mermaid插件安装与实战指南:文本驱动图表一步到位

Draw.io Mermaid插件安装与实战指南:文本驱动图表一步到位 【免费下载链接】drawio_mermaid_plugin Mermaid plugin for drawio desktop 项目地址: https://gitcode.com/gh_mirrors/dr/drawio_mermaid_plugin Draw.io Mermaid插件是为draw.io桌面版量身打造的…

2026/8/15 20:45:32 阅读更多 →
Docker-SSH过滤器使用技巧:精准定位目标容器的方法

Docker-SSH过滤器使用技巧:精准定位目标容器的方法

Docker-SSH过滤器使用技巧:精准定位目标容器的方法 【免费下载链接】docker-ssh SSH Server for Docker containers ~ Because every container should be accessible 项目地址: https://gitcode.com/gh_mirrors/do/docker-ssh Docker-SSH是一款专为容器环境…

2026/8/15 20:45:32 阅读更多 →
atc-react未来路线图:即将发布的5大功能预测与使用场景

atc-react未来路线图:即将发布的5大功能预测与使用场景

atc-react未来路线图:即将发布的5大功能预测与使用场景 【免费下载链接】atc-react A knowledge base of actionable Incident Response techniques 项目地址: https://gitcode.com/gh_mirrors/at/atc-react atc-react作为一款专注于事件响应技术的知识库项目…

2026/8/15 20:45:32 阅读更多 →
Template7源码解析:揭开JavaScript模板引擎的工作原理

Template7源码解析:揭开JavaScript模板引擎的工作原理

Template7源码解析:揭开JavaScript模板引擎的工作原理 【免费下载链接】template7 Mobile-first JavaScript template engine 项目地址: https://gitcode.com/gh_mirrors/te/template7 Template7是一款轻量级的Mobile-first JavaScript模板引擎,它…

2026/8/15 20:45:32 阅读更多 →
5步吃透Godot信号系统:场景通信从此不再乱

5步吃透Godot信号系统:场景通信从此不再乱

5步吃透Godot信号系统:场景通信从此不再乱 【免费下载链接】godot Godot Engine – Multi-platform 2D and 3D game engine 项目地址: https://gitcode.com/GitHub_Trending/go/godot Godot Engine 是一款免费开源、支持 2D 与 3D 开发的跨平台游戏引擎&…

2026/8/15 20:45:32 阅读更多 →
如何快速上手keras-language-modeling?3分钟搭建你的第一个语言模型

如何快速上手keras-language-modeling?3分钟搭建你的第一个语言模型

如何快速上手keras-language-modeling?3分钟搭建你的第一个语言模型 【免费下载链接】keras-language-modeling :book: Some language modeling tools for Keras 项目地址: https://gitcode.com/gh_mirrors/ke/keras-language-modeling keras-language-model…

2026/8/15 20:44:32 阅读更多 →

日新闻

内景 空间站内部 中国空间站 太空 内仓

内景 空间站内部 中国空间站 太空 内仓

本项目为前几天收费帮学妹做的一个项目,在工作环境中基本使用不到,但是很多学校把这个当作编程入门的项目来做,故分享出本项目供初学者参考。 一、项目描述 空间站内部 中国空间站 太空 内仓 地址:本地PC端运行(或Web…

2026/8/15 0:00:30 阅读更多 →
重新定义数据接口:3个突破性场景让通达信数据读取更智能

重新定义数据接口:3个突破性场景让通达信数据读取更智能

重新定义数据接口:3个突破性场景让通达信数据读取更智能 【免费下载链接】mootdx 通达信数据读取的一个简便使用封装 项目地址: https://gitcode.com/GitHub_Trending/mo/mootdx 当我们面对海量金融数据时,传统的数据获取方式往往让我们陷入困境—…

2026/8/15 0:00:30 阅读更多 →
一文读懂快消WMS怎么选?2026年国内外10大主流WMS品牌盘点

一文读懂快消WMS怎么选?2026年国内外10大主流WMS品牌盘点

快消品(FMCG)是流通速度较快、竞争较为激烈的行业之一。一瓶饮料从出厂到消费者手中,往往只有几十天甚至几天的周转窗口。这决定了快消行业的仓储管理系统(WMS)与制造业、电商行业存在明显区别:它不仅需要管…

2026/8/15 0:02:30 阅读更多 →

周新闻

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁 【免费下载链接】baidupankey 在线查询网盘提取码(维护中 rm repo) 项目地址: https://gitcode.com/gh_mirrors/ba/baidupankey 你是否曾经在深夜寻找一份重要资料&#x…

2026/8/13 2:38:34 阅读更多 →
如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南 【免费下载链接】chinese_license_plate_generator 中国车牌生成器 项目地址: https://gitcode.com/gh_mirrors/ch/chinese_license_plate_generator 中国车牌生成器是一个基于Python的开源项目&#xff0c…

2026/8/15 12:59:14 阅读更多 →
收藏!小白程序员轻松入门大模型,从Harness工程开始实践

收藏!小白程序员轻松入门大模型,从Harness工程开始实践

文章强调学习大模型不应只关注模型本身,而应重视模型外的系统搭建,即Harness。提出AgentModelHarness的实用公式,详细介绍Harness的四个层次:持久化层、执行层、控制层和观察与验证层。文章还探讨了上下文工程、工具设计、AGENTS.…

2026/8/13 10:41:51 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/14 13:40:53 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/14 14:06:45 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/15 2:35:29 阅读更多 →