前言
ECMAScript 模块是 JavaScript 的新标准格式。在 Node.js 中越来越多的库逐渐从从 CommonJS 转移到 ES 模块
注:这里是指“真”ES 模块并不是指代码中 Node.js 中使用 import 写法但是实际被 tsc 转成 commonJS 的形式
但是 Node.js ES 开发中此前有一个棘手的问题是获取当前文件目录、路径。不过这个问题在最近也已经解决
结论
在 ES 模块中,现在可以使用以下方式而不是使用__dirname
或__filename
1 | import.meta.dirname // 当前模块的目录名 (__dirname) |
获取当前目录
通过访问当前模块的目录路径,可以相对于代码所在位置遍历文件系统并在项目中读取或写入文件,或动态导入代码。相关的使用方式随着时间的推移而发生了一些变化,从 CommonJS 的实现到最新的 ES 模块更新
旧的 CommonJS 方式
Node.js 最初使用 CommonJS 模块系统。CommonJS 提供了两个变量,返回当前模块的目录名称和文件名称,分别是__dirname
和__filename
1 | __dirname // 当前模块所在的目录 |
旧的 ES 模块方式
__dirname
和__filename
在 ES 模块中不可用。需要使用以下代码来实现获取
1 | import * as url from 'url'; |
最新的 ES 模块方式
最终在经过许多讨论后,现在有了更好的方法。自从Node.js20.11.0和Deno 1.40.0和Bun 1.0.23之后可以调用import.meta
对象的dirname
和filename
属性来获取了
1 | import.meta.dirname // 当前模块所在的目录 |
为什么需要一个新的 API
ES 模块是 JavaScript 的标准。然而 JavaScript 最初是作为在 Web 浏览器中运行的语言而诞生的。Node.js 流行起来后开始在服务器上运行 JavaScript,但必须使用一些约定来加载模块,Node.js 项目早期做出的一个选择是采用 CommonJS 模块系统及其相关内容
ES 模块是为浏览器和服务器环境设计的。浏览器通常没有文件系统访问权限,因此提供对当前目录或文件名的访问是没有意义。然而对于浏览器处理 URL,可以使用file://scheme
以 URL 格式提供文件路径。因此,ES 模块具有对模块的 URL 的引用。即import.meta.ur
l。可以看看在 Node.js 中可以使用 URL 的相关使用
假设一个名为module.js
的 ES 模块包含以下代码:
1 | console.log(import.meta.url); |
如果使用 Node.js 的服务器上运行此文件,则会得到以下结果:
1 | $ node module.js |
如果 Web 浏览器中加载 module.js,则会得到以下结果:
1 | https://example.com/module.js |
基于不同上下文会有不同的结果
import.meta.url
是一个描述 URL 的字符串,而不是一个 URL 对象。可以通过将该字符串传递给URL
构造函数将其转换为真正的 URL 对象:
1 | const fileUrl = new URL(import.meta.url); |
使用 URL 对象,可以使用 Node.js 的 URL 模块将模块的 URL 转换为文件路径,等价于 __filename
1 | import * as url from "url"; |
也可以操作 URL 来获取目录名,等价于__dirname
1 | import * as url from "url"; |
使用 URL 而不是字符串
大多数的代码可能都是需要使用路径字符串来在 Node.js 中执行常见的文件操作。但其实许多在字符串路径上工作的 Node.js API 也可以使用URL
对象
__dirname
最常见的用途是遍历目录以查找要加载的数据文件。例如,如果 module.js
文件与名为 data.json
的文件位于同一目录中,并且想将数据加载到脚本中,则以前会像这样使用 __dirname
1 | const { join } = require("node:path"); |
在 ES 模块中可以直接使用import.meta.dirname
1 | import { join } from "node:path"; |
但是也可以像如下使用 URL 对象:
1 | import { readFile } from "node:fs/promises"; |
由于 ES 模块为客户端和服务器编写的 JavaScript 带来了一致性,因此使用 URL 对象而不是路径字符串也可以实现相同的效果。更多关于替代__dirname
可以参考
如何找到 import.meta.dirname
import.meta.dirname
和import.meta.filename
可以在最新版本的 Node.js、Deno 和 Bun 中使用
Bun 已经提前实现了import.meta.dir
和import.meta.pat
,它们是等效的,所以dirname
和filename
在 bun 其实是dir
和path
的别名
由于这个属性仅涉及基础文件系统,因此仅在import.meta.url
的 scheme 为file:
时可用。也就是说在浏览器环境中不可用;在浏览器中尝试使用import.meta.dirname
将仅返回 undefined
参考
- Post title:在ES模块中的使用 __dirname
- Post author:flytam
- Create time:2024-04-07 17:49:01
- Post link:https://blog.flytam.vip/在ES模块中的使用 __dirname .html
- Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.