◆ そのファイルから
◆ path.resolve や fs.readFile などはカレントディレクトリから
◆ require(path.resovle("./file.js")) とするとカレントディレクトリを元にした相対パスのファイルをロードする
◆ __dirname と結合すれば常にそのファイルからの相対パスにできる
◆ require でまで __dirname 使うと混乱は減るけど見やすくない

import 構文だと相対パスは import 文が書かれた JavaScript ファイルからの相対パスになります
require もそうだっけ? と思ったのですが前に __dirname 使うべきみたいなのを聞いた覚えがあったので require はカレントディレクトリからのパスかと思っていました
実際 __dirname なしで相対パスで書いて思ったように動かなくて 「カレントディレクトリからか」 と自分でも納得して __dirname を使った覚えもあったので

でも __dirname と join するよう書いてみるとけっこう手間で 見た目もあんまりきれいじゃないです
そこでしか使わないのに path をロードする必要ありますし join 使わなくて + にしてもなんか全部に __dirname って冗長感あります

普段見てる github とかにある Node.js ファイルのソースこんなのだっけ? と思って探してみても __dirname は見当たらないです
探してて思ったのが大きなプロジェクトでもひとつひとつのパッケージ自体が小さい機能に分けられているのが多くて ソースが置かれたフォルダ内にフォルダがなくフラットで同じディレクトリのモジュールをロードしてるだけが多かったです
複雑なディレクトリ構造になってるのを見つけて確認しても "../../" とか使ってます

あれ これで動くの?
気になって 試してみたところ import 構文同様 そのファイルからの相対パスでカレントディレクトリは関係ないようです

試してみる

- file1.js
- file2.js
- dir/file.js

という 3 ファイルを用意します

[file1.js]
require("./dir/file.js")

[dir/file.js]
require("../file2.js")

[file2.js]
console.log("ok")

これで file1.js を実行します
するとちゃんと "ok" が出ました
常にカレントディレクトリを参照していたら出ないはずです

file1.js があるのとは関係ないところで実行しても正常に動きます


昔動かなかった覚えがあるのなんだったのでしょうか
さすがにここの仕様が変わるとは思えませんし

ありそうなのは

require(path.resolve("../foo/bar.js"))

とかやってたということです
絶対パスにする際はカレントディレクトリが基準となります

同じく

require("fs").readFileSync("./file2.js")

こういうのもカレントディレクトリ基準なのでそのファイルからにしたいなら __dirname が必要です
import みたいな構文ならともかく ファイル読み取りと require みたいな似たものでどっちも関数なのに相対パスの基準が違うのはややこしいですね
はっきり覚えてないのですが __dirname 使うべきという主張はこういうことがあるから require でも常に __dirname 使っておけば混乱しなくて済む ということだったのかもしれません