__dirname 在ES模块中的使用

news/2024/4/30 2:01:48

前言

ECMAScript模块是 JavaScript 的新标准格式。在Node.js中越来越多的库逐渐从从CommonJS转移到ES模块

注:这里是指“真”ES 模块并不是指代码中 Node.js 中使用 import 写法但是实际被 tsc 转成 commonJS 的形式

但是Node.js ES 开发中此前有一个棘手的问题是获取当前文件目录、路径。不过这个问题在最近也已经解决

结论

在ES模块中,现在可以使用以下方式而不是使用__dirname__filename

import.meta.dirname  // 当前模块的目录名 (__dirname)
import.meta.filename //当前模块文件名 (__filename)

获取当前目录

通过访问当前模块的目录路径,可以相对于代码所在位置遍历文件系统并在项目中读取或写入文件,或动态导入代码。相关的使用方式随着时间的推移而发生了一些变化,从CommonJS的实现到最新的ES模块更新

旧的CommonJS方式

Node.js最初使用CommonJS模块系统。CommonJS提供了两个变量,返回当前模块的目录名称和文件名称,分别是__dirname__filename

__dirname  // 当前模块所在的目录
__filename // 当前模块文件名

旧的 ES 模块方式

__dirname__filename在ES模块中不可用。需要使用以下代码来实现获取

import * as url from 'url';const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
const __filename = url.fileURLToPath(import.meta.url);

最新的 ES 模块方式

最终在经过许多讨论后,现在有了更好的方法。自从Node.js20.11.0和Deno 1.40.0和Bun 1.0.23之后可以调用import.meta对象的dirnamefilename属性来获取了

import.meta.dirname // 当前模块所在的目录
import.meta.filename// 当前模块文件名

为什么需要一个新的 API

ES模块是JavaScript的标准。然而JavaScript最初是作为在Web浏览器中运行的语言而诞生的。Node.js流行起来后开始在服务器上运行JavaScript,但必须使用一些约定来加载模块,Node.js项目早期做出的一个选择是采用CommonJS模块系统及其相关内容

ES模块是为浏览器和服务器环境设计的。浏览器通常没有文件系统访问权限,因此提供对当前目录或文件名的访问是没有意义。然而对于浏览器处理URL,可以使用file://scheme以URL格式提供文件路径。因此,ES模块具有对模块的URL的引用。即import.meta.url。可以看看在Node.js中可以使用URL的相关使用

假设一个名为module.js的ES模块包含以下代码:

console.log(import.meta.url);

如果使用Node.js的服务器上运行此文件,则会得到以下结果:

$ node module.js
file:///path/to/module.js

如果Web浏览器中加载module.js,则会得到以下结果:

https://example.com/module.js

基于不同上下文会有不同的结果

import.meta.url是一个描述URL的字符串,而不是一个URL对象。可以通过将该字符串传递给URL构造函数将其转换为真正的URL对象:

const fileUrl = new URL(import.meta.url);
console.log(url.protocol);
// Node.js: "file:"
// Browser: "https:"

使用 URL 对象,可以使用 Node.js 的 URL 模块将模块的 URL 转换为文件路径,等价于 __filename

import * as url from "url";const fileUrl = new URL(import.meta.url);
const filePath = url.fileURLToPath(fileUrl);
console.log(filePath);// /path/to/module.js

也可以操作URL来获取目录名,等价于__dirname

import * as url from "url";const directoryUrl = new URL(".", import.meta.url);
const directoryPath = url.fileURLToPath(directoryUrl);
console.log(directoryPath);// /path/to

使用 URL 而不是字符串

大多数的代码可能都是需要使用路径字符串来在Node.js中执行常见的文件操作。但其实许多在字符串路径上工作的Node.js API也可以使用URL对象

__dirname 最常见的用途是遍历目录以查找要加载的数据文件。例如,如果 module.js 文件与名为 data.json 的文件位于同一目录中,并且想将数据加载到脚本中,则以前会像这样使用 __dirname

const { join } = require("node:path");
const { readFile } = require("node:fs/promises");function readData() {const filePath = join(__dirname, "data.json");return readFile(filePath, { encoding: "utf8" });
} 
} 

在 ES 模块中可以直接使用import.meta.dirname

import { join } from "node:path";
import { readFile } from "node:fs/promises";function readData() {const filePath = join(import.meta.dirname, "data.json");return readFile(filePath, { encoding: "utf8" });
} 

但是也可以像如下使用URL对象:

import { readFile } from "node:fs/promises";function readData() {const fileUrl = new URL("data.json", import.meta.url);return readFile(fileUrl, { encoding: "utf8" });
} 

由于ES模块为客户端和服务器编写的JavaScript带来了一致性,因此使用URL对象而不是路径字符串也可以实现相同的效果。更多关于替代__dirname可以参考

如何找到 import.meta.dirname

import.meta.dirnameimport.meta.filename可以在最新版本的Node.js、Deno和Bun中使用

Bun已经提前实现了import.meta.dirimport.meta.pat,它们是等效的,所以dirnamefilename在 bun 其实是dirpath的别名

由于这个属性仅涉及基础文件系统,因此仅在import.meta.url的 scheme为file:时可用。也就是说在浏览器环境中不可用;在浏览器中尝试使用import.meta.dirname将仅返回 undefined

参考

__dirname is back in Node.js with ES modules

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.cpky.cn/p/11694.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

一个浮动绝对居中的tailwindcss

今天改进图片组件,遇到个SVG绝对居中的问题。想起之前大概是通过top left来实现,由于组件的宽高需要动态输入。不能定死宽高,于是想起来问GPT。刚开始老是给一些很菜的代码,不是我想要的 气不打一处来,索性给他限死框框…

策略模式图

策略模式 小小的图解 主要的三个角色 Strategy—抽象策略角色ConcreateStrategy—具体策略角色Context—上下文角色 封装了对具体策略的调用可以使用set的依赖注入也可以使用构造方法 核心是上下文角色 只要调用上下文角色就行,实现解耦 策略 工厂 将上下文角…

【Easy云盘 | 第十三篇】分享模块(获取目录信息、获取文件信息、创建下载链接)

文章目录 4.4.7获取目录信息4.4.8获取文件信息4.4.9创建下载链接 4.4.7获取目录信息 明天做 4.4.8获取文件信息 明天做 4.4.9创建下载链接 明天做

【THM】Protocols and Servers(协议和服务器)-初级渗透测试

介绍 这个房间向用户介绍了一些常用的协议,例如: HTTP协议文件传输协议POP3邮件传输协议IMAP每个协议的每个任务都旨在帮助我们了解底层发生的情况,并且通常被优雅的GUI(图形用户界面)隐藏。我们将使用简单的 Telnet 客户端来使用上述协议进行“对话”,以充分了解GUI客户…

DDIM,多样性与运行效率之间的trade off

DDPM的重大缺陷在于其在反向扩散的过程中需要逐步从 x t x_t xt​倒推到 x 0 x_0 x0​,因此其推理速度非常缓慢。相反,DDPM的训练过程是很快的,可以直接根据 x 0 x_0 x0​到 x t x_t xt​添加的高斯噪声 ϵ \epsilon ϵ完成一次训练。 为了解…

Kafka入门到实战-第五弹

Kafka入门到实战 Kafka常见操作官网地址Kafka概述Kafka的基础操作更新计划 Kafka常见操作 官网地址 声明: 由于操作系统, 版本更新等原因, 文章所列内容不一定100%复现, 还要以官方信息为准 https://kafka.apache.org/Kafka概述 Apache Kafka 是一个开源的分布式事件流平台&…