Node.js の require はキャッシュされるよ
https://2.bp.blogspot.com/-3OA8V7gg1MI/XLAc2Fu3m2I/AAAAAAABSTY/r4KvaydtjkorIQuS1WbUGqVklodI25kXwCLcBGAs/s400/character_danbo-ru_daisya.png
以下のようなテキストを export するモジュールを1つ作る。
code:ts
// module.js
module.exports = 'hello world'
このモジュールを参照し、1秒おきに出力するプログラムを実行中にモジュールを書き換えるととどうなるか?
code:ts
// index.js
;(async () => {
const sleep = (t) => new Promise((r) => setTimeout(r, t))
for(;;){
// ./modules を require して結果を出力する
console.log(require('./module'))
// 1秒待つ
await (sleep(1000))
}
})()
for の内部で require しているので書き換えた内容が反映されそうなものだがそうはならない。
code:text
hello world
hello world
hello world // ここで dummy に書き換える
hello world // しかしこうかがない
これは require したモジュールが Node.js でキャッシュされるから。
Node.js で require したモジュールのキャッシュは require.cache というメンバを参照することで確認できる。 中身は Object でキーが require.resolve でモジュール名を解決したフルパスになっている。
其のため Node.js で require をする際にはキャッシュが存在する場合先にそちらを参照するので、毎度ファイルを開いてロードするような動きには基本的にはならない。もし実行中に modules を書き換えて、変更を反映するには以下のように Node.js の require が持っている cache を削除する必要がある。
code:ts
;(async () => {
const sleep = (t) => new Promise((r) => setTimeout(r, t))
for(;;){
// ./modules を require して結果を出力する
console.log(require('./module.js'))
// ./modules のパスを解決してそれに対応する cache をオブジェクト的に削除する
// 1秒待つ
await (sleep(1000))
}
})()
これであればこのように意図した(?)とおりに書き換わる
code:text
hello world
hello world
hello world // ここで dummy に書き換える
dummy // 書き換わった
この辺は Node.js の公式のドキュメントの Module Cache の章に詳しく書いてある
Caching
モジュールは、最初にロードされた後にキャッシュされます。これは、(特に)へのすべての呼び出しrequire('foo')が、同じファイルに解決される場合、まったく同じオブジェクトが返されることを意味します。
キャッシュがパージされる瞬間については記載がないが、基本的にプロセスが死ぬまではキャッシュされ続ける様子であった。