Node.js

Node.jsで絶対パスでモジュールを読み込むには?

先日までは以下のようなフォーマットで外部モジュールをrequireしていました。これでうまく行っているように見えていました。しかし。

var noderc = require( path.relative( __dirname , process.env.NODE_RC_FILE ) );

実は上記コードでは不完全で、参照パスが同階層のディレクトリにあった場合、エラーになります。

module.js:550
    throw err;
    ^

Error: Cannot find module 'noderc.js'
    at Function.Module._resolveFilename (module.js:548:15)
    at Function.Module._load (module.js:475:25)
    at Module.require (module.js:597:17)
    at require (internal/module.js:11:18)
    at Object.<anonymous> (/mnt/c/pg/node/tmp.js:10:14)
    at Module._compile (module.js:653:30)
    at Object.Module._extensions..js (module.js:664:10)
    at Module.load (module.js:566:32)
    at tryModuleLoad (module.js:506:12)
    at Function.Module._load (module.js:498:3)

なぜか。同階層に参照パスがある場合、./noderc.jsといったパスではなくnoderc.jsというパスとして値が返されます。

わかりやすく言うとこういうことですね。

var noderc = require( "noderc.js" ); # => ERROR
var noderc = require( "../node/noderc.js" ); # => OK
var noderc = require( "./noderc.js" ); # => OK

なので以下を書いてみました。パスが”noderc.js”みたいなものであるとき、”./noderc.js”へ変換するものです。

global.require_absolute = function( filepath ){

    if ( ! /^\./.test( path.relative( __dirname , filepath ) ) ){
        global.noderc = require( `./${ path.relative( __dirname , filepath ) }` );
    } else {
        global.noderc = require( path.relative( __dirname , filepath ) );
    }

}

そして使用例。

require_absolute( "/mnt/c/pg/node/noderc.js" ) ;

require_absolute( process.env.NODE_RC_FILE ) ;

nodejsのrequireに関しては深い議論がされているようです。このトピックだけで2000スター。

Better local require() paths for Node.js

追記

すみません間違えてました。以下のほうが汎用性が高いです。

global.to_relative = function( filepath ){

    if ( ! /^\./.test( path.relative( __dirname , filepath ) ) ){
        return `./${ path.relative( __dirname , filepath ) }` ;
    } else {
        return path.relative( __dirname , filepath ) ;
    }

}

var noderc = require( to_relative( process.env.NODE_RC_FILE ) ) ;