Node.js - check if module is installed without actually requiring it

I need to check whether "mocha" is installed, before running it. I came up with the following code:

try {
    var mocha = require("mocha");
} catch(e) {
    console.error(e.message);
    console.error("Mocha is probably not found. Try running `npm install mocha`.");
    process.exit(e.code);
}

I dont like the idea to catch an exception. Is there a better way?

You should use require.resolve() instead of require(). require will load the library if found, but require.resolve() will not, it will return the file name of the module. See here

try {
    console.log(require.resolve("mocha"));
} catch(e) {
    console.error("Mocha is not found");
    process.exit(e.code);
}

require.resolve() does throw error if module is not found so you have to handle it.

module.paths stores array of search paths for require. Search paths are relative to the current module from where require is called. So:

var fs = require("fs");

// checks if module is available to load
var isModuleAvailableSync = function(moduleName)
{
    var ret = false; // return value, boolean
    var dirSeparator = require("path").sep

    // scan each module.paths. If there exists
    // node_modules/moduleName then
    // return true. Otherwise return false.
    module.paths.forEach(function(nodeModulesPath)
    {
        if(fs.existsSync(nodeModulesPath + dirSeparator + moduleName) === true)
        {
            ret = true;
            return false; // break forEach
        }
    });

    return ret;
}

And asynchronous version:

// asynchronous version, calls callback(true) on success
// or callback(false) on failure.
var isModuleAvailable = function(moduleName, callback)
{
    var counter = 0;
    var dirSeparator = require("path").sep

    module.paths.forEach(function(nodeModulesPath)
    {
        var path = nodeModulesPath + dirSeparator + moduleName;
        fs.exists(path, function(exists)
        {
            if(exists)
            {
                callback(true);
            }
            else
            {
                counter++;

                if(counter === module.paths.length)
                {
                    callback(false);
                }
            }
        });
    });
};

Usage:

if( isModuleAvailableSync("mocha") === true )
{
    console.log("yay!");
}

Or:

isModuleAvailable("colors", function(exists)
{
    if(exists)
    {
        console.log("yay!");
    }
    else
    {
        console.log("nay:(");
    }
});

Edit: Note:

  • module.paths is not in the API
  • Documentation states that you can add paths that will be scanned by require but I couldn't make it work (I'm on Windows XP).

I think you can make a trick here. As far as node.js can works with shell commands, use "npm list --global" to list all intalled modules and check if needed one is presented.

var sys = require('sys')
var exec = require('child_process').exec;
var child;

// execute command
child = exec("npm list --global", function (error, stdout, stderr) {
    // TODO: search in stdout
    if (error !== null) {
        console.log('exec error: ' + error);
    }
});