Node.js 原生 ES 模块使用指南:从启用到最佳实践

作者:慢半拍时间:2026-10-22 08:31:23浏览:632

本文详解如何在 Node.js 8.5.0 及以上版本中启用并使用原生 ES 模块。内容包括通过命令行选项开启支持、.mjs 文件编写示例、与 CommonJS 模块的互操作性限制(如默认导出、禁止 require)、模块标识符 URL 化规则以及动态导入和 import.meta 等未来特性展望。

Node.js 原生 ES 模块概述

自 Node.js 版本 8.5.0 起,系统开始内置支持原生 ES 模块功能,用户可通过添加特定的命令行标志来激活该特性。这一重要功能的实现主要归功于开发者 Bradley Farias 的贡献。

基础代码演示

1. 基础演示

以下示例项目采用如下目录结构进行组织:


esm-demo/
 lib.mjs
 main.mjs

文件 lib.mjs 的内容如下:


export function add(x, y) {
 return x + y;
}

文件 main.mjs 的代码如下:


import {add} from './lib.mjs';
console.log('Result: '+add(2, 3));

执行演示的命令行操作如下:


$ node --experimental-modules main.mjs
Result: 5

ES 模块使用注意事项

2. 关键注意事项清单

关于 ES 模块的使用,需关注以下几点:

· 目前尚不支持动态导入模块。不过,针对动态 import() 语法的开发工作正在推进中,预计不久后将获得官方支持。

· 模块内部不存在 __dirname 和 __filename 等传统元变量。取而代之的是一个名为 “import.meta” 的提案,其预期用法如下所示:


console.log(import.meta.url);

· 当前所有模块标识符均被视为 URL(这是 Node.js 引入的新特性):

· 文件路径:需包含文件扩展名的相对路径,例如 ../util/tools.mjs

· 库引用:不使用文件扩展名,也不包含路径信息,如 lodash

· 关于如何更好地使 npm 库在浏览器环境中直接可用(无需打包工具)仍有待探索。一种可能的方案是引入类似 RequireJS 的配置数据,将路径映射到实际文件。目前,在浏览器中使用裸路径(bare path)的模块标识符是不合法的。

与 CommonJS 模块的互操作性

与 CommonJS (CJS) 模块的互操作性

你可以导入 CJS 模块,但它们仅暴露默认导出,即 module.exports 的值。虽然让 CJS 模块支持命名导出的工作已在进行中,但这可能需要一段时间才能完善。如果你有兴趣参与,欢迎贡献代码。


import fs1 from 'fs';
console.log(Object.keys(fs1).length); // 86
import * as fs2 from 'fs';
console.log(Object.keys(fs2)); // ['default']

· 在 ES 模块中禁止使用 require() 函数。主要原因包括:

· 路径解析机制略有不同:ESM 不支持 NODE_PATH 和 require.extensions。此外,由于标识符始终被视为 URL,这导致了一些细微的差异。

· ES 模块始终以异步方式加载,以确保与 Web 标准的最大兼容性。这种加载模式不允许通过 require() 混合使用同步加载的 CJS 模块。

· 禁止同步模块加载也为未来支持 Top-level await(当前正在讨论的功能)导入 ES 模块保留了可能性。

早期版本兼容方案

3. 在早期 Node.js 版本上使用 ES 模块

如果你需要在 Node.js 8.5.0 之前的版本中使用 ES 模块,可以参考 John-David Dalton 开发的 @std/esm 库。

提示:如果不启用任何解锁额外功能的标志,Node.js 将保持 100% 兼容原生 ES 模块的标准行为。

常见问题与延伸阅读

常见问题解答 (FAQ)

何时可以无需命令行选项直接使用 ES 模块?

目前的计划是在 Node.js 10 LTS 版本中默认启用 ES 模块支持。

延伸阅读

有关 Node.js 和浏览器环境中 ES 模块的更多信息:

· “Making transpiled ES modules more spec-compliant” [使用原生 ES 模块与通过 Babel 转译的对比]

· “Module specifiers: what's new with ES modules?” [.mjs 文件扩展名原因及模块标识符解析机制等]

· “Modules” [《Exploring ES6》中关于 ES 模块的深入章节]

即将到来的 ECMAScript 提案:

· 博客文章: “ES proposal: import() – dynamically importing ES modules”

· 提案文档: “import.meta”

总结

以上就是在 Node.js 中使用原生 ES 模块的详细解析,希望能对大家有所帮助。如有任何疑问,欢迎留言讨论。感谢对本站的支持。

作者最新文章