node.jsでモジュールを再ロードする

requireされたモジュールは、モジュールのフルパスをキーとしてrequire.cacheというオブジェクトに格納されており、これを削除すればモジュールを再びロードできるらしい。というわけでテスト。

# main.js
console.log(process.pid);

setInterval(function() {
    var a = require('./a');
    console.log(a.value);
}, 3000);

process.on('SIGINT', function() {
    console.log('clear module a');
    var key = require.resolve('./a');
    delete require.cache[key];
});
# a.js
console.log('load module a');

exports.value = 'wang';

実行すると、3秒毎にwangと書かれる。キャッシュされるので load module a というログは1回しかでない。

$ node hoge.js
13330
load module a
wang
wang
wang
wang
wang

別のターミナルでa.jsを編集する

# a.js
console.log('load module a');

exports.value = 'nyan';

a.jsを書き換えて保存し、

$ kill -SIGINT 13330

nodeプロセスにSIGINTを投げると…

wang
clear module a
load module a
nyan
nyan
nyan

再度 load module a が出力され、書き換えた内容が反映されている。モジュールがロードしなおされたようだ。

開発用のhot reloadingに使えると思うが、既存のアプリに適用するには設計レベルで見直しが必要なので難しそう。hot reloading機能付きのフレームワークを設計するならアリでしょう。

ag(the silver searcher)でリテラル検索

agは内部でpcreを使っているようで、デフォルトで .ワイルドカードとして扱われてしまう。ドットそのものを検索するには

ag -Q .save ./lib 

のように-Q(--literal、または-F)オプションを指定する。

-Qの代わりに2重のバックスラッシュでエスケープしても良い。正規表現エンジンに \. を渡せばドットはただの文字リテラルとして扱われる。しかし \ はシェル上でも特殊文字なので \ でエスケープしなくてはならない。

ag \\.save ./lib 

$正規表現で末尾を示す記号であるため、Qオプションが必要だが、 $set はシェル変数として展開されてしまうので バックスラッシュでエスケープする必要がある

ag -Q \$set ./lib

-Qなしの場合は、 \$set という文字列を正規表現に渡すため、 \$ の両方をエスケープする必要がある。

ag \\\$set ./lib

\$ がシェル上で展開されないように、シングルクオートで囲っても良い

ag '\$set' ./lib
ag '\.save' ./lib