▒ 目录 ▒
- 🛫 问题
- 描述
- 环境
- 1️⃣ 原理
- CommonJS vs ESM
- 错误原因
- 2️⃣ 禁用 ESM 模式并改用 CommonJS
- 方案一:项目
- 方案二:单文件
- 3️⃣ 在 ESM 模式下自实现__dirname
- 📖 参考资料
🛫 问题
描述
从网上找了一份代码,其中包含了__dirname变量的使用,结果运行的时候报错:
__dirname is not defined
环境
版本号 | 描述 | |
---|---|---|
文章日期 | 2023-06- | |
操作系统 | Ubuntu 20.04.4 LTS | CSDN开发云 |
node -v | v16.17.0 | npm -v (8.15.0) |
Cloud IDE | 1.71.0 | |
操作系统 | Win11 - 21H2 - 22000.1335 | |
Python | 3.7.1 | |
frida.exe | 15.0.18 | |
1️⃣ 原理
CommonJS vs ESM
讨论__dirname报错,首先要分清楚CommonJS 和 ESM的区别。
CommonJS 和 ESM(ECMAScript Modules) 都是 JavaScript 模块系统的规范,用于组织和管理代码。它们之间有一些区别,下面简要介绍一下:
特点 | CommonJS | ESM |
---|---|---|
加载方式 | 同步加载 | 异步加载 |
导出/引入关键字 | module.exports 和 require() | export 和 import |
支持环境 | Node.js 默认支持 | 现代浏览器和最新版本的 Node.js 支持 |
应用范围 | 主要用于服务器端开发,如 Node.js | 在浏览器端和 Node.js 中有广泛应用,是未来趋势 |
错误原因
在 CommonJS 模式下,__dirname 是包含
当前文件目录
的变量
。 许多Node.js项目都依赖于此变量。
但不能在 ESM 模式下使用(ESM模式不提供 __dirname 变量)。 您有两种选择:
- 禁用 ESM 模式并改用 CommonJS
- 聚填充__dirname
2️⃣ 禁用 ESM 模式并改用 CommonJS
在 JavaScript 中,通常文件扩展名 “.js” 用于表示普通的 JavaScript 文件,
而 “.mjs” 用于表示 ECMAScript 模块(ESM)文件。这两种文件扩展名的区别在于它们所代表的 JavaScript 模块类型。
- .js 文件:通常用来表示普通的 JavaScript 文件,其中可能包含常规的 JavaScript 代码,采用 CommonJS 或其他模块加载方案。
- .mjs 文件:表示 ECMAScript 模块,这种文件中的代码采用了 ECMAScript Modules(ESM)规范,即使用 “import” 和 “export” 关键字来定义模块。
要使用 “.mjs” 文件,您需要确保在 Node.js 中启用了对 ECMAScript 模块的支持。您可以通过以下几种方式之一实现:
方案一:项目
Node.js 项目中的
package.json
文件是一个用于描述项目信息、依赖关系和脚本命令的 JSON 文件。它位于项目根目录下,是 Node.js 项目的重要配置文件之一。
在 Node.js 项目中的 package.json 文件中,“type” 字段不要设置为 “module”,以明确告知 Node.js 不使用 ESM 规范(或者直接删除)
方案二:单文件
对于单文件运行node,即不包含
package.json
文件的情况。node是根据文件后缀判断运行模式的。
我们确保文件后缀是.js
,而不是.mjs
即可使用__dirname。
3️⃣ 在 ESM 模式下自实现__dirname
在 ECMAScript 模块(ESM)中,与 CommonJS 不同,没有像 __dirname 这样的内置变量来表示当前模块的目录路径。不过,您可以通过一些方法来模拟实现类似的功能。
一种常见的方法是使用 import.meta.url 属性来获取当前模块的 URL,然后从中提取出目录路径。下面是一个示例代码,演示如何在 ESM 模式下自实现类似 __dirname 的功能:
import path from 'path';
import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
在这个示例中,我们首先导入了 Node.js 中的 fileURLToPath 和 dirname 函数,然后使用 import.meta.url 获取当前模块的 URL。接着,通过 fileURLToPath 将 URL 转换为文件路径,并最终通过 dirname 获取该文件路径的目录部分,从而模拟实现了类似 __dirname 的功能。
请注意,这种方法依赖于 Node.js 提供的 url 和 path 模块,确保您的项目中已安装这些模块。这样,您就可以在 ESM 模式下获取当前模块的目录路径,类似于 CommonJS 中的 __dirname 变量。
📖 参考资料
- How To Fix “__dirname is not defined” Error in Node.js https://masteringjs.io/tutorials/node/__dirname-is-not-defined