发布于2026-07-04 阅读(0)
扫一扫,手机访问
在ESM环境下遇到__dirname is not defined的报错,很多人第一反应是代码写错了或者配置有问题。其实,这还真不是bug,而是ESM标准本身就没有定义这两个变量。CommonJS时代,Node.js在背后偷偷塞了个“便利糖”,让你能随手取到当前文件路径。但到了ESM,标准要求你把路径计算逻辑显式写出来,这反而是一种更可控、更可预测的做法。
__dirname is not defined 是 ESM 的正常行为,因 ESM 标准未定义 __dirname 和 __filename,需用 import.meta.url 配合 fileURLToPath 和 dirname 替代,或直接用 path.resolve(fileURLToPath(import.meta.url), ...) 构建路径。

只要你在 .mjs 文件里,或者 package.json 里配置了 "type": "module",Node.js 就会按照严格的ESM规范来加载模块。这时候,__dirname 和 __filename 这两个变量就像凭空消失了一样。别怀疑是VSCode的问题,也不是你配置得不够。原因很简单——ESM标准压根就没定义它们。CommonJS 里它们是 Node.js 运行时注入的“便捷变量”,而 ESM 则要求你显式地获取路径,换来了更规范且可预测的行为。
import.meta.url + fileURLToPath 组合这组方案是 Node.js 官方给出的推荐方案——稳健、跨版本兼容(v12.20+)。它由两个函数配合完成:
import.meta.url 是ESM环境下唯一可靠的当前模块URL,格式类似 file:///path/to/index.mjsfileURLToPath() 负责把这个URL字符串转成你能理解的本地文件路径(/path/to/index.mjs)dirname() 再从该路径里提取出目录名(/path/to)看个例子:
import { fileURLToPath } from 'url';
import { dirname } from 'path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// ✅ 现在可以安全拼接路径了
const configPath = path.join(__dirname, 'config.json');
不少开发者会掉进这个坑:在 launch.json 里配置了 "program": "${workspaceFolder}/src/index.mjs",但代码里还惯性写着 __dirname,结果断点直接跳过或者报错。调试器能解析ESM,但不会好心帮你“补全”那些不存在的变量。几个需要注意的点:
import.meta.url 衍生,不要混用 process.cwd() 或硬编码的相对路径字符串.cjs 和 .mjs 文件,千万别把 __dirname 的用法直接复制粘贴过去——模块系统不同,行为完全不同__dirname 存在,那是语言服务的默认假设,实际运行时它会失效path.resolve() + import.meta.url其实还有一个更干净的选择:不需要模拟 __dirname,直接从模块URL构建绝对路径:
path.resolve(fileURLToPath(import.meta.url), '..', 'data', 'users.json')__dirname 再 join 少了一步操作,也避免了变量名污染(不小心重声明 __dirname 之类的低级错误)import.meta.url 是标准API真正需要警惕的是:哪怕你只改了一处 __dirname,只要项目其他地方还在用 require('./util') 加载CommonJS模块,整个模块图就可能陷入混合系统。这时候,不同模块里的路径计算逻辑必须各自独立,绝不能假设“都一样”。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8