I'd like to know if require(pkgName) would succeed, that is, if the package with name pkgName is available. How do I best test for that?
I know I can do
try {
require(pkgName)
} catch (err) {
available = false
}
but this swallows load errors, and I'd also like to avoid require'ing the package if possible.
The best way is to use require.resolve(), since it does not actually run any code contained in the module.
Use the internal require() machinery to look up the location of a module, but rather than loading the module, just return the resolved filename.
Just like require, resolve throws if the module is not found, so it needs to be wrapped in try/catch.
Don't think you can work around using require, but you can specifically check for MODULE_NOT_FOUND errors:
function moduleExists(mod) {
try {
require(mod);
} catch(e) {
if (e.code === 'MODULE_NOT_FOUND')
return false;
throw e;
};
return true;
}
I'm showing with the "swig" module. There might be better ways, but this works for me.
var swig;
try {
swig = require('swig');
} catch (err) {
console.log(" [FAIL]\t Cannot load swig.\n\t Have you tried installing it? npm install swig");
}
if (swig != undefined) {
console.log(" [ OK ]\t Module: swig");
}
Related
I have an application and I want it to be resilient against missing dependencies. Some sort of fallback mechanism, in case a dependency is missing or corrupted.
So I have this, which monkey-patches require() and in theory will re-install a dependency if it cannot be loaded the first time:
const cp = require('child_process');
const Mod = require('module');
const req = Mod.prototype.require;
Mod.prototype.require = function (d) {
try {
return req.apply(this, arguments);
}
catch (e) {
if (/^[A-Za-z]/.test(String(d))) {
console.error(`could not require dependency "${d}".`);
try {
var actualDep = String(d).split('/')[0];
console.error(`but we are resilient and we are attempting to install "${actualDep}" now.`);
cp.execSync(`cd ${_suman.projectRoot} && npm install ${actualDep}`);
return req.apply(this, arguments);
}
catch (err) {
console.error('\n', err.stack || err, '\n');
throw e;
}
}
else {
throw e;
}
}
};
but the above patch is not working as expected. The problem is that the initial try statement:
return req.apply(this, arguments);
it mostly works, but it's doing some strange things..for example, it starts installing
bufferutil
utf-8-validate
this doesn't make sense to me, because require() works without any errors normally, but when using the patch, require() suddenly fails.
Anyone know what might be going on? Super weird.
(Note what it's doing is only attempting to re-install dependencies that start with a character [a-zA-z], it won't attempt to install a dependency that starts with './' etc.)
The reason I ask, is because Node.js on ubuntu doesn't seem to have the fs.exists() function. Although I can call this when I run Node.js on my Mac, when I deploy to the server, it fails with an error saying the function does not exist.
Now, I am aware that some people consider it an "anti-pattern" to check if a file exists and then try and edit / open it etc, but in my case, I never delete these files, but I still need to check if they exist before writing to them.
So how can I check if the directory (or file) exists ?
EDIT:
This is the code I run in a file called 'temp.'s' :
var fs=require('fs');
fs.exists('./temp.js',function(exists){
if(exists){
console.log('yes');
}else{
console.log("no");
}
});
On my Mac, it works fine. On ubuntu I get the error:
node.js:201
throw e; // process.nextTick error, or 'error' event on first tick
^ TypeError: Object #<Object> has no method 'exists'
at Object.<anonymous> (/home/banana/temp.js:2:4)
at Module._compile (module.js:441:26)
at Object..js (module.js:459:10)
at Module.load (module.js:348:32)
at Function._load (module.js:308:12)
at Array.0 (module.js:479:10)
at EventEmitter._tickCallback (node.js:192:41)
On my Mac - version : v0.13.0-pre
On Ubuntu - version : v0.6.12
It's probably due to the fact that in NodeJs 0.6 the exists() method was located in the path module: http://web.archive.org/web/20111230180637/http://nodejs.org/api/path.html – try-catch-finally
^^ That comment answers why it isn't there. I'll answer what you can do about it (besides not using ancient versions).
From the fs.exists() documentation:
In particular, checking if a file exists before opening it is an anti-pattern that leaves you vulnerable to race conditions: another process may remove the file between the calls to fs.exists() and fs.open(). Just open the file and handle the error when it's not there.
You could do something like this:
fs.open('mypath','r',function(err,fd){
if (err && err.code=='ENOENT') { /* file doesn't exist */ }
});
The accepted answer does not take into account that the node fs module documentation recommends using fs.stat to replace fs.exists (see the documentation).
I ended up going with this:
function filePathExists(filePath) {
return new Promise((resolve, reject) => {
fs.stat(filePath, (err, stats) => {
if (err && err.code === 'ENOENT') {
return resolve(false);
} else if (err) {
return reject(err);
}
if (stats.isFile() || stats.isDirectory()) {
return resolve(true);
}
});
});
}
Note ES6 syntax + Promises - the sync version of this would be a bit simpler. Also my code also checks to see if there is a directory present in the path string and returns true if stat is happy with it - this may not be what everyone wants.
The Sync methods don't have any way of notifying about an error. Except for exceptions! As it turns out, the fs.statSync method throws an exception when the file or directory doesn't exist. Creating the sync version is as easy as that:
function checkDirectorySync(directory) {
try {
fs.statSync(directory);
} catch(e) {
try {
fs.mkdirSync(directory);
} catch(e) {
return e;
}
}
}
And that's it.
Using is as simple as before:
checkDirectorySync("./logs");
//directory created / exists, all good.
[]´z
I'm loading a config.json file using require('./config.json') but I don't want to require a config file if they want to pass command line arguments instead, or just use the defaults. Is there any way to try to load a JSON file this way but not spit out an error if it can't be found?
For general modules, you can check for existence before trying to load. In the following path is whatever path you want to load and process() is a function performing whatever processing you'd like on your module:
var fs = require("fs");
fs.exists(path, function (exists) {
if (exists) {
var foo = require(path);
process(foo);
}
else {
// Whatever needs to be done if it does not exist.
}
});
And remember that path above must be an actual path, and not a module name to be later resolved by Node as a path.
For a JSON file specifically, with path and process having the same meanings as above:
fs.readFile(path, function (err, data) {
if (err) {
// Whatever you must do if the file cannot be read.
return;
}
var parsed = JSON.parse(data);
process(parsed);
});
You can also use try... catch but keep in mind that v8 won't optimize functions that have try... catch in them. With path and process meaning the same as above:
try {
var foo = require(path);
process(foo);
}
catch (e) {
if (e.code !== "MODULE_NOT_FOUND")
throw e; // Other problem, rethrow.
// Do what you need if the module does not exist.
}
I need to check if file/(custom)module js exists under some path. I tried like
var m = require('/home/test_node_project/per');
but it throws error when there is no per.js in path.
I thought to check with
fs if file exists but I don't want to add '.js' as suffix if is possible to check without that.
How to check in node if module exists and if exists to load ?
Require is a synchronous operation so you can just wrap it in a try/catch.
try {
var m = require('/home/test_node_project/per');
// do stuff
} catch (ex) {
handleErr(ex);
}
You can just try to load it and then catch the exception it generates if it fails to load:
try {
var foo = require("foo");
}
catch (e) {
if (e instanceof Error && e.code === "MODULE_NOT_FOUND")
console.log("Can't load foo!");
else
throw e;
}
You should examine the exception you get just in case it is not merely a loading problem but something else going on. Avoid false positives and all that.
It is possible to check if the module is present, without actually loading it:
function moduleIsAvailable (path) {
try {
require.resolve(path);
return true;
} catch (e) {
return false;
}
}
Documentation:
require.resolve(request[, options])
Use the internal require() machinery to look up the location of a module, but rather than loading the module, just return the resolved filename.
Note: Runtime checks like this will work for Node apps, but they won't work for bundlers like browserify, WebPack, and React Native.
You can just check is a folder exists by using methods:
var fs = require('fs');
if (fs.existsSync(path)) {
// Do something
}
// Or
fs.exists(path, function(exists) {
if (exists) {
// Do something
}
});
I am trying to modify require like this
require = function (path) {
try {
return module.require(path);
} catch (err) {
console.log(path)
}
}
However, scope of this modification is only in the current module. I want to modify it globally, so every module that is required by this module will also get the same copy of require function.
Basically, I want to catch SyntaxError to know which file has problem. I can't seem to find any other alternative. If I put module.require in try/catch block, I'll be able to get the file name which caused SyntaxError.
I managed to solve it by modifying prototype function require of Module class. I put this in the main script and its available to all the required modules.
var pathModule = require('path');
var assert = require('assert').ok;
module.constructor.prototype.require = function (path) {
var self = this;
assert(typeof path === 'string', 'path must be a string');
assert(path, 'missing path');
try {
return self.constructor._load(path, self);
} catch (err) {
// if module not found, we have nothing to do, simply throw it back.
if (err.code === 'MODULE_NOT_FOUND') {
throw err;
}
// resolve the path to get absolute path
path = pathModule.resolve(__dirname, path)
// Write to log or whatever
console.log('Error in file: ' + path);
}
}
Why don't you use a try-catch block inside your code and once an error occurs to check the stack trace. Check out these links
How to print a stack trace in Node.js?
http://machadogj.com/2013/4/error-handling-in-nodejs.html