CJS のときはこんな感じで書けた部分ですが
[/tmp/a.js]
const path = require("path")
const file_path = path.join(__dirname, "./file.txt")
console.log(file_path)
// /tmp/file.txt
この長さになります
[/tmp/b.js]
import { fileURLToPath } from "node:url"
import path from "node:path"
const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
const file_path = path.join(__dirname, "./file.txt")
console.log(file_path)
// /tmp/file.txt
Node.js 20 なら import.meta に resolve があって __dirname を作らなくてもそのファイルからの相対パスでフルパスを取得できます
でも file:// から始まる URL 形式なので最後に fileURLToPath を通してローカルのパス形式にしないといけないです
[/tmp/c.js]
import { fileURLToPath } from "node:url"
const file_url = import.meta.resolve("./file.txt")
console.log(file_url)
// file:///tmp/file.txt
const file_path = fileURLToPath(file_url)
console.log(file_path)
// /tmp/file.txt
Node.js 21 なら import.meta.dirname があるので CJS と同じようなことができます
🔗 Node.js 21.2 で ESM に CJS の __dirname と __filename 相当の機能が追加された
[/tmp/d.js]
import path from "node:path"
const file_path = path.join(import.meta.dirname, "./file.txt")
console.log(file_path)
// /tmp/file.txt
でも現在の LTS は 20 です
21 に機能追加されて 3 ヶ月以上経っても 20 にバックポートされないのであまり期待できなそうです
使えるのは 22 の LTS からになるかもしれません
それに CJS と近い感じで書けるだけで __dirname が import.meta.dirname になって少し長いです
fs が URL 形式のパスもサポートしてくれるともっと楽なんですけどね
それなら同じフォルダのファイルを読み取るときはこれだけで済みます
fs.readFileSync(import.meta.resolve("./file.txt"))
そういう話がないのか探してみたのですが あまり積極的ではないようで放置されて issue がクローズされてました
https://github.com/nodejs/node/issues/48994
単に中で fileURLToPath を通すだけで file://foo/bar みたいなものを入れてもエラーにするでいいと思うのですけど